File:  [DragonFly] / src / sys / dev / serial / cy / cy.c
Revision 1.11: download - view: text, annotated - select for diffs
Wed May 19 22:52:48 2004 UTC (10 years, 4 months ago) by dillon
Branches: MAIN
CVS tags: HEAD, DragonFly_Snap13Sep2004, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Device layer rollup commit.

* cdevsw_add() is now required.  cdevsw_add() and cdevsw_remove() may specify
  a mask/match indicating the range of supported minor numbers.  Multiple
  cdevsw_add()'s using the same major number, but distinctly different
  ranges, may be issued.  All devices that failed to call cdevsw_add() before
  now do.

* cdevsw_remove() now automatically marks all devices within its supported
  range as being destroyed.

* vnode->v_rdev is no longer resolved when the vnode is created.  Instead,
  only v_udev (a newly added field) is resolved.  v_rdev is resolved when
  the vnode is opened and cleared on the last close.

* A great deal of code was making rather dubious assumptions with regards
  to the validity of devices associated with vnodes, primarily due to
  the persistence of a device structure due to being indexed by (major, minor)
  instead of by (cdevsw, major, minor).  In particular, if you run a program
  which connects to a USB device and then you pull the USB device and plug
  it back in, the vnode subsystem will continue to believe that the device
  is open when, in fact, it isn't (because it was destroyed and recreated).

  In particular, note that all the VFS mount procedures now check devices
  via v_udev instead of v_rdev prior to calling VOP_OPEN(), since v_rdev
  is NULL prior to the first open.

* The disk layer's device interaction has been rewritten.  The disk layer
  (i.e. the slice and disklabel management layer) no longer overloads
  its data onto the device structure representing the underlying physical
  disk.  Instead, the disk layer uses the new cdevsw_add() functionality
  to register its own cdevsw using the underlying device's major number,
  and simply does NOT register the underlying device's cdevsw.  No
  confusion is created because the device hash is now based on
  (cdevsw,major,minor) rather then (major,minor).

  NOTE: This also means that underlying raw disk devices may use the entire
  device minor number instead of having to reserve the bits used by the disk
  layer, and also means that can we (theoretically) stack a fully
  disklabel-supported 'disk' on top of any block device.

* The new reference counting scheme prevents this by associating a device
  with a cdevsw and disconnecting the device from its cdevsw when the cdevsw
  is removed.  Additionally, all udev2dev() lookups run through the cdevsw
  mask/match and only successfully find devices still associated with an
  active cdevsw.

* Major work on MFS:  MFS no longer shortcuts vnode and device creation.  It
  now creates a real vnode and a real device and implements real open and
  close VOPs.  Additionally, due to the disk layer changes, MFS is no longer
  limited to 255 mounts.  The new limit is 16 million.  Since MFS creates a
  real device node, mount_mfs will now create a real /dev/mfs<PID> device
  that can be read from userland (e.g. so you can dump an MFS filesystem).

* BUF AND DEVICE STRATEGY changes.  The struct buf contains a b_dev field.
  In order to properly handle stacked devices we now require that the b_dev
  field be initialized before the device strategy routine is called.  This
  required some additional work in various VFS implementations.  To enforce
  this requirement, biodone() now sets b_dev to NODEV.  The new disk layer
  will adjust b_dev before forwarding a request to the actual physical
  device.

* A bug in the ISO CD boot sequence which resulted in a panic has been fixed.

Testing by: lots of people, but David Rhodus found the most aggregious bugs.

    1: /*-
    2:  * cyclades cyclom-y serial driver
    3:  *	Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993
    4:  *
    5:  * Copyright (c) 1993 Andrew Herbert.
    6:  * All rights reserved.
    7:  *
    8:  * Redistribution and use in source and binary forms, with or without
    9:  * modification, are permitted provided that the following conditions
   10:  * are met:
   11:  * 1. Redistributions of source code must retain the above copyright
   12:  *    notice, this list of conditions and the following disclaimer.
   13:  * 2. Redistributions in binary form must reproduce the above copyright
   14:  *    notice, this list of conditions and the following disclaimer in the
   15:  *    documentation and/or other materials provided with the distribution.
   16:  * 3. The name Andrew Herbert may not be used to endorse or promote products
   17:  *    derived from this software without specific prior written permission.
   18:  *
   19:  * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
   20:  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   21:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
   22:  * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   23:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   24:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   25:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   26:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   27:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   28:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29:  *
   30:  * $FreeBSD: src/sys/i386/isa/cy.c,v 1.97.2.2 2001/08/22 13:04:58 bde Exp $
   31:  * $DragonFly: src/sys/dev/serial/cy/cy.c,v 1.11 2004/05/19 22:52:48 dillon Exp $
   32:  */
   33: 
   34: #include "opt_compat.h"
   35: #include "use_cy.h"
   36: 
   37: /*
   38:  * TODO:
   39:  * Atomic COR change.
   40:  * Consoles.
   41:  */
   42: 
   43: /*
   44:  * Temporary compile-time configuration options.
   45:  */
   46: #define	RxFifoThreshold	(CD1400_RX_FIFO_SIZE / 2)
   47: 			/* Number of chars in the receiver FIFO before an
   48: 			 * an interrupt is generated.  Should depend on
   49: 			 * line speed.  Needs to be about 6 on a 486DX33
   50: 			 * for 4 active ports at 115200 bps.  Why doesn't
   51: 			 * 10 work?
   52: 			 */
   53: #define	PollMode	/* Use polling-based irq service routine, not the
   54: 			 * hardware svcack lines.  Must be defined for
   55: 			 * Cyclom-16Y boards.  Less efficient for Cyclom-8Ys,
   56: 			 * and stops 4 * 115200 bps from working.
   57: 			 */
   58: #undef	Smarts		/* Enable slightly more CD1400 intelligence.  Mainly
   59: 			 * the output CR/LF processing, plus we can avoid a
   60: 			 * few checks usually done in ttyinput().
   61: 			 *
   62: 			 * XXX not fully implemented, and not particularly
   63: 			 * worthwhile.
   64: 			 */
   65: #undef	CyDebug		/* Include debugging code (not very expensive). */
   66: 
   67: /* These will go away. */
   68: #undef	SOFT_CTS_OFLOW
   69: #define	SOFT_HOTCHAR
   70: 
   71: #include <sys/param.h>
   72: #include <sys/systm.h>
   73: #include <sys/tty.h>
   74: #include <sys/proc.h>
   75: #include <sys/conf.h>
   76: #include <sys/dkstat.h>
   77: #include <sys/fcntl.h>
   78: #include <sys/interrupt.h>
   79: #include <sys/kernel.h>
   80: #include <sys/malloc.h>
   81: #include <sys/syslog.h>
   82: #include <machine/clock.h>
   83: #include <machine/ipl.h>
   84: #ifndef SMP
   85: #include <machine/lock.h>
   86: #endif
   87: #include <machine/psl.h>
   88: 
   89: #include <bus/isa/i386/isa_device.h>
   90: #include "cyreg.h"
   91: #include <i386/isa/ic/cd1400.h>
   92: 
   93: #ifdef SMP
   94: #define disable_intr()	com_lock()
   95: #define enable_intr()	com_unlock()
   96: #endif /* SMP */
   97: 
   98: /*
   99:  * Dictionary so that I can name everything *sio* or *com* to compare with
  100:  * sio.c.  There is also lots of ugly formatting and unnecessary ifdefs to
  101:  * simplify the comparision.  These will go away.
  102:  */
  103: #define	LSR_BI		CD1400_RDSR_BREAK
  104: #define	LSR_FE		CD1400_RDSR_FE
  105: #define	LSR_OE		CD1400_RDSR_OE
  106: #define	LSR_PE		CD1400_RDSR_PE
  107: #define	MCR_DTR		CD1400_MSVR2_DTR
  108: #define	MCR_RTS		CD1400_MSVR1_RTS
  109: #define	MSR_CTS		CD1400_MSVR2_CTS
  110: #define	MSR_DCD		CD1400_MSVR2_CD
  111: #define	MSR_DSR		CD1400_MSVR2_DSR
  112: #define	MSR_RI		CD1400_MSVR2_RI
  113: #define	NSIO		(NCY * CY_MAX_PORTS)
  114: #define	comconsole	cyconsole
  115: #define	comdefaultrate	cydefaultrate
  116: #define	com_events	cy_events
  117: #define	comhardclose	cyhardclose
  118: #define	commctl		cymctl
  119: #define	comparam	cyparam
  120: #define	comspeed	cyspeed
  121: #define	comstart	cystart
  122: #define	comwakeup	cywakeup
  123: #define	nsio_tty	ncy_tty
  124: #define	p_com_addr	p_cy_addr
  125: #define	sioattach	cyattach
  126: #define	sioclose	cyclose
  127: #define	siodriver	cydriver
  128: #define	siodtrwakeup	cydtrwakeup
  129: #define	sioinput	cyinput
  130: #define	siointr		cyintr
  131: #define	siointr1	cyintr1
  132: #define	sioioctl	cyioctl
  133: #define	sioopen		cyopen
  134: #define	siopoll		cypoll
  135: #define	sioprobe	cyprobe
  136: #define	siosettimeout	cysettimeout
  137: #define	siosetwater	cysetwater
  138: #define	comstop		cystop
  139: #define	siowrite	cywrite
  140: #define	sio_registered	cy_registered
  141: #define	sio_timeout	cy_timeout
  142: #define	sio_timeout_handle cy_timeout_handle
  143: #define	sio_timeouts_until_log	cy_timeouts_until_log
  144: #define	sio_tty		cy_tty
  145: 
  146: #define	CY_MAX_PORTS		(CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s)
  147: 
  148: /* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */
  149: #define	CD1400_xIVR_CHAN_SHIFT	3
  150: #define	CD1400_xIVR_CHAN	0x1F
  151: 
  152: /*
  153:  * ETC states.  com->etc may also contain a hardware ETC command value,
  154:  * meaning that execution of that command is pending.
  155:  */
  156: #define	ETC_NONE		0	/* we depend on bzero() setting this */
  157: #define	ETC_BREAK_STARTING	1
  158: #define	ETC_BREAK_STARTED	2
  159: #define	ETC_BREAK_ENDING	3
  160: #define	ETC_BREAK_ENDED		4
  161: 
  162: #define	LOTS_OF_EVENTS	64	/* helps separate urgent events from input */
  163: 
  164: #define	CALLOUT_MASK		0x80
  165: #define	CONTROL_MASK		0x60
  166: #define	CONTROL_INIT_STATE	0x20
  167: #define	CONTROL_LOCK_STATE	0x40
  168: #define	DEV_TO_UNIT(dev)	(MINOR_TO_UNIT(minor(dev)))
  169: #define	MINOR_MAGIC_MASK	(CALLOUT_MASK | CONTROL_MASK)
  170: /*
  171:  * Not all of the magic is parametrized in the following macros.  16 and
  172:  * 0xff are related to the bitfields in a udev_t.  CY_MAX_PORTS must be
  173:  * ((0xff & ~MINOR_MAGIC_MASK) + 1) for things to work.
  174:  */
  175: #define	MINOR_TO_UNIT(mynor)	(((mynor) >> 16) * CY_MAX_PORTS \
  176: 				 | (((mynor) & 0xff) & ~MINOR_MAGIC_MASK))
  177: #define	UNIT_TO_MINOR(unit)	(((unit) / CY_MAX_PORTS) << 16 \
  178: 				 | (((unit) & 0xff) & ~MINOR_MAGIC_MASK))
  179: 
  180: /*
  181:  * com state bits.
  182:  * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
  183:  * than the other bits so that they can be tested as a group without masking
  184:  * off the low bits.
  185:  *
  186:  * The following com and tty flags correspond closely:
  187:  *	CS_BUSY		= TS_BUSY (maintained by comstart(), siopoll() and
  188:  *				   comstop())
  189:  *	CS_TTGO		= ~TS_TTSTOP (maintained by comparam() and comstart())
  190:  *	CS_CTS_OFLOW	= CCTS_OFLOW (maintained by comparam())
  191:  *	CS_RTS_IFLOW	= CRTS_IFLOW (maintained by comparam())
  192:  * TS_FLUSH is not used.
  193:  * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
  194:  * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
  195:  */
  196: #define	CS_BUSY		0x80	/* output in progress */
  197: #define	CS_TTGO		0x40	/* output not stopped by XOFF */
  198: #define	CS_ODEVREADY	0x20	/* external device h/w ready (CTS) */
  199: #define	CS_CHECKMSR	1	/* check of MSR scheduled */
  200: #define	CS_CTS_OFLOW	2	/* use CTS output flow control */
  201: #define	CS_DTR_OFF	0x10	/* DTR held off */
  202: #define	CS_ODONE	4	/* output completed */
  203: #define	CS_RTS_IFLOW	8	/* use RTS input flow control */
  204: #define	CSE_ODONE	1	/* output transmitted */
  205: 
  206: static	char const * const	error_desc[] = {
  207: #define	CE_OVERRUN			0
  208: 	"silo overflow",
  209: #define	CE_INTERRUPT_BUF_OVERFLOW	1
  210: 	"interrupt-level buffer overflow",
  211: #define	CE_TTY_BUF_OVERFLOW		2
  212: 	"tty-level buffer overflow",
  213: };
  214: 
  215: #define	CE_NTYPES			3
  216: #define	CE_RECORD(com, errnum)		(++(com)->delta_error_counts[errnum])
  217: 
  218: /* types.  XXX - should be elsewhere */
  219: typedef u_char	bool_t;		/* boolean */
  220: typedef u_char volatile *cy_addr;
  221: 
  222: /* queue of linear buffers */
  223: struct lbq {
  224: 	u_char	*l_head;	/* next char to process */
  225: 	u_char	*l_tail;	/* one past the last char to process */
  226: 	struct lbq *l_next;	/* next in queue */
  227: 	bool_t	l_queued;	/* nonzero if queued */
  228: };
  229: 
  230: /* com device structure */
  231: struct com_s {
  232: 	u_char	state;		/* miscellaneous flag bits */
  233: 	bool_t  active_out;	/* nonzero if the callout device is open */
  234: #if 0
  235: 	u_char	cfcr_image;	/* copy of value written to CFCR */
  236: #endif
  237: 	u_char	etc;		/* pending Embedded Transmit Command */
  238: 	u_char	extra_state;	/* more flag bits, separate for order trick */
  239: #if 0
  240: 	u_char	fifo_image;	/* copy of value written to FIFO */
  241: #endif
  242: 	u_char	gfrcr_image;	/* copy of value read from GFRCR */
  243: #if 0
  244: 	bool_t	hasfifo;	/* nonzero for 16550 UARTs */
  245: 	bool_t	loses_outints;	/* nonzero if device loses output interrupts */
  246: #endif
  247: 	u_char	mcr_dtr;	/* MCR bit that is wired to DTR */
  248: 	u_char	mcr_image;	/* copy of value written to MCR */
  249: 	u_char	mcr_rts;	/* MCR bit that is wired to RTS */
  250: #if 0
  251: #ifdef COM_MULTIPORT
  252: 	bool_t	multiport;	/* is this unit part of a multiport device? */
  253: #endif /* COM_MULTIPORT */
  254: 	bool_t	no_irq;		/* nonzero if irq is not attached */
  255: 	bool_t	poll;		/* nonzero if polling is required */
  256: 	bool_t	poll_output;	/* nonzero if polling for output is required */
  257: #endif
  258: 	int	unit;		/* unit	number */
  259: 	int	dtr_wait;	/* time to hold DTR down on close (* 1/hz) */
  260: #if 0
  261: 	u_int	tx_fifo_size;
  262: #endif
  263: 	u_int	wopeners;	/* # processes waiting for DCD in open() */
  264: 
  265: 	/*
  266: 	 * The high level of the driver never reads status registers directly
  267: 	 * because there would be too many side effects to handle conveniently.
  268: 	 * Instead, it reads copies of the registers stored here by the
  269: 	 * interrupt handler.
  270: 	 */
  271: 	u_char	last_modem_status;	/* last MSR read by intr handler */
  272: 	u_char	prev_modem_status;	/* last MSR handled by high level */
  273: 
  274: 	u_char	hotchar;	/* ldisc-specific char to be handled ASAP */
  275: 	u_char	*ibuf;		/* start of input buffer */
  276: 	u_char	*ibufend;	/* end of input buffer */
  277: 	u_char	*ibufold;	/* old input buffer, to be freed */
  278: 	u_char	*ihighwater;	/* threshold in input buffer */
  279: 	u_char	*iptr;		/* next free spot in input buffer */
  280: 	int	ibufsize;	/* size of ibuf (not include error bytes) */
  281: 	int	ierroff;	/* offset of error bytes in ibuf */
  282: 
  283: 	struct lbq	obufq;	/* head of queue of output buffers */
  284: 	struct lbq	obufs[2];	/* output buffers */
  285: 
  286: 	int	cy_align;	/* index for register alignment */
  287: 	cy_addr	cy_iobase;	/* base address of this port's cyclom */
  288: 	cy_addr	iobase;		/* base address of this port's cd1400 */
  289: 	int	mcr_rts_reg;	/* cd1400 reg number of reg holding mcr_rts */
  290: 
  291: 	struct tty	*tp;	/* cross reference */
  292: 
  293: 	/* Initial state. */
  294: 	struct termios	it_in;	/* should be in struct tty */
  295: 	struct termios	it_out;
  296: 
  297: 	/* Lock state. */
  298: 	struct termios	lt_in;	/* should be in struct tty */
  299: 	struct termios	lt_out;
  300: 
  301: 	bool_t	do_timestamp;
  302: 	bool_t	do_dcd_timestamp;
  303: 	struct timeval	timestamp;
  304: 	struct timeval	dcd_timestamp;
  305: 
  306: 	u_long	bytes_in;	/* statistics */
  307: 	u_long	bytes_out;
  308: 	u_int	delta_error_counts[CE_NTYPES];
  309: 	u_long	error_counts[CE_NTYPES];
  310: 
  311: 	u_int	recv_exception;	/* exception chars received */
  312: 	u_int	mdm;		/* modem signal changes */
  313: #ifdef CyDebug
  314: 	u_int	start_count;	/* no. of calls to comstart() */
  315: 	u_int	start_real;	/* no. of calls that did something */
  316: #endif
  317: 	u_char	car;		/* CD1400 CAR shadow (if first unit in cd) */
  318: 	u_char	channel_control;/* CD1400 CCR control command shadow */
  319: 	u_char	cor[3];		/* CD1400 COR1-3 shadows */
  320: 	u_char	intr_enable;	/* CD1400 SRER shadow */
  321: 
  322: 	/*
  323: 	 * Data area for output buffers.  Someday we should build the output
  324: 	 * buffer queue without copying data.
  325: 	 */
  326: 	u_char	obuf1[256];
  327: 	u_char	obuf2[256];
  328: };
  329: 
  330: /* PCI driver entry point. */
  331: int	cyattach_common		(cy_addr cy_iobase, int cy_align);
  332: ointhand2_t	siointr;
  333: 
  334: static	int	cy_units	(cy_addr cy_iobase, int cy_align);
  335: static	int	sioattach	(struct isa_device *dev);
  336: static	void	cd1400_channel_cmd (struct com_s *com, int cmd);
  337: static	void	cd1400_channel_cmd_wait (struct com_s *com);
  338: static	void	cd_etc		(struct com_s *com, int etc);
  339: static	int	cd_getreg	(struct com_s *com, int reg);
  340: static	void	cd_setreg	(struct com_s *com, int reg, int val);
  341: static	timeout_t siodtrwakeup;
  342: static	void	comhardclose	(struct com_s *com);
  343: static	void	sioinput	(struct com_s *com);
  344: #if 0
  345: static	void	siointr1	(struct com_s *com);
  346: #endif
  347: static	int	commctl		(struct com_s *com, int bits, int how);
  348: static	int	comparam	(struct tty *tp, struct termios *t);
  349: static	inthand2_t siopoll;
  350: static	int	sioprobe	(struct isa_device *dev);
  351: static	void	siosettimeout	(void);
  352: static	int	siosetwater	(struct com_s *com, speed_t speed);
  353: static	int	comspeed	(speed_t speed, u_long cy_clock,
  354: 				     int *prescaler_io);
  355: static	void	comstart	(struct tty *tp);
  356: static	void	comstop		(struct tty *tp, int rw);
  357: static	timeout_t comwakeup;
  358: static	void	disc_optim	(struct tty	*tp, struct termios *t,
  359: 				     struct com_s *com);
  360: 
  361: #ifdef CyDebug
  362: void	cystatus	(int unit);
  363: #endif
  364: 
  365: static char driver_name[] = "cy";
  366: 
  367: /* table and macro for fast conversion from a unit number to its com struct */
  368: static	struct com_s	*p_com_addr[NSIO];
  369: #define	com_addr(unit)	(p_com_addr[unit])
  370: 
  371: struct isa_driver	siodriver = {
  372: 	sioprobe, sioattach, driver_name
  373: };
  374: 
  375: static	d_open_t	sioopen;
  376: static	d_close_t	sioclose;
  377: static	d_write_t	siowrite;
  378: static	d_ioctl_t	sioioctl;
  379: 
  380: #define	CDEV_MAJOR	48
  381: static struct cdevsw sio_cdevsw = {
  382: 	/* name */	driver_name,
  383: 	/* maj */	CDEV_MAJOR,
  384: 	/* flags */	D_TTY | D_KQFILTER,
  385: 	/* port */	NULL,
  386: 	/* clone */	NULL,
  387: 
  388: 	/* open */	sioopen,
  389: 	/* close */	sioclose,
  390: 	/* read */	ttyread,
  391: 	/* write */	siowrite,
  392: 	/* ioctl */	sioioctl,
  393: 	/* poll */	ttypoll,
  394: 	/* mmap */	nommap,
  395: 	/* strategy */	nostrategy,
  396: 	/* dump */	nodump,
  397: 	/* psize */	nopsize,
  398: 	/* kqfilter */	ttykqfilter
  399: };
  400: 
  401: static	int	comconsole = -1;
  402: static	speed_t	comdefaultrate = TTYDEF_SPEED;
  403: static	u_int	com_events;	/* input chars + weighted output completions */
  404: static	bool_t	sio_registered;
  405: static	int	sio_timeout;
  406: static	int	sio_timeouts_until_log;
  407: static	struct	callout_handle sio_timeout_handle
  408:     = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
  409: #if 0 /* XXX */
  410: static struct tty	*sio_tty[NSIO];
  411: #else
  412: static struct tty	sio_tty[NSIO];
  413: #endif
  414: static	const int	nsio_tty = NSIO;
  415: 
  416: #ifdef CyDebug
  417: static	u_int	cd_inbs;
  418: static	u_int	cy_inbs;
  419: static	u_int	cd_outbs;
  420: static	u_int	cy_outbs;
  421: static	u_int	cy_svrr_probes;
  422: static	u_int	cy_timeouts;
  423: #endif
  424: 
  425: static	int	cy_chip_offset[] = {
  426: 	0x0000, 0x0400, 0x0800, 0x0c00, 0x0200, 0x0600, 0x0a00, 0x0e00,
  427: };
  428: static	int	cy_nr_cd1400s[NCY];
  429: static	int	cy_total_devices;
  430: #undef	RxFifoThreshold
  431: static	int	volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);
  432: 
  433: static int
  434: sioprobe(dev)
  435: 	struct isa_device	*dev;
  436: {
  437: 	cy_addr	iobase;
  438: 
  439: 	iobase = (cy_addr)dev->id_maddr;
  440: 
  441: 	/* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */
  442: 	cy_inb(iobase, CY16_RESET, 0);	/* XXX? */
  443: 	DELAY(500);	/* wait for the board to get its act together */
  444: 
  445: 	/* this is needed to get the board out of reset */
  446: 	cy_outb(iobase, CY_CLEAR_INTR, 0, 0);
  447: 	DELAY(500);
  448: 
  449: 	return (cy_units(iobase, 0) == 0 ? 0 : -1);
  450: }
  451: 
  452: static int
  453: cy_units(cy_iobase, cy_align)
  454: 	cy_addr	cy_iobase;
  455: 	int	cy_align;
  456: {
  457: 	int	cyu;
  458: 	u_char	firmware_version = 0;  /* assign to avoid warning */
  459: 	int	i;
  460: 	cy_addr	iobase;
  461: 
  462: 	for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) {
  463: 		iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align);
  464: 
  465: 		/* wait for chip to become ready for new command */
  466: 		for (i = 0; i < 10; i++) {
  467: 			DELAY(50);
  468: 			if (!cd_inb(iobase, CD1400_CCR, cy_align))
  469: 				break;
  470: 		}
  471: 
  472: 		/* clear the GFRCR register */
  473: 		cd_outb(iobase, CD1400_GFRCR, cy_align, 0);
  474: 
  475: 		/* issue a reset command */
  476: 		cd_outb(iobase, CD1400_CCR, cy_align,
  477: 			CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
  478: 
  479: 		/* wait for the CD1400 to initialize itself */
  480: 		for (i = 0; i < 200; i++) {
  481: 			DELAY(50);
  482: 
  483: 			/* retrieve firmware version */
  484: 			firmware_version = cd_inb(iobase, CD1400_GFRCR,
  485: 						  cy_align);
  486: 			if ((firmware_version & 0xf0) == 0x40)
  487: 				break;
  488: 		}
  489: 
  490: 		/*
  491: 		 * Anything in the 0x40-0x4F range is fine.
  492: 		 * If one CD1400 is bad then we don't support higher
  493: 		 * numbered good ones on this board.
  494: 		 */
  495: 		if ((firmware_version & 0xf0) != 0x40)
  496: 			break;
  497: 	}
  498: 	return (cyu);
  499: }
  500: 
  501: static int
  502: sioattach(isdp)
  503: 	struct isa_device	*isdp;
  504: {
  505: 	int	adapter;
  506: 
  507: 	adapter = cyattach_common((cy_addr) isdp->id_maddr, 0);
  508: 	if (adapter < 0)
  509: 		return (0);
  510: 
  511: 	/*
  512: 	 * XXX
  513: 	 * This kludge is to allow ISA/PCI device specifications in the
  514: 	 * kernel config file to be in any order.
  515: 	 */
  516: 	if (isdp->id_unit != adapter) {
  517: 		printf("cy%d: attached as cy%d\n", isdp->id_unit, adapter);
  518: 		isdp->id_unit = adapter;	/* XXX */
  519: 	}
  520: 	isdp->id_ointr = siointr;
  521: 	/* isdp->id_ri_flags |= RI_FAST; XXX unimplemented - use newbus! */
  522: 	return (1);
  523: }
  524: 
  525: int
  526: cyattach_common(cy_iobase, cy_align)
  527: 	cy_addr	cy_iobase;
  528: 	int	cy_align;
  529: {
  530: 	int	adapter;
  531: 	int	cyu;
  532: 	u_char	firmware_version;
  533: 	cy_addr	iobase;
  534: 	int	minorbase;
  535: 	int	ncyu;
  536: 	int	unit;
  537: 
  538: 	adapter = cy_total_devices;
  539: 	if ((u_int)adapter >= NCY) {
  540: 		printf(
  541: 	"cy%d: can't attach adapter: insufficient cy devices configured\n",
  542: 		       adapter);
  543: 		return (-1);
  544: 	}
  545: 	ncyu = cy_units(cy_iobase, cy_align);
  546: 	if (ncyu == 0)
  547: 		return (-1);
  548: 	cy_nr_cd1400s[adapter] = ncyu;
  549: 	cy_total_devices++;
  550: 
  551: 	unit = adapter * CY_MAX_PORTS;
  552: 	for (cyu = 0; cyu < ncyu; ++cyu) {
  553: 		int	cdu;
  554: 
  555: 		iobase = (cy_addr) (cy_iobase
  556: 				    + (cy_chip_offset[cyu] << cy_align));
  557: 		firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align);
  558: 
  559: 		/* Set up a receive timeout period of than 1+ ms. */
  560: 		cd_outb(iobase, CD1400_PPR, cy_align,
  561: 			howmany(CY_CLOCK(firmware_version)
  562: 				/ CD1400_PPR_PRESCALER, 1000));
  563: 
  564: 		for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) {
  565: 			struct com_s	*com;
  566: 			int		s;
  567: 
  568: 	com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT);
  569: 	if (com == NULL)
  570: 		break;
  571: 	bzero(com, sizeof *com);
  572: 	com->unit = unit;
  573: 			com->gfrcr_image = firmware_version;
  574: 			if (CY_RTS_DTR_SWAPPED(firmware_version)) {
  575: 				com->mcr_dtr = MCR_RTS;
  576: 				com->mcr_rts = MCR_DTR;
  577: 				com->mcr_rts_reg = CD1400_MSVR2;
  578: 			} else {
  579: 				com->mcr_dtr = MCR_DTR;
  580: 				com->mcr_rts = MCR_RTS;
  581: 				com->mcr_rts_reg = CD1400_MSVR1;
  582: 			}
  583: 	com->dtr_wait = 3 * hz;
  584: 	com->obufs[0].l_head = com->obuf1;
  585: 	com->obufs[1].l_head = com->obuf2;
  586: 
  587: 			com->cy_align = cy_align;
  588: 			com->cy_iobase = cy_iobase;
  589: 	com->iobase = iobase;
  590: 			com->car = ~CD1400_CAR_CHAN;
  591: 
  592: 	/*
  593: 	 * We don't use all the flags from <sys/ttydefaults.h> since they
  594: 	 * are only relevant for logins.  It's important to have echo off
  595: 	 * initially so that the line doesn't start blathering before the
  596: 	 * echo flag can be turned off.
  597: 	 */
  598: 	com->it_in.c_iflag = 0;
  599: 	com->it_in.c_oflag = 0;
  600: 	com->it_in.c_cflag = TTYDEF_CFLAG;
  601: 	com->it_in.c_lflag = 0;
  602: 	if (unit == comconsole) {
  603: 		com->it_in.c_iflag = TTYDEF_IFLAG;
  604: 		com->it_in.c_oflag = TTYDEF_OFLAG;
  605: 		com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
  606: 		com->it_in.c_lflag = TTYDEF_LFLAG;
  607: 		com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
  608: 	}
  609: 	if (siosetwater(com, com->it_in.c_ispeed) != 0) {
  610: 		enable_intr();
  611: 		free(com, M_DEVBUF);
  612: 		return (0);
  613: 	}
  614: 	enable_intr();
  615: 	termioschars(&com->it_in);
  616: 	com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
  617: 	com->it_out = com->it_in;
  618: 
  619: 	s = spltty();
  620: 	com_addr(unit) = com;
  621: 	splx(s);
  622: 
  623: 	if (!sio_registered) {
  624: 		register_swi(SWI_TTY, siopoll, NULL, "cy");
  625: 		sio_registered = TRUE;
  626: 	}
  627: 	minorbase = UNIT_TO_MINOR(unit);
  628: 	cdevsw_add(&sio_cdevsw, UNIT_TO_MINOR(-1), minorbase);
  629: 	make_dev(&sio_cdevsw, minorbase,
  630: 		UID_ROOT, GID_WHEEL, 0600, "ttyc%r%r", adapter,
  631: 		unit % CY_MAX_PORTS);
  632: 	make_dev(&sio_cdevsw, minorbase | CONTROL_INIT_STATE,
  633: 		UID_ROOT, GID_WHEEL, 0600, "ttyic%r%r", adapter,
  634: 		unit % CY_MAX_PORTS);
  635: 	make_dev(&sio_cdevsw, minorbase | CONTROL_LOCK_STATE,
  636: 		UID_ROOT, GID_WHEEL, 0600, "ttylc%r%r", adapter,
  637: 		unit % CY_MAX_PORTS);
  638: 	make_dev(&sio_cdevsw, minorbase | CALLOUT_MASK,
  639: 		UID_UUCP, GID_DIALER, 0660, "cuac%r%r", adapter,
  640: 		unit % CY_MAX_PORTS);
  641: 	make_dev(&sio_cdevsw, minorbase | CALLOUT_MASK | CONTROL_INIT_STATE,
  642: 		UID_UUCP, GID_DIALER, 0660, "cuaic%r%r", adapter,
  643: 		unit % CY_MAX_PORTS);
  644: 	make_dev(&sio_cdevsw, minorbase | CALLOUT_MASK | CONTROL_LOCK_STATE,
  645: 		UID_UUCP, GID_DIALER, 0660, "cualc%r%r", adapter,
  646: 		unit % CY_MAX_PORTS);
  647: 		}
  648: 	}
  649: 
  650: 	/* ensure an edge for the next interrupt */
  651: 	cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
  652: 
  653: 	return (adapter);
  654: }
  655: 
  656: static int
  657: sioopen(dev_t dev, int flag, int mode, struct thread *td)
  658: {
  659: 	struct com_s	*com;
  660: 	int		error;
  661: 	int		mynor;
  662: 	int		s;
  663: 	struct tty	*tp;
  664: 	int		unit;
  665: 
  666: 	mynor = minor(dev);
  667: 	unit = MINOR_TO_UNIT(mynor);
  668: 	if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
  669: 		return (ENXIO);
  670: 	if (mynor & CONTROL_MASK)
  671: 		return (0);
  672: #if 0 /* XXX */
  673: 	tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
  674: #else
  675: 	tp = com->tp = &sio_tty[unit];
  676: #endif
  677: 	dev->si_tty = tp;
  678: 	s = spltty();
  679: 	/*
  680: 	 * We jump to this label after all non-interrupted sleeps to pick
  681: 	 * up any changes of the device state.
  682: 	 */
  683: open_top:
  684: 	while (com->state & CS_DTR_OFF) {
  685: 		error = tsleep(&com->dtr_wait, PCATCH, "cydtr", 0);
  686: 		if (error != 0)
  687: 			goto out;
  688: 	}
  689: 	if (tp->t_state & TS_ISOPEN) {
  690: 		/*
  691: 		 * The device is open, so everything has been initialized.
  692: 		 * Handle conflicts.
  693: 		 */
  694: 		if (mynor & CALLOUT_MASK) {
  695: 			if (!com->active_out) {
  696: 				error = EBUSY;
  697: 				goto out;
  698: 			}
  699: 		} else {
  700: 			if (com->active_out) {
  701: 				if (flag & O_NONBLOCK) {
  702: 					error = EBUSY;
  703: 					goto out;
  704: 				}
  705: 				error =	tsleep(&com->active_out,
  706: 					       PCATCH, "cybi", 0);
  707: 				if (error != 0)
  708: 					goto out;
  709: 				goto open_top;
  710: 			}
  711: 		}
  712: 		if (tp->t_state & TS_XCLUDE &&
  713: 		    suser(td)) {
  714: 			error = EBUSY;
  715: 			goto out;
  716: 		}
  717: 	} else {
  718: 		/*
  719: 		 * The device isn't open, so there are no conflicts.
  720: 		 * Initialize it.  Initialization is done twice in many
  721: 		 * cases: to preempt sleeping callin opens if we are
  722: 		 * callout, and to complete a callin open after DCD rises.
  723: 		 */
  724: 		tp->t_oproc = comstart;
  725: 		tp->t_stop = comstop;
  726: 		tp->t_param = comparam;
  727: 		tp->t_dev = dev;
  728: 		tp->t_termios = mynor & CALLOUT_MASK
  729: 				? com->it_out : com->it_in;
  730: 
  731: 		/* Encode per-board unit in LIVR for access in intr routines. */
  732: 		cd_setreg(com, CD1400_LIVR,
  733: 			  (unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT);
  734: 
  735: 		(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
  736: #if 0
  737: 		com->poll = com->no_irq;
  738: 		com->poll_output = com->loses_outints;
  739: #endif
  740: 		++com->wopeners;
  741: 		error = comparam(tp, &tp->t_termios);
  742: 		--com->wopeners;
  743: 		if (error != 0)
  744: 			goto out;
  745: #if 0
  746: 		if (com->hasfifo) {
  747: 			/*
  748: 			 * (Re)enable and flush fifos.
  749: 			 *
  750: 			 * Certain SMC chips cause problems if the fifos
  751: 			 * are enabled while input is ready.  Turn off the
  752: 			 * fifo if necessary to clear the input.  We test
  753: 			 * the input ready bit after enabling the fifos
  754: 			 * since we've already enabled them in comparam()
  755: 			 * and to handle races between enabling and fresh
  756: 			 * input.
  757: 			 */
  758: 			while (TRUE) {
  759: 				outb(iobase + com_fifo,
  760: 				     FIFO_RCV_RST | FIFO_XMT_RST
  761: 				     | com->fifo_image);
  762: 				DELAY(100);
  763: 				if (!(inb(com->line_status_port) & LSR_RXRDY))
  764: 					break;
  765: 				outb(iobase + com_fifo, 0);
  766: 				DELAY(100);
  767: 				(void) inb(com->data_port);
  768: 			}
  769: 		}
  770: 
  771: 		disable_intr();
  772: 		(void) inb(com->line_status_port);
  773: 		(void) inb(com->data_port);
  774: 		com->prev_modem_status = com->last_modem_status
  775: 		    = inb(com->modem_status_port);
  776: 		outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
  777: 				       | IER_EMSC);
  778: 		enable_intr();
  779: #else /* !0 */
  780: 		/*
  781: 		 * Flush fifos.  This requires a full channel reset which
  782: 		 * also disables the transmitter and receiver.  Recover
  783: 		 * from this.
  784: 		 */
  785: 		cd1400_channel_cmd(com,
  786: 				   CD1400_CCR_CMDRESET | CD1400_CCR_CHANRESET);
  787: 		cd1400_channel_cmd(com, com->channel_control);
  788: 
  789: 		disable_intr();
  790: 		com->prev_modem_status = com->last_modem_status
  791: 		    = cd_getreg(com, CD1400_MSVR2);
  792: 		cd_setreg(com, CD1400_SRER,
  793: 			  com->intr_enable
  794: 			  = CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
  795: 		enable_intr();
  796: #endif /* 0 */
  797: 		/*
  798: 		 * Handle initial DCD.  Callout devices get a fake initial
  799: 		 * DCD (trapdoor DCD).  If we are callout, then any sleeping
  800: 		 * callin opens get woken up and resume sleeping on "cybi"
  801: 		 * instead of "cydcd".
  802: 		 */
  803: 		/*
  804: 		 * XXX `mynor & CALLOUT_MASK' should be
  805: 		 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
  806: 		 * TRAPDOOR_CARRIER is the default initial state for callout
  807: 		 * devices and SOFT_CARRIER is like CLOCAL except it hides
  808: 		 * the true carrier.
  809: 		 */
  810: 		if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
  811: 			(*linesw[tp->t_line].l_modem)(tp, 1);
  812: 	}
  813: 	/*
  814: 	 * Wait for DCD if necessary.
  815: 	 */
  816: 	if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
  817: 	    && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
  818: 		++com->wopeners;
  819: 		error = tsleep(TSA_CARR_ON(tp), PCATCH, "cydcd", 0);
  820: 		--com->wopeners;
  821: 		if (error != 0)
  822: 			goto out;
  823: 		goto open_top;
  824: 	}
  825: 	error =	(*linesw[tp->t_line].l_open)(dev, tp);
  826: 	disc_optim(tp, &tp->t_termios, com);
  827: 	if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
  828: 		com->active_out = TRUE;
  829: 	siosettimeout();
  830: out:
  831: 	splx(s);
  832: 	if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
  833: 		comhardclose(com);
  834: 	return (error);
  835: }
  836: 
  837: static int
  838: sioclose(dev_t dev, int flag, int mode, struct thread *td)
  839: {
  840: 	struct com_s	*com;
  841: 	int		mynor;
  842: 	int		s;
  843: 	struct tty	*tp;
  844: 
  845: 	mynor = minor(dev);
  846: 	if (mynor & CONTROL_MASK)
  847: 		return (0);
  848: 	com = com_addr(MINOR_TO_UNIT(mynor));
  849: 	tp = com->tp;
  850: 	s = spltty();
  851: 	cd_etc(com, CD1400_ETC_STOPBREAK);
  852: 	(*linesw[tp->t_line].l_close)(tp, flag);
  853: 	disc_optim(tp, &tp->t_termios, com);
  854: 	comstop(tp, FREAD | FWRITE);
  855: 	comhardclose(com);
  856: 	ttyclose(tp);
  857: 	siosettimeout();
  858: 	splx(s);
  859: #ifdef broken /* session holds a ref to the tty; can't deallocate */
  860: 	ttyfree(tp);
  861: 	com->tp = sio_tty[unit] = NULL;
  862: #endif
  863: 	return (0);
  864: }
  865: 
  866: static void
  867: comhardclose(com)
  868: 	struct com_s	*com;
  869: {
  870: 	cy_addr		iobase;
  871: 	int		s;
  872: 	struct tty	*tp;
  873: 	int		unit;
  874: 
  875: 	unit = com->unit;
  876: 	iobase = com->iobase;
  877: 	s = spltty();
  878: #if 0
  879: 	com->poll = FALSE;
  880: 	com->poll_output = FALSE;
  881: #endif
  882: 	com->do_timestamp = 0;
  883: #if 0
  884: 	outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
  885: #else
  886: 	/* XXX */
  887: 	disable_intr();
  888: 	com->etc = ETC_NONE;
  889: 	cd_setreg(com, CD1400_COR2, com->cor[1] &= ~CD1400_COR2_ETC);
  890: 	enable_intr();
  891: 	cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);
  892: #endif
  893: 
  894: 	{
  895: #if 0
  896: 		outb(iobase + com_ier, 0);
  897: #else
  898: 		disable_intr();
  899: 		cd_setreg(com, CD1400_SRER, com->intr_enable = 0);
  900: 		enable_intr();
  901: #endif
  902: 		tp = com->tp;
  903: 		if ((tp->t_cflag & HUPCL)
  904: 		    /*
  905: 		     * XXX we will miss any carrier drop between here and the
  906: 		     * next open.  Perhaps we should watch DCD even when the
  907: 		     * port is closed; it is not sufficient to check it at
  908: 		     * the next open because it might go up and down while
  909: 		     * we're not watching.
  910: 		     */
  911: 		    || (!com->active_out
  912: 		       && !(com->prev_modem_status & MSR_DCD)
  913: 		       && !(com->it_in.c_cflag & CLOCAL))
  914: 		    || !(tp->t_state & TS_ISOPEN)) {
  915: 			(void)commctl(com, TIOCM_DTR, DMBIC);
  916: 
  917: 			/* Disable receiver (leave transmitter enabled). */
  918: 			com->channel_control = CD1400_CCR_CMDCHANCTL
  919: 					       | CD1400_CCR_XMTEN
  920: 					       | CD1400_CCR_RCVDIS;
  921: 			cd1400_channel_cmd(com, com->channel_control);
  922: 
  923: 			if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
  924: 				timeout(siodtrwakeup, com, com->dtr_wait);
  925: 				com->state |= CS_DTR_OFF;
  926: 			}
  927: 		}
  928: 	}
  929: #if 0
  930: 	if (com->hasfifo) {
  931: 		/*
  932: 		 * Disable fifos so that they are off after controlled
  933: 		 * reboots.  Some BIOSes fail to detect 16550s when the
  934: 		 * fifos are enabled.
  935: 		 */
  936: 		outb(iobase + com_fifo, 0);
  937: 	}
  938: #endif
  939: 	com->active_out = FALSE;
  940: 	wakeup(&com->active_out);
  941: 	wakeup(TSA_CARR_ON(tp));	/* restart any wopeners */
  942: 	splx(s);
  943: }
  944: 
  945: static int
  946: siowrite(dev, uio, flag)
  947: 	dev_t		dev;
  948: 	struct uio	*uio;
  949: 	int		flag;
  950: {
  951: 	int		mynor;
  952: 	struct tty	*tp;
  953: 	int		unit;
  954: 
  955: 	mynor = minor(dev);
  956: 	if (mynor & CONTROL_MASK)
  957: 		return (ENODEV);
  958: 
  959: 	unit = MINOR_TO_UNIT(mynor);
  960: 	tp = com_addr(unit)->tp;
  961: 	/*
  962: 	 * (XXX) We disallow virtual consoles if the physical console is
  963: 	 * a serial port.  This is in case there is a display attached that
  964: 	 * is not the console.  In that situation we don't need/want the X
  965: 	 * server taking over the console.
  966: 	 */
  967: 	if (constty != NULL && unit == comconsole)
  968: 		constty = NULL;
  969: #ifdef Smarts
  970: 	/* XXX duplicate ttwrite(), but without so much output processing on
  971: 	 * CR & LF chars.  Hardly worth the effort, given that high-throughput
  972: 	 * sessions are raw anyhow.
  973: 	 */
  974: #else
  975: 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
  976: #endif
  977: }
  978: 
  979: static void
  980: siodtrwakeup(chan)
  981: 	void	*chan;
  982: {
  983: 	struct com_s	*com;
  984: 
  985: 	com = (struct com_s *)chan;
  986: 	com->state &= ~CS_DTR_OFF;
  987: 	wakeup(&com->dtr_wait);
  988: }
  989: 
  990: static void
  991: sioinput(com)
  992: 	struct com_s	*com;
  993: {
  994: 	u_char		*buf;
  995: 	int		incc;
  996: 	u_char		line_status;
  997: 	int		recv_data;
  998: 	struct tty	*tp;
  999: 
 1000: 	buf = com->ibuf;
 1001: 	tp = com->tp;
 1002: 	if (!(tp->t_state & TS_ISOPEN)) {
 1003: 		com_events -= (com->iptr - com->ibuf);
 1004: 		com->iptr = com->ibuf;
 1005: 		return;
 1006: 	}
 1007: 	if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
 1008: 		/*
 1009: 		 * Avoid the grotesquely inefficient lineswitch routine
 1010: 		 * (ttyinput) in "raw" mode.  It usually takes about 450
 1011: 		 * instructions (that's without canonical processing or echo!).
 1012: 		 * slinput is reasonably fast (usually 40 instructions plus
 1013: 		 * call overhead).
 1014: 		 */
 1015: 		do {
 1016: 			enable_intr();
 1017: 			incc = com->iptr - buf;
 1018: 			if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
 1019: 			    && (com->state & CS_RTS_IFLOW
 1020: 				|| tp->t_iflag & IXOFF)
 1021: 			    && !(tp->t_state & TS_TBLOCK))
 1022: 				ttyblock(tp);
 1023: 			com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
 1024: 				+= b_to_q((char *)buf, incc, &tp->t_rawq);
 1025: 			buf += incc;
 1026: 			tk_nin += incc;
 1027: 			tk_rawcc += incc;
 1028: 			tp->t_rawcc += incc;
 1029: 			ttwakeup(tp);
 1030: 			if (tp->t_state & TS_TTSTOP
 1031: 			    && (tp->t_iflag & IXANY
 1032: 				|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
 1033: 				tp->t_state &= ~TS_TTSTOP;
 1034: 				tp->t_lflag &= ~FLUSHO;
 1035: 				comstart(tp);
 1036: 			}
 1037: 			disable_intr();
 1038: 		} while (buf < com->iptr);
 1039: 	} else {
 1040: 		do {
 1041: 			enable_intr();
 1042: 			line_status = buf[com->ierroff];
 1043: 			recv_data = *buf++;
 1044: 			if (line_status
 1045: 			    & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
 1046: 				if (line_status & LSR_BI)
 1047: 					recv_data |= TTY_BI;
 1048: 				if (line_status & LSR_FE)
 1049: 					recv_data |= TTY_FE;
 1050: 				if (line_status & LSR_OE)
 1051: 					recv_data |= TTY_OE;
 1052: 				if (line_status & LSR_PE)
 1053: 					recv_data |= TTY_PE;
 1054: 			}
 1055: 			(*linesw[tp->t_line].l_rint)(recv_data, tp);
 1056: 			disable_intr();
 1057: 		} while (buf < com->iptr);
 1058: 	}
 1059: 	com_events -= (com->iptr - com->ibuf);
 1060: 	com->iptr = com->ibuf;
 1061: 
 1062: 	/*
 1063: 	 * There is now room for another low-level buffer full of input,
 1064: 	 * so enable RTS if it is now disabled and there is room in the
 1065: 	 * high-level buffer.
 1066: 	 */
 1067: 	if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & com->mcr_rts) &&
 1068: 	    !(tp->t_state & TS_TBLOCK))
 1069: #if 0
 1070: 		outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
 1071: #else
 1072: 		cd_setreg(com, com->mcr_rts_reg,
 1073: 			  com->mcr_image |= com->mcr_rts);
 1074: #endif
 1075: }
 1076: 
 1077: void
 1078: siointr(unit)
 1079: 	int	unit;
 1080: {
 1081: 	int	baseu;
 1082: 	int	cy_align;
 1083: 	cy_addr	cy_iobase;
 1084: 	int	cyu;
 1085: 	cy_addr	iobase;
 1086: 	u_char	status;
 1087: 
 1088: 	com_lock();	/* XXX could this be placed down lower in the loop? */
 1089: 
 1090: 	baseu = unit * CY_MAX_PORTS;
 1091: 	cy_align = com_addr(baseu)->cy_align;
 1092: 	cy_iobase = com_addr(baseu)->cy_iobase;
 1093: 
 1094: 	/* check each CD1400 in turn */
 1095: 	for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) {
 1096: 		iobase = (cy_addr) (cy_iobase
 1097: 				    + (cy_chip_offset[cyu] << cy_align));
 1098: 		/* poll to see if it has any work */
 1099: 		status = cd_inb(iobase, CD1400_SVRR, cy_align);
 1100: 		if (status == 0)
 1101: 			continue;
 1102: #ifdef CyDebug
 1103: 		++cy_svrr_probes;
 1104: #endif
 1105: 		/* service requests as appropriate, giving priority to RX */
 1106: 		if (status & CD1400_SVRR_RXRDY) {
 1107: 			struct com_s	*com;
 1108: 			u_int		count;
 1109: 			u_char		*ioptr;
 1110: 			u_char		line_status;
 1111: 			u_char		recv_data;
 1112: 			u_char		serv_type;
 1113: #ifdef PollMode
 1114: 			u_char		save_rir;
 1115: #endif
 1116: 
 1117: #ifdef PollMode
 1118: 			save_rir = cd_inb(iobase, CD1400_RIR, cy_align);
 1119: 
 1120: 			/* enter rx service */
 1121: 			cd_outb(iobase, CD1400_CAR, cy_align, save_rir);
 1122: 			com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car
 1123: 			= save_rir & CD1400_CAR_CHAN;
 1124: 
 1125: 			serv_type = cd_inb(iobase, CD1400_RIVR, cy_align);
 1126: 			com = com_addr(baseu
 1127: 				       + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
 1128: 					  & CD1400_xIVR_CHAN));
 1129: #else
 1130: 			/* ack receive service */
 1131: 			serv_type = cy_inb(iobase, CY8_SVCACKR, cy_align);
 1132: 
 1133: 			com = com_addr(baseu +
 1134: 				       + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
 1135: 					  & CD1400_xIVR_CHAN));
 1136: #endif
 1137: 
 1138: 		if (serv_type & CD1400_RIVR_EXCEPTION) {
 1139: 			++com->recv_exception;
 1140: 			line_status = cd_inb(iobase, CD1400_RDSR, cy_align);
 1141: 			/* break/unnattached error bits or real input? */
 1142: 			recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
 1143: #ifndef SOFT_HOTCHAR
 1144: 			if (line_status & CD1400_RDSR_SPECIAL
 1145: 			    && com->hotchar != 0)
 1146: 				setsofttty();
 1147: #endif
 1148: #if 1 /* XXX "intelligent" PFO error handling would break O error handling */
 1149: 			if (line_status & (LSR_PE|LSR_FE|LSR_BI)) {
 1150: 				/*
 1151: 				  Don't store PE if IGNPAR and BI if IGNBRK,
 1152: 				  this hack allows "raw" tty optimization
 1153: 				  works even if IGN* is set.
 1154: 				*/
 1155: 				if (   com->tp == NULL
 1156: 				    || !(com->tp->t_state & TS_ISOPEN)
 1157: 				    || ((line_status & (LSR_PE|LSR_FE))
 1158: 				    &&  (com->tp->t_iflag & IGNPAR))
 1159: 				    || ((line_status & LSR_BI)
 1160: 				    &&  (com->tp->t_iflag & IGNBRK)))
 1161: 					goto cont;
 1162: 				if (   (line_status & (LSR_PE|LSR_FE))
 1163: 				    && (com->tp->t_state & TS_CAN_BYPASS_L_RINT)
 1164: 				    && ((line_status & LSR_FE)
 1165: 				    ||  ((line_status & LSR_PE)
 1166: 				    &&  (com->tp->t_iflag & INPCK))))
 1167: 					recv_data = 0;
 1168: 			}
 1169: #endif /* 1 */
 1170: 			++com->bytes_in;
 1171: #ifdef SOFT_HOTCHAR
 1172: 			if (com->hotchar != 0 && recv_data == com->hotchar)
 1173: 				setsofttty();
 1174: #endif
 1175: 			ioptr = com->iptr;
 1176: 			if (ioptr >= com->ibufend)
 1177: 				CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
 1178: 			else {
 1179: 				if (com->do_timestamp)
 1180: 					microtime(&com->timestamp);
 1181: 				++com_events;
 1182: 				ioptr[0] = recv_data;
 1183: 				ioptr[com->ierroff] = line_status;
 1184: 				com->iptr = ++ioptr;
 1185: 				if (ioptr == com->ihighwater
 1186: 				    && com->state & CS_RTS_IFLOW)
 1187: #if 0
 1188: 					outb(com->modem_ctl_port,
 1189: 					     com->mcr_image &= ~MCR_RTS);
 1190: #else
 1191: 					cd_outb(iobase, com->mcr_rts_reg,
 1192: 						cy_align,
 1193: 						com->mcr_image &=
 1194: 						~com->mcr_rts);
 1195: #endif
 1196: 				if (line_status & LSR_OE)
 1197: 					CE_RECORD(com, CE_OVERRUN);
 1198: 			}
 1199: 			goto cont;
 1200: 		} else {
 1201: 			int	ifree;
 1202: 
 1203: 			count = cd_inb(iobase, CD1400_RDCR, cy_align);
 1204: 			if (!count)
 1205: 				goto cont;
 1206: 			com->bytes_in += count;
 1207: 			ioptr = com->iptr;
 1208: 			ifree = com->ibufend - ioptr;
 1209: 			if (count > ifree) {
 1210: 				count -= ifree;
 1211: 				com_events += ifree;
 1212: 				if (ifree != 0) {
 1213: 					if (com->do_timestamp)
 1214: 						microtime(&com->timestamp);
 1215: 					do {
 1216: 						recv_data = cd_inb(iobase,
 1217: 								   CD1400_RDSR,
 1218: 								   cy_align);
 1219: #ifdef SOFT_HOTCHAR
 1220: 						if (com->hotchar != 0
 1221: 						    && recv_data
 1222: 						       == com->hotchar)
 1223: 							setsofttty();
 1224: #endif
 1225: 						ioptr[0] = recv_data;
 1226: 						ioptr[com->ierroff] = 0;
 1227: 						++ioptr;
 1228: 					} while (--ifree != 0);
 1229: 				}
 1230: 				com->delta_error_counts
 1231: 				    [CE_INTERRUPT_BUF_OVERFLOW] += count;
 1232: 				do {
 1233: 					recv_data = cd_inb(iobase, CD1400_RDSR,
 1234: 							   cy_align);
 1235: #ifdef SOFT_HOTCHAR
 1236: 					if (com->hotchar != 0
 1237: 					    && recv_data == com->hotchar)
 1238: 						setsofttty();
 1239: #endif
 1240: 				} while (--count != 0);
 1241: 			} else {
 1242: 				if (com->do_timestamp)
 1243: 					microtime(&com->timestamp);
 1244: 				if (ioptr <= com->ihighwater
 1245: 				    && ioptr + count > com->ihighwater
 1246: 				    && com->state & CS_RTS_IFLOW)
 1247: #if 0
 1248: 					outb(com->modem_ctl_port,
 1249: 					     com->mcr_image &= ~MCR_RTS);
 1250: #else
 1251: 					cd_outb(iobase, com->mcr_rts_reg,
 1252: 						cy_align,
 1253: 						com->mcr_image
 1254: 						&= ~com->mcr_rts);
 1255: #endif
 1256: 				com_events += count;
 1257: 				do {
 1258: 					recv_data = cd_inb(iobase, CD1400_RDSR,
 1259: 							   cy_align);
 1260: #ifdef SOFT_HOTCHAR
 1261: 					if (com->hotchar != 0
 1262: 					    && recv_data == com->hotchar)
 1263: 						setsofttty();
 1264: #endif
 1265: 					ioptr[0] = recv_data;
 1266: 					ioptr[com->ierroff] = 0;
 1267: 					++ioptr;
 1268: 				} while (--count != 0);
 1269: 			}
 1270: 			com->iptr = ioptr;
 1271: 		}
 1272: cont:
 1273: 
 1274: 			/* terminate service context */
 1275: #ifdef PollMode
 1276: 			cd_outb(iobase, CD1400_RIR, cy_align,
 1277: 				save_rir
 1278: 				& ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));
 1279: #else
 1280: 			cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
 1281: #endif
 1282: 		}
 1283: 		if (status & CD1400_SVRR_MDMCH) {
 1284: 			struct com_s	*com;
 1285: 			u_char	modem_status;
 1286: #ifdef PollMode
 1287: 			u_char	save_mir;
 1288: #else
 1289: 			u_char	vector;
 1290: #endif
 1291: 
 1292: #ifdef PollMode
 1293: 			save_mir = cd_inb(iobase, CD1400_MIR, cy_align);
 1294: 
 1295: 			/* enter modem service */
 1296: 			cd_outb(iobase, CD1400_CAR, cy_align, save_mir);
 1297: 			com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car
 1298: 			= save_mir & CD1400_CAR_CHAN;
 1299: 
 1300: 			com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS
 1301: 				       + (save_mir & CD1400_MIR_CHAN));
 1302: #else
 1303: 			/* ack modem service */
 1304: 			vector = cy_inb(iobase, CY8_SVCACKM, cy_align);
 1305: 
 1306: 			com = com_addr(baseu
 1307: 				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)
 1308: 					  & CD1400_xIVR_CHAN));
 1309: #endif
 1310: 			++com->mdm;
 1311: 			modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align);
 1312: 		if (modem_status != com->last_modem_status) {
 1313: 			if (com->do_dcd_timestamp
 1314: 			    && !(com->last_modem_status & MSR_DCD)
 1315: 			    && modem_status & MSR_DCD)
 1316: 				microtime(&com->dcd_timestamp);
 1317: 
 1318: 			/*
 1319: 			 * Schedule high level to handle DCD changes.  Note
 1320: 			 * that we don't use the delta bits anywhere.  Some
 1321: 			 * UARTs mess them up, and it's easy to remember the
 1322: 			 * previous bits and calculate the delta.
 1323: 			 */
 1324: 			com->last_modem_status = modem_status;
 1325: 			if (!(com->state & CS_CHECKMSR)) {
 1326: 				com_events += LOTS_OF_EVENTS;
 1327: 				com->state |= CS_CHECKMSR;
 1328: 				setsofttty();
 1329: 			}
 1330: 
 1331: #ifdef SOFT_CTS_OFLOW
 1332: 			/* handle CTS change immediately for crisp flow ctl */
 1333: 			if (com->state & CS_CTS_OFLOW) {
 1334: 				if (modem_status & MSR_CTS) {
 1335: 					com->state |= CS_ODEVREADY;
 1336: 					if (com->state >= (CS_BUSY | CS_TTGO
 1337: 							   | CS_ODEVREADY)
 1338: 					    && !(com->intr_enable
 1339: 						 & CD1400_SRER_TXRDY))
 1340: 						cd_outb(iobase, CD1400_SRER,
 1341: 							cy_align,
 1342: 							com->intr_enable
 1343: 							= com->intr_enable
 1344: 							  & ~CD1400_SRER_TXMPTY
 1345: 							  | CD1400_SRER_TXRDY);
 1346: 				} else {
 1347: 					com->state &= ~CS_ODEVREADY;
 1348: 					if (com->intr_enable
 1349: 					    & CD1400_SRER_TXRDY)
 1350: 						cd_outb(iobase, CD1400_SRER,
 1351: 							cy_align,
 1352: 							com->intr_enable
 1353: 							= com->intr_enable
 1354: 							  & ~CD1400_SRER_TXRDY
 1355: 							  | CD1400_SRER_TXMPTY);
 1356: 				}
 1357: 			}
 1358: #endif
 1359: 		}
 1360: 
 1361: 			/* terminate service context */
 1362: #ifdef PollMode
 1363: 			cd_outb(iobase, CD1400_MIR, cy_align,
 1364: 				save_mir
 1365: 				& ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));
 1366: #else
 1367: 			cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
 1368: #endif
 1369: 		}
 1370: 		if (status & CD1400_SVRR_TXRDY) {
 1371: 			struct com_s	*com;
 1372: #ifdef PollMode
 1373: 			u_char	save_tir;
 1374: #else
 1375: 			u_char	vector;
 1376: #endif
 1377: 
 1378: #ifdef PollMode
 1379: 			save_tir = cd_inb(iobase, CD1400_TIR, cy_align);
 1380: 
 1381: 			/* enter tx service */
 1382: 			cd_outb(iobase, CD1400_CAR, cy_align, save_tir);
 1383: 			com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car
 1384: 			= save_tir & CD1400_CAR_CHAN;
 1385: 
 1386: 			com = com_addr(baseu
 1387: 				       + cyu * CD1400_NO_OF_CHANNELS
 1388: 				       + (save_tir & CD1400_TIR_CHAN));
 1389: #else
 1390: 			/* ack transmit service */
 1391: 			vector = cy_inb(iobase, CY8_SVCACKT, cy_align);
 1392: 
 1393: 			com = com_addr(baseu
 1394: 				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)
 1395: 					  & CD1400_xIVR_CHAN));
 1396: #endif
 1397: 
 1398: 			if (com->etc != ETC_NONE) {
 1399: 				if (com->intr_enable & CD1400_SRER_TXRDY) {
 1400: 					/*
 1401: 					 * Here due to sloppy SRER_TXRDY
 1402: 					 * enabling.  Ignore.  Come back when
 1403: 					 * tx is empty.
 1404: 					 */
 1405: 					cd_outb(iobase, CD1400_SRER, cy_align,
 1406: 						com->intr_enable
 1407: 						= (com->intr_enable
 1408: 						  & ~CD1400_SRER_TXRDY)
 1409: 						  | CD1400_SRER_TXMPTY);
 1410: 					goto terminate_tx_service;
 1411: 				}
 1412: 				switch (com->etc) {
 1413: 				case CD1400_ETC_SENDBREAK:
 1414: 				case CD1400_ETC_STOPBREAK:
 1415: 					/*
 1416: 					 * Start the command.  Come back on
 1417: 					 * next tx empty interrupt, hopefully
 1418: 					 * after command has been executed.
 1419: 					 */
 1420: 					cd_outb(iobase, CD1400_COR2, cy_align,
 1421: 						com->cor[1] |= CD1400_COR2_ETC);
 1422: 					cd_outb(iobase, CD1400_TDR, cy_align,
 1423: 						CD1400_ETC_CMD);
 1424: 					cd_outb(iobase, CD1400_TDR, cy_align,
 1425: 						com->etc);
 1426: 					if (com->etc == CD1400_ETC_SENDBREAK)
 1427: 						com->etc = ETC_BREAK_STARTING;
 1428: 					else
 1429: 						com->etc = ETC_BREAK_ENDING;
 1430: 					goto terminate_tx_service;
 1431: 				case ETC_BREAK_STARTING:
 1432: 					/*
 1433: 					 * BREAK is now on.  Continue with
 1434: 					 * SRER_TXMPTY processing, hopefully
 1435: 					 * don't come back.
 1436: 					 */
 1437: 					com->etc = ETC_BREAK_STARTED;
 1438: 					break;
 1439: 				case ETC_BREAK_STARTED:
 1440: 					/*
 1441: 					 * Came back due to sloppy SRER_TXMPTY
 1442: 					 * enabling.  Hope again.
 1443: 					 */
 1444: 					break;
 1445: 				case ETC_BREAK_ENDING:
 1446: 					/*
 1447: 					 * BREAK is now off.  Continue with
 1448: 					 * SRER_TXMPTY processing and don't
 1449: 					 * come back.  The SWI handler will
 1450: 					 * restart tx interrupts if necessary.
 1451: 					 */
 1452: 					cd_outb(iobase, CD1400_COR2, cy_align,
 1453: 						com->cor[1]
 1454: 						&= ~CD1400_COR2_ETC);
 1455: 					com->etc = ETC_BREAK_ENDED;
 1456: 					if (!(com->state & CS_ODONE)) {
 1457: 						com_events += LOTS_OF_EVENTS;
 1458: 						com->state |= CS_ODONE;
 1459: 						setsofttty();
 1460: 					}
 1461: 					break;
 1462: 				case ETC_BREAK_ENDED:
 1463: 					/*
 1464: 					 * Shouldn't get here.  Hope again.
 1465: 					 */
 1466: 					break;
 1467: 				}
 1468: 			}
 1469: 			if (com->intr_enable & CD1400_SRER_TXMPTY) {
 1470: 				if (!(com->extra_state & CSE_ODONE)) {
 1471: 					com_events += LOTS_OF_EVENTS;
 1472: 					com->extra_state |= CSE_ODONE;
 1473: 					setsofttty();
 1474: 				}
 1475: 				cd_outb(iobase, CD1400_SRER, cy_align,
 1476: 					com->intr_enable
 1477: 					&= ~CD1400_SRER_TXMPTY);
 1478: 				goto terminate_tx_service;
 1479: 			}
 1480: 		if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
 1481: 			u_char	*ioptr;
 1482: 			u_int	ocount;
 1483: 
 1484: 			ioptr = com->obufq.l_head;
 1485: 				ocount = com->obufq.l_tail - ioptr;
 1486: 				if (ocount > CD1400_TX_FIFO_SIZE)
 1487: 					ocount = CD1400_TX_FIFO_SIZE;
 1488: 				com->bytes_out += ocount;
 1489: 				do
 1490: 					cd_outb(iobase, CD1400_TDR, cy_align,
 1491: 						*ioptr++);
 1492: 				while (--ocount != 0);
 1493: 			com->obufq.l_head = ioptr;
 1494: 			if (ioptr >= com->obufq.l_tail) {
 1495: 				struct lbq	*qp;
 1496: 
 1497: 				qp = com->obufq.l_next;
 1498: 				qp->l_queued = FALSE;
 1499: 				qp = qp->l_next;
 1500: 				if (qp != NULL) {
 1501: 					com->obufq.l_head = qp->l_head;
 1502: 					com->obufq.l_tail = qp->l_tail;
 1503: 					com->obufq.l_next = qp;
 1504: 				} else {
 1505: 					/* output just completed */
 1506: 					com->state &= ~CS_BUSY;
 1507: 
 1508: 					/*
 1509: 					 * The setting of CSE_ODONE may be
 1510: 					 * stale here.  We currently only
 1511: 					 * use it when CS_BUSY is set, and
 1512: 					 * fixing it when we clear CS_BUSY
 1513: 					 * is easiest.
 1514: 					 */
 1515: 					if (com->extra_state & CSE_ODONE) {
 1516: 						com_events -= LOTS_OF_EVENTS;
 1517: 						com->extra_state &= ~CSE_ODONE;
 1518: 					}
 1519: 
 1520: 					cd_outb(iobase, CD1400_SRER, cy_align,
 1521: 						com->intr_enable
 1522: 						= (com->intr_enable
 1523: 						  & ~CD1400_SRER_TXRDY)
 1524: 						  | CD1400_SRER_TXMPTY);
 1525: 				}
 1526: 				if (!(com->state & CS_ODONE)) {
 1527: 					com_events += LOTS_OF_EVENTS;
 1528: 					com->state |= CS_ODONE;
 1529: 
 1530: 					/* handle at high level ASAP */
 1531: 					setsofttty();
 1532: 				}
 1533: 			}
 1534: 		}
 1535: 
 1536: 			/* terminate service context */
 1537: terminate_tx_service:
 1538: #ifdef PollMode
 1539: 			cd_outb(iobase, CD1400_TIR, cy_align,
 1540: 				save_tir
 1541: 				& ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));
 1542: #else
 1543: 			cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
 1544: #endif
 1545: 		}
 1546: 	}
 1547: 
 1548: 	/* ensure an edge for the next interrupt */
 1549: 	cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
 1550: 
 1551: 	schedsofttty();
 1552: 
 1553: 	com_unlock();
 1554: }
 1555: 
 1556: #if 0
 1557: static void
 1558: siointr1(com)
 1559: 	struct com_s	*com;
 1560: {
 1561: }
 1562: #endif
 1563: 
 1564: static int
 1565: sioioctl(dev_t dev, u_long cmd, caddr_t	data, int flag, struct thread *td)
 1566: {
 1567: 	struct com_s	*com;
 1568: 	int		error;
 1569: 	int		mynor;
 1570: 	int		s;
 1571: 	struct tty	*tp;
 1572: #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1573: 	int		oldcmd;
 1574: 	struct termios	term;
 1575: #endif
 1576: 
 1577: 	mynor = minor(dev);
 1578: 	com = com_addr(MINOR_TO_UNIT(mynor));
 1579: 	if (mynor & CONTROL_MASK) {
 1580: 		struct termios	*ct;
 1581: 
 1582: 		switch (mynor & CONTROL_MASK) {
 1583: 		case CONTROL_INIT_STATE:
 1584: 			ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
 1585: 			break;
 1586: 		case CONTROL_LOCK_STATE:
 1587: 			ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
 1588: 			break;
 1589: 		default:
 1590: 			return (ENODEV);	/* /dev/nodev */
 1591: 		}
 1592: 		switch (cmd) {
 1593: 		case TIOCSETA:
 1594: 			error = suser(td);
 1595: 			if (error != 0)
 1596: 				return (error);
 1597: 			*ct = *(struct termios *)data;
 1598: 			return (0);
 1599: 		case TIOCGETA:
 1600: 			*(struct termios *)data = *ct;
 1601: 			return (0);
 1602: 		case TIOCGETD:
 1603: 			*(int *)data = TTYDISC;
 1604: 			return (0);
 1605: 		case TIOCGWINSZ:
 1606: 			bzero(data, sizeof(struct winsize));
 1607: 			return (0);
 1608: 		default:
 1609: 			return (ENOTTY);
 1610: 		}
 1611: 	}
 1612: 	tp = com->tp;
 1613: #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
 1614: 	term = tp->t_termios;
 1615: 	oldcmd = cmd;
 1616: 	error = ttsetcompat(tp, &cmd, data, &term);
 1617: 	if (error != 0)
 1618: 		return (error);
 1619: 	if (cmd != oldcmd)
 1620: 		data = (caddr_t)&term;
 1621: #endif
 1622: 	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
 1623: 		int	cc;
 1624: 		struct termios *dt = (struct termios *)data;
 1625: 		struct termios *lt = mynor & CALLOUT_MASK
 1626: 				     ? &com->lt_out : &com->lt_in;
 1627: 
 1628: 		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
 1629: 			      | (dt->c_iflag & ~lt->c_iflag);
 1630: 		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
 1631: 			      | (dt->c_oflag & ~lt->c_oflag);
 1632: 		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
 1633: 			      | (dt->c_cflag & ~lt->c_cflag);
 1634: 		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
 1635: 			      | (dt->c_lflag & ~lt->c_lflag);
 1636: 		for (cc = 0; cc < NCCS; ++cc)
 1637: 			if (lt->c_cc[cc] != 0)
 1638: 				dt->c_cc[cc] = tp->t_cc[cc];
 1639: 		if (lt->c_ispeed != 0)
 1640: 			dt->c_ispeed = tp->t_ispeed;
 1641: 		if (lt->c_ospeed != 0)
 1642: 			dt->c_ospeed = tp->t_ospeed;
 1643: 	}
 1644: 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
 1645: 	if (error != ENOIOCTL)
 1646: 		return (error);
 1647: 	s = spltty();
 1648: 	error = ttioctl(tp, cmd, data, flag);
 1649: 	disc_optim(tp, &tp->t_termios, com);
 1650: 	if (error != ENOIOCTL) {
 1651: 		splx(s);
 1652: 		return (error);
 1653: 	}
 1654: 	switch (cmd) {
 1655: 	case TIOCSBRK:
 1656: #if 0
 1657: 		outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
 1658: #else
 1659: 		cd_etc(com, CD1400_ETC_SENDBREAK);
 1660: #endif
 1661: 		break;
 1662: 	case TIOCCBRK:
 1663: #if 0
 1664: 		outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
 1665: #else
 1666: 		cd_etc(com, CD1400_ETC_STOPBREAK);
 1667: #endif
 1668: 		break;
 1669: 	case TIOCSDTR:
 1670: 		(void)commctl(com, TIOCM_DTR, DMBIS);
 1671: 		break;
 1672: 	case TIOCCDTR:
 1673: 		(void)commctl(com, TIOCM_DTR, DMBIC);
 1674: 		break;
 1675: 	/*
 1676: 	 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
 1677: 	 * changes get undone on the next call to comparam().
 1678: 	 */
 1679: 	case TIOCMSET:
 1680: 		(void)commctl(com, *(int *)data, DMSET);
 1681: 		break;
 1682: 	case TIOCMBIS:
 1683: 		(void)commctl(com, *(int *)data, DMBIS);
 1684: 		break;
 1685: 	case TIOCMBIC:
 1686: 		(void)commctl(com, *(int *)data, DMBIC);
 1687: 		break;
 1688: 	case TIOCMGET:
 1689: 		*(int *)data = commctl(com, 0, DMGET);
 1690: 		break;
 1691: 	case TIOCMSDTRWAIT:
 1692: 		/* must be root since the wait applies to following logins */
 1693: 		error = suser(td);
 1694: 		if (error != 0) {
 1695: 			splx(s);
 1696: 			return (error);
 1697: 		}
 1698: 		com->dtr_wait = *(int *)data * hz / 100;
 1699: 		break;
 1700: 	case TIOCMGDTRWAIT:
 1701: 		*(int *)data = com->dtr_wait * 100 / hz;
 1702: 		break;
 1703: 	case TIOCTIMESTAMP:
 1704: 		com->do_timestamp = TRUE;
 1705: 		*(struct timeval *)data = com->timestamp;
 1706: 		break;
 1707: 	case TIOCDCDTIMESTAMP:
 1708: 		com->do_dcd_timestamp = TRUE;
 1709: 		*(struct timeval *)data = com->dcd_timestamp;
 1710: 		break;
 1711: 	default:
 1712: 		splx(s);
 1713: 		return (ENOTTY);
 1714: 	}
 1715: 	splx(s);
 1716: 	return (0);
 1717: }
 1718: 
 1719: static void
 1720: siopoll(void *data)
 1721: {
 1722: 	int		unit;
 1723: 
 1724: #ifdef CyDebug
 1725: 	++cy_timeouts;
 1726: #endif
 1727: 	if (com_events == 0)
 1728: 		return;
 1729: repeat:
 1730: 	for (unit = 0; unit < NSIO; ++unit) {
 1731: 		struct com_s	*com;
 1732: 		int		incc;
 1733: 		struct tty	*tp;
 1734: 
 1735: 		com = com_addr(unit);
 1736: 		if (com == NULL)
 1737: 			continue;
 1738: 		tp = com->tp;
 1739: 		if (tp == NULL) {
 1740: 			/*
 1741: 			 * XXX forget any events related to closed devices
 1742: 			 * (actually never opened devices) so that we don't
 1743: 			 * loop.
 1744: 			 */
 1745: 			disable_intr();
 1746: 			incc = com->iptr - com->ibuf;
 1747: 			com->iptr = com->ibuf;
 1748: 			if (com->state & CS_CHECKMSR) {
 1749: 				incc += LOTS_OF_EVENTS;
 1750: 				com->state &= ~CS_CHECKMSR;
 1751: 			}
 1752: 			com_events -= incc;
 1753: 			enable_intr();
 1754: 			if (incc != 0)
 1755: 				log(LOG_DEBUG,
 1756: 				    "sio%d: %d events for device with no tp\n",
 1757: 				    unit, incc);
 1758: 			continue;
 1759: 		}
 1760: 		if (com->iptr != com->ibuf) {
 1761: 			disable_intr();
 1762: 			sioinput(com);
 1763: 			enable_intr();
 1764: 		}
 1765: 		if (com->state & CS_CHECKMSR) {
 1766: 			u_char	delta_modem_status;
 1767: 
 1768: 			disable_intr();
 1769: 			delta_modem_status = com->last_modem_status
 1770: 					     ^ com->prev_modem_status;
 1771: 			com->prev_modem_status = com->last_modem_status;
 1772: 			com_events -= LOTS_OF_EVENTS;
 1773: 			com->state &= ~CS_CHECKMSR;
 1774: 			enable_intr();
 1775: 			if (delta_modem_status & MSR_DCD)
 1776: 				(*linesw[tp->t_line].l_modem)
 1777: 					(tp, com->prev_modem_status & MSR_DCD);
 1778: 		}
 1779: 		if (com->extra_state & CSE_ODONE) {
 1780: 			disable_intr();
 1781: 			com_events -= LOTS_OF_EVENTS;
 1782: 			com->extra_state &= ~CSE_ODONE;
 1783: 			enable_intr();
 1784: 			if (!(com->state & CS_BUSY)) {
 1785: 				tp->t_state &= ~TS_BUSY;
 1786: 				ttwwakeup(com->tp);
 1787: 			}
 1788: 			if (com->etc != ETC_NONE) {
 1789: 				if (com->etc == ETC_BREAK_ENDED)
 1790: 					com->etc = ETC_NONE;
 1791: 				wakeup(&com->etc);
 1792: 			}
 1793: 		}
 1794: 		if (com->state & CS_ODONE) {
 1795: 			disable_intr();
 1796: 			com_events -= LOTS_OF_EVENTS;
 1797: 			com->state &= ~CS_ODONE;
 1798: 			enable_intr();
 1799: 			(*linesw[tp->t_line].l_start)(tp);
 1800: 		}
 1801: 		if (com_events == 0)
 1802: 			break;
 1803: 	}
 1804: 	if (com_events >= LOTS_OF_EVENTS)
 1805: 		goto repeat;
 1806: }
 1807: 
 1808: static int
 1809: comparam(tp, t)
 1810: 	struct tty	*tp;
 1811: 	struct termios	*t;
 1812: {
 1813: 	int		bits;
 1814: 	int		cflag;
 1815: 	struct com_s	*com;
 1816: 	u_char		cor_change;
 1817: 	u_long		cy_clock;
 1818: 	int		idivisor;
 1819: 	int		iflag;
 1820: 	int		iprescaler;
 1821: 	int		itimeout;
 1822: 	int		odivisor;
 1823: 	int		oprescaler;
 1824: 	u_char		opt;
 1825: 	int		s;
 1826: 	int		unit;
 1827: 
 1828: 	/* do historical conversions */
 1829: 	if (t->c_ispeed == 0)
 1830: 		t->c_ispeed = t->c_ospeed;
 1831: 
 1832: 	unit = DEV_TO_UNIT(tp->t_dev);
 1833: 	com = com_addr(unit);
 1834: 
 1835: 	/* check requested parameters */
 1836: 	cy_clock = CY_CLOCK(com->gfrcr_image);
 1837: 	idivisor = comspeed(t->c_ispeed, cy_clock, &iprescaler);
 1838: 	if (idivisor < 0)
 1839: 		return (EINVAL);
 1840: 	odivisor = comspeed(t->c_ospeed, cy_clock, &oprescaler);
 1841: 	if (odivisor < 0)
 1842: 		return (EINVAL);
 1843: 
 1844: 	/* parameters are OK, convert them to the com struct and the device */
 1845: 	s = spltty();
 1846: 	if (odivisor == 0)
 1847: 		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */
 1848: 	else
 1849: 		(void)commctl(com, TIOCM_DTR, DMBIS);
 1850: 
 1851: 	/*
 1852: 	 * This returns with interrupts disabled so that we can complete
 1853: 	 * the speed change atomically.
 1854: 	 */
 1855: 	(void) siosetwater(com, t->c_ispeed);
 1856: 
 1857: 	/* XXX we don't actually change the speed atomically. */
 1858: 	enable_intr();
 1859: 
 1860: 	if (idivisor != 0) {
 1861: 		cd_setreg(com, CD1400_RBPR, idivisor);
 1862: 		cd_setreg(com, CD1400_RCOR, iprescaler);
 1863: 	}
 1864: 	if (odivisor != 0) {
 1865: 		cd_setreg(com, CD1400_TBPR, odivisor);
 1866: 		cd_setreg(com, CD1400_TCOR, oprescaler);
 1867: 	}
 1868: 
 1869: 	/*
 1870: 	 * channel control
 1871: 	 *	receiver enable
 1872: 	 *	transmitter enable (always set)
 1873: 	 */
 1874: 	cflag = t->c_cflag;
 1875: 	opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN
 1876: 	      | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
 1877: 	if (opt != com->channel_control) {
 1878: 		com->channel_control = opt;
 1879: 		cd1400_channel_cmd(com, opt);
 1880: 	}
 1881: 
 1882: #ifdef Smarts
 1883: 	/* set special chars */
 1884: 	/* XXX if one is _POSIX_VDISABLE, can't use some others */
 1885: 	if (t->c_cc[VSTOP] != _POSIX_VDISABLE)
 1886: 		cd_setreg(com, CD1400_SCHR1, t->c_cc[VSTOP]);
 1887: 	if (t->c_cc[VSTART] != _POSIX_VDISABLE)
 1888: 		cd_setreg(com, CD1400_SCHR2, t->c_cc[VSTART]);
 1889: 	if (t->c_cc[VINTR] != _POSIX_VDISABLE)
 1890: 		cd_setreg(com, CD1400_SCHR3, t->c_cc[VINTR]);
 1891: 	if (t->c_cc[VSUSP] != _POSIX_VDISABLE)
 1892: 		cd_setreg(com, CD1400_SCHR4, t->c_cc[VSUSP]);
 1893: #endif
 1894: 
 1895: 	/*
 1896: 	 * set channel option register 1 -
 1897: 	 *	parity mode
 1898: 	 *	stop bits
 1899: 	 *	char length
 1900: 	 */
 1901: 	opt = 0;
 1902: 	/* parity */
 1903: 	if (cflag & PARENB) {
 1904: 		if (cflag & PARODD)
 1905: 			opt |= CD1400_COR1_PARODD;
 1906: 		opt |= CD1400_COR1_PARNORMAL;
 1907: 	}
 1908: 	iflag = t->c_iflag;
 1909: 	if (!(iflag & INPCK))
 1910: 		opt |= CD1400_COR1_NOINPCK;
 1911: 	bits = 1 + 1;
 1912: 	/* stop bits */
 1913: 	if (cflag & CSTOPB) {
 1914: 		++bits;
 1915: 		opt |= CD1400_COR1_STOP2;
 1916: 	}
 1917: 	/* char length */
 1918: 	switch (cflag & CSIZE) {
 1919: 	case CS5:
 1920: 		bits += 5;
 1921: 		opt |= CD1400_COR1_CS5;
 1922: 		break;
 1923: 	case CS6:
 1924: 		bits += 6;
 1925: 		opt |= CD1400_COR1_CS6;
 1926: 		break;
 1927: 	case CS7:
 1928: 		bits += 7;
 1929: 		opt |= CD1400_COR1_CS7;
 1930: 		break;
 1931: 	default:
 1932: 		bits += 8;
 1933: 		opt |= CD1400_COR1_CS8;
 1934: 		break;
 1935: 	}
 1936: 	cor_change = 0;
 1937: 	if (opt != com->cor[0]) {
 1938: 		cor_change |= CD1400_CCR_COR1;
 1939: 		cd_setreg(com, CD1400_COR1, com->cor[0] = opt);
 1940: 	}
 1941: 
 1942: 	/*
 1943: 	 * Set receive time-out period, normally to max(one char time, 5 ms).
 1944: 	 */
 1945: 	if (t->c_ispeed == 0)
 1946: 		itimeout = cd_getreg(com, CD1400_RTPR);
 1947: 	else {
 1948: 		itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;
 1949: #ifdef SOFT_HOTCHAR
 1950: #define	MIN_RTP		1
 1951: #else
 1952: #define	MIN_RTP		5
 1953: #endif
 1954: 		if (itimeout < MIN_RTP)
 1955: 			itimeout = MIN_RTP;
 1956: 	}
 1957: 	if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0
 1958: 	    && t->c_cc[VTIME] * 10 > itimeout)
 1959: 		itimeout = t->c_cc[VTIME] * 10;
 1960: 	if (itimeout > 255)
 1961: 		itimeout = 255;
 1962: 	cd_setreg(com, CD1400_RTPR, itimeout);
 1963: 
 1964: 	/*
 1965: 	 * set channel option register 2 -
 1966: 	 *	flow control
 1967: 	 */
 1968: 	opt = 0;
 1969: #ifdef Smarts
 1970: 	if (iflag & IXANY)
 1971: 		opt |= CD1400_COR2_IXANY;
 1972: 	if (iflag & IXOFF)
 1973: 		opt |= CD1400_COR2_IXOFF;
 1974: #endif
 1975: #ifndef SOFT_CTS_OFLOW
 1976: 	if (cflag & CCTS_OFLOW)
 1977: 		opt |= CD1400_COR2_CCTS_OFLOW;
 1978: #endif
 1979: 	disable_intr();
 1980: 	if (opt != com->cor[1]) {
 1981: 		cor_change |= CD1400_CCR_COR2;
 1982: 		cd_setreg(com, CD1400_COR2, com->cor[1] = opt);
 1983: 	}
 1984: 	enable_intr();
 1985: 
 1986: 	/*
 1987: 	 * set channel option register 3 -
 1988: 	 *	receiver FIFO interrupt threshold
 1989: 	 *	flow control
 1990: 	 */
 1991: 	opt = RxFifoThreshold;
 1992: #ifdef Smarts
 1993: 	if (t->c_lflag & ICANON)
 1994: 		opt |= CD1400_COR3_SCD34;	/* detect INTR & SUSP chars */
 1995: 	if (iflag & IXOFF)
 1996: 		/* detect and transparently handle START and STOP chars */
 1997: 		opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12;
 1998: #endif
 1999: 	if (opt != com->cor[2]) {
 2000: 		cor_change |= CD1400_CCR_COR3;
 2001: 		cd_setreg(com, CD1400_COR3, com->cor[2] = opt);
 2002: 	}
 2003: 
 2004: 	/* notify the CD1400 if COR1-3 have changed */
 2005: 	if (cor_change)
 2006: 		cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | cor_change);
 2007: 
 2008: 	/*
 2009: 	 * set channel option register 4 -
 2010: 	 *	CR/NL processing
 2011: 	 *	break processing
 2012: 	 *	received exception processing
 2013: 	 */
 2014: 	opt = 0;
 2015: 	if (iflag & IGNCR)
 2016: 		opt |= CD1400_COR4_IGNCR;
 2017: #ifdef Smarts
 2018: 	/*
 2019: 	 * we need a new ttyinput() for this, as we don't want to
 2020: 	 * have ICRNL && INLCR being done in both layers, or to have
 2021: 	 * synchronisation problems
 2022: 	 */
 2023: 	if (iflag & ICRNL)
 2024: 		opt |= CD1400_COR4_ICRNL;
 2025: 	if (iflag & INLCR)
 2026: 		opt |= CD1400_COR4_INLCR;
 2027: #endif
 2028: 	if (iflag & IGNBRK)
 2029: 		opt |= CD1400_COR4_IGNBRK | CD1400_COR4_NOBRKINT;
 2030: 	/*
 2031: 	 * The `-ignbrk -brkint parmrk' case is not handled by the hardware,
 2032: 	 * so only tell the hardware about -brkint if -parmrk.
 2033: 	 */
 2034: 	if (!(iflag & (BRKINT | PARMRK)))
 2035: 		opt |= CD1400_COR4_NOBRKINT;
 2036: #if 0
 2037: 	/* XXX using this "intelligence" breaks reporting of overruns. */
 2038: 	if (iflag & IGNPAR)
 2039: 		opt |= CD1400_COR4_PFO_DISCARD;
 2040: 	else {
 2041: 		if (iflag & PARMRK)
 2042: 			opt |= CD1400_COR4_PFO_ESC;
 2043: 		else
 2044: 			opt |= CD1400_COR4_PFO_NUL;
 2045: 	}
 2046: #else
 2047: 	opt |= CD1400_COR4_PFO_EXCEPTION;
 2048: #endif
 2049: 	cd_setreg(com, CD1400_COR4, opt);
 2050: 
 2051: 	/*
 2052: 	 * set channel option register 5 -
 2053: 	 */
 2054: 	opt = 0;
 2055: 	if (iflag & ISTRIP)
 2056: 		opt |= CD1400_COR5_ISTRIP;
 2057: 	if (t->c_iflag & IEXTEN)
 2058: 		/* enable LNEXT (e.g. ctrl-v quoting) handling */
 2059: 		opt |= CD1400_COR5_LNEXT;
 2060: #ifdef Smarts
 2061: 	if (t->c_oflag & ONLCR)
 2062: 		opt |= CD1400_COR5_ONLCR;
 2063: 	if (t->c_oflag & OCRNL)
 2064: 		opt |= CD1400_COR5_OCRNL;
 2065: #endif
 2066: 	cd_setreg(com, CD1400_COR5, opt);
 2067: 
 2068: 	/*
 2069: 	 * We always generate modem status change interrupts for CD changes.
 2070: 	 * Among other things, this is necessary to track TS_CARR_ON for
 2071: 	 * pstat to print even when the driver doesn't care.  CD changes
 2072: 	 * should be rare so interrupts for them are not worth extra code to
 2073: 	 * avoid.  We avoid interrupts for other modem status changes (except
 2074: 	 * for CTS changes when SOFT_CTS_OFLOW is configured) since this is
 2075: 	 * simplest and best.
 2076: 	 */
 2077: 
 2078: 	/*
 2079: 	 * set modem change option register 1
 2080: 	 *	generate modem interrupts on which 1 -> 0 input transitions
 2081: 	 *	also controls auto-DTR output flow-control, which we don't use
 2082: 	 */
 2083: 	opt = CD1400_MCOR1_CDzd;
 2084: #ifdef SOFT_CTS_OFLOW
 2085: 	if (cflag & CCTS_OFLOW)
 2086: 		opt |= CD1400_MCOR1_CTSzd;
 2087: #endif
 2088: 	cd_setreg(com, CD1400_MCOR1, opt);
 2089: 
 2090: 	/*
 2091: 	 * set modem change option register 2
 2092: 	 *	generate modem interrupts on specific 0 -> 1 input transitions
 2093: 	 */
 2094: 	opt = CD1400_MCOR2_CDod;
 2095: #ifdef SOFT_CTS_OFLOW
 2096: 	if (cflag & CCTS_OFLOW)
 2097: 		opt |= CD1400_MCOR2_CTSod;
 2098: #endif
 2099: 	cd_setreg(com, CD1400_MCOR2, opt);
 2100: 
 2101: 	/*
 2102: 	 * XXX should have done this long ago, but there is too much state
 2103: 	 * to change all atomically.
 2104: 	 */
 2105: 	disable_intr();
 2106: 
 2107: 	com->state &= ~CS_TTGO;
 2108: 	if (!(tp->t_state & TS_TTSTOP))
 2109: 		com->state |= CS_TTGO;
 2110: 	if (cflag & CRTS_IFLOW) {
 2111: 		com->state |= CS_RTS_IFLOW;
 2112: 		/*
 2113: 		 * If CS_RTS_IFLOW just changed from off to on, the change
 2114: 		 * needs to be propagated to MCR_RTS.  This isn't urgent,
 2115: 		 * so do it later by calling comstart() instead of repeating
 2116: 		 * a lot of code from comstart() here.
 2117: 		 */
 2118: 	} else if (com->state & CS_RTS_IFLOW) {
 2119: 		com->state &= ~CS_RTS_IFLOW;
 2120: 		/*
 2121: 		 * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
 2122: 		 * on here, since comstart() won't do it later.
 2123: 		 */
 2124: #if 0
 2125: 		outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
 2126: #else
 2127: 		cd_setreg(com, com->mcr_rts_reg,
 2128: 			  com->mcr_image |= com->mcr_rts);
 2129: #endif
 2130: 	}
 2131: 
 2132: 	/*
 2133: 	 * Set up state to handle output flow control.
 2134: 	 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
 2135: 	 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
 2136: 	 */
 2137: 	com->state |= CS_ODEVREADY;
 2138: #ifdef SOFT_CTS_OFLOW
 2139: 	com->state &= ~CS_CTS_OFLOW;
 2140: 	if (cflag & CCTS_OFLOW) {
 2141: 		com->state |= CS_CTS_OFLOW;
 2142: 		if (!(com->last_modem_status & MSR_CTS))
 2143: 			com->state &= ~CS_ODEVREADY;
 2144: 	}
 2145: #endif
 2146: 	/* XXX shouldn't call functions while intrs are disabled. */
 2147: 	disc_optim(tp, t, com);
 2148: #if 0
 2149: 	/*
 2150: 	 * Recover from fiddling with CS_TTGO.  We used to call siointr1()
 2151: 	 * unconditionally, but that defeated the careful discarding of
 2152: 	 * stale input in sioopen().
 2153: 	 */
 2154: 	if (com->state >= (CS_BUSY | CS_TTGO))
 2155: 		siointr1(com);
 2156: #endif
 2157: 	if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
 2158: 		if (!(com->intr_enable & CD1400_SRER_TXRDY))
 2159: 			cd_setreg(com, CD1400_SRER,
 2160: 				  com->intr_enable
 2161: 				  = (com->intr_enable & ~CD1400_SRER_TXMPTY)
 2162: 				    | CD1400_SRER_TXRDY);
 2163: 	} else {
 2164: 		if (com->intr_enable & CD1400_SRER_TXRDY)
 2165: 			cd_setreg(com, CD1400_SRER,
 2166: 				  com->intr_enable
 2167: 				  = (com->intr_enable & ~CD1400_SRER_TXRDY)
 2168: 				    | CD1400_SRER_TXMPTY);
 2169: 	}
 2170: 
 2171: 	enable_intr();
 2172: 	splx(s);
 2173: 	comstart(tp);
 2174: 	if (com->ibufold != NULL) {
 2175: 		free(com->ibufold, M_DEVBUF);
 2176: 		com->ibufold = NULL;
 2177: 	}
 2178: 	return (0);
 2179: }
 2180: 
 2181: static int
 2182: siosetwater(com, speed)
 2183: 	struct com_s	*com;
 2184: 	speed_t		speed;
 2185: {
 2186: 	int		cp4ticks;
 2187: 	u_char		*ibuf;
 2188: 	int		ibufsize;
 2189: 	struct tty	*tp;
 2190: 
 2191: 	/*
 2192: 	 * Make the buffer size large enough to handle a softtty interrupt
 2193: 	 * latency of about 2 ticks without loss of throughput or data
 2194: 	 * (about 3 ticks if input flow control is not used or not honoured,
 2195: 	 * but a bit less for CS5-CS7 modes).
 2196: 	 */
 2197: 	cp4ticks = speed / 10 / hz * 4;
 2198: 	for (ibufsize = 128; ibufsize < cp4ticks;)
 2199: 		ibufsize <<= 1;
 2200: 	if (ibufsize == com->ibufsize) {
 2201: 		disable_intr();
 2202: 		return (0);
 2203: 	}
 2204: 
 2205: 	/*
 2206: 	 * Allocate input buffer.  The extra factor of 2 in the size is
 2207: 	 * to allow for an error byte for each input byte.
 2208: 	 */
 2209: 	ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT);
 2210: 	if (ibuf == NULL) {
 2211: 		disable_intr();
 2212: 		return (ENOMEM);
 2213: 	}
 2214: 
 2215: 	/* Initialize non-critical variables. */
 2216: 	com->ibufold = com->ibuf;
 2217: 	com->ibufsize = ibufsize;
 2218: 	tp = com->tp;
 2219: 	if (tp != NULL) {
 2220: 		tp->t_ififosize = 2 * ibufsize;
 2221: 		tp->t_ispeedwat = (speed_t)-1;
 2222: 		tp->t_ospeedwat = (speed_t)-1;
 2223: 	}
 2224: 
 2225: 	/*
 2226: 	 * Read current input buffer, if any.  Continue with interrupts
 2227: 	 * disabled.
 2228: 	 */
 2229: 	disable_intr();
 2230: 	if (com->iptr != com->ibuf)
 2231: 		sioinput(com);
 2232: 
 2233: 	/*-
 2234: 	 * Initialize critical variables, including input buffer watermarks.
 2235: 	 * The external device is asked to stop sending when the buffer
 2236: 	 * exactly reaches high water, or when the high level requests it.
 2237: 	 * The high level is notified immediately (rather than at a later
 2238: 	 * clock tick) when this watermark is reached.
 2239: 	 * The buffer size is chosen so the watermark should almost never
 2240: 	 * be reached.
 2241: 	 * The low watermark is invisibly 0 since the buffer is always
 2242: 	 * emptied all at once.
 2243: 	 */
 2244: 	com->iptr = com->ibuf = ibuf;
 2245: 	com->ibufend = ibuf + ibufsize;
 2246: 	com->ierroff = ibufsize;
 2247: 	com->ihighwater = ibuf + 3 * ibufsize / 4;
 2248: 	return (0);
 2249: }
 2250: 
 2251: static void
 2252: comstart(tp)
 2253: 	struct tty	*tp;
 2254: {
 2255: 	struct com_s	*com;
 2256: 	int		s;
 2257: #ifdef CyDebug
 2258: 	bool_t		started;
 2259: #endif
 2260: 	int		unit;
 2261: 
 2262: 	unit = DEV_TO_UNIT(tp->t_dev);
 2263: 	com = com_addr(unit);
 2264: 	s = spltty();
 2265: 
 2266: #ifdef CyDebug
 2267: 	++com->start_count;
 2268: 	started = FALSE;
 2269: #endif
 2270: 
 2271: 	disable_intr();
 2272: 	if (tp->t_state & TS_TTSTOP) {
 2273: 		com->state &= ~CS_TTGO;
 2274: 		if (com->intr_enable & CD1400_SRER_TXRDY)
 2275: 			cd_setreg(com, CD1400_SRER,
 2276: 				  com->intr_enable
 2277: 				  = (com->intr_enable & ~CD1400_SRER_TXRDY)
 2278: 				    | CD1400_SRER_TXMPTY);
 2279: 	} else {
 2280: 		com->state |= CS_TTGO;
 2281: 		if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
 2282: 		    && !(com->intr_enable & CD1400_SRER_TXRDY))
 2283: 			cd_setreg(com, CD1400_SRER,
 2284: 				  com->intr_enable
 2285: 				  = (com->intr_enable & ~CD1400_SRER_TXMPTY)
 2286: 				    | CD1400_SRER_TXRDY);
 2287: 	}
 2288: 	if (tp->t_state & TS_TBLOCK) {
 2289: 		if (com->mcr_image & com->mcr_rts && com->state & CS_RTS_IFLOW)
 2290: #if 0
 2291: 			outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
 2292: #else
 2293: 			cd_setreg(com, com->mcr_rts_reg,
 2294: 				  com->mcr_image &= ~com->mcr_rts);
 2295: #endif
 2296: 	} else {
 2297: 		if (!(com->mcr_image & com->mcr_rts)
 2298: 		    && com->iptr < com->ihighwater
 2299: 		    && com->state & CS_RTS_IFLOW)
 2300: #if 0
 2301: 			outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
 2302: #else
 2303: 			cd_setreg(com, com->mcr_rts_reg,
 2304: 				  com->mcr_image |= com->mcr_rts);
 2305: #endif
 2306: 	}
 2307: 	enable_intr();
 2308: 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
 2309: 		ttwwakeup(tp);
 2310: 		splx(s);
 2311: 		return;
 2312: 	}
 2313: 	if (tp->t_outq.c_cc != 0) {
 2314: 		struct lbq	*qp;
 2315: 		struct lbq	*next;
 2316: 
 2317: 		if (!com->obufs[0].l_queued) {
 2318: #ifdef CyDebug
 2319: 			started = TRUE;
 2320: #endif
 2321: 			com->obufs[0].l_tail
 2322: 			    = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
 2323: 						  sizeof com->obuf1);
 2324: 			com->obufs[0].l_next = NULL;
 2325: 			com->obufs[0].l_queued = TRUE;
 2326: 			disable_intr();
 2327: 			if (com->state & CS_BUSY) {
 2328: 				qp = com->obufq.l_next;
 2329: 				while ((next = qp->l_next) != NULL)
 2330: 					qp = next;
 2331: 				qp->l_next = &com->obufs[0];
 2332: 			} else {
 2333: 				com->obufq.l_head = com->obufs[0].l_head;
 2334: 				com->obufq.l_tail = com->obufs[0].l_tail;
 2335: 				com->obufq.l_next = &com->obufs[0];
 2336: 				com->state |= CS_BUSY;
 2337: 				if (com->state >= (CS_BUSY | CS_TTGO
 2338: 						   | CS_ODEVREADY))
 2339: 					cd_setreg(com, CD1400_SRER,
 2340: 						  com->intr_enable
 2341: 						  = (com->intr_enable
 2342: 						    & ~CD1400_SRER_TXMPTY)
 2343: 						    | CD1400_SRER_TXRDY);
 2344: 			}
 2345: 			enable_intr();
 2346: 		}
 2347: 		if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
 2348: #ifdef CyDebug
 2349: 			started = TRUE;
 2350: #endif
 2351: 			com->obufs[1].l_tail
 2352: 			    = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
 2353: 						  sizeof com->obuf2);
 2354: 			com->obufs[1].l_next = NULL;
 2355: 			com->obufs[1].l_queued = TRUE;
 2356: 			disable_intr();
 2357: 			if (com->state & CS_BUSY) {
 2358: 				qp = com->obufq.l_next;
 2359: 				while ((next = qp->l_next) != NULL)
 2360: 					qp = next;
 2361: 				qp->l_next = &com->obufs[1];
 2362: 			} else {
 2363: 				com->obufq.l_head = com->obufs[1].l_head;
 2364: 				com->obufq.l_tail = com->obufs[1].l_tail;
 2365: 				com->obufq.l_next = &com->obufs[1];
 2366: 				com->state |= CS_BUSY;
 2367: 				if (com->state >= (CS_BUSY | CS_TTGO
 2368: 						   | CS_ODEVREADY))
 2369: 					cd_setreg(com, CD1400_SRER,
 2370: 						  com->intr_enable
 2371: 						  = (com->intr_enable
 2372: 						    & ~CD1400_SRER_TXMPTY)
 2373: 						    | CD1400_SRER_TXRDY);
 2374: 			}
 2375: 			enable_intr();
 2376: 		}
 2377: 		tp->t_state |= TS_BUSY;
 2378: 	}
 2379: #ifdef CyDebug
 2380: 	if (started)
 2381: 		++com->start_real;
 2382: #endif
 2383: #if 0
 2384: 	disable_intr();
 2385: 	if (com->state >= (CS_BUSY | CS_TTGO))
 2386: 		siointr1(com);	/* fake interrupt to start output */
 2387: 	enable_intr();
 2388: #endif
 2389: 	ttwwakeup(tp);
 2390: 	splx(s);
 2391: }
 2392: 
 2393: static void
 2394: comstop(tp, rw)
 2395: 	struct tty	*tp;
 2396: 	int		rw;
 2397: {
 2398: 	struct com_s	*com;
 2399: 	bool_t		wakeup_etc;
 2400: 
 2401: 	com = com_addr(DEV_TO_UNIT(tp->t_dev));
 2402: 	wakeup_etc = FALSE;
 2403: 	disable_intr();
 2404: 	if (rw & FWRITE) {
 2405: 		com->obufs[0].l_queued = FALSE;
 2406: 		com->obufs[1].l_queued = FALSE;
 2407: 		if (com->extra_state & CSE_ODONE) {
 2408: 			com_events -= LOTS_OF_EVENTS;
 2409: 			com->extra_state &= ~CSE_ODONE;
 2410: 			if (com->etc != ETC_NONE) {
 2411: 				if (com->etc == ETC_BREAK_ENDED)
 2412: 					com->etc = ETC_NONE;
 2413: 				wakeup_etc = TRUE;
 2414: 			}
 2415: 		}
 2416: 		com->tp->t_state &= ~TS_BUSY;
 2417: 		if (com->state & CS_ODONE)
 2418: 			com_events -= LOTS_OF_EVENTS;
 2419: 		com->state &= ~(CS_ODONE | CS_BUSY);
 2420: 	}
 2421: 	if (rw & FREAD) {
 2422: 		/* XXX no way to reset only input fifo. */
 2423: 		com_events -= (com->iptr - com->ibuf);
 2424: 		com->iptr = com->ibuf;
 2425: 	}
 2426: 	enable_intr();
 2427: 	if (wakeup_etc)
 2428: 		wakeup(&com->etc);
 2429: 	if (rw & FWRITE && com->etc == ETC_NONE)
 2430: 		cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);
 2431: 	comstart(tp);
 2432: }
 2433: 
 2434: static int
 2435: commctl(com, bits, how)
 2436: 	struct com_s	*com;
 2437: 	int		bits;
 2438: 	int		how;
 2439: {
 2440: 	int	mcr;
 2441: 	int	msr;
 2442: 
 2443: 	if (how == DMGET) {
 2444: 		if (com->channel_control & CD1400_CCR_RCVEN)
 2445: 			bits |= TIOCM_LE;
 2446: 		mcr = com->mcr_image;
 2447: 		if (mcr & com->mcr_dtr)
 2448: 			bits |= TIOCM_DTR;
 2449: 		if (mcr & com->mcr_rts)
 2450: 			/* XXX wired on for Cyclom-8Ys */
 2451: 			bits |= TIOCM_RTS;
 2452: 
 2453: 		/*
 2454: 		 * We must read the modem status from the hardware because
 2455: 		 * we don't generate modem status change interrupts for all
 2456: 		 * changes, so com->prev_modem_status is not guaranteed to
 2457: 		 * be up to date.  This is safe, unlike for sio, because
 2458: 		 * reading the status register doesn't clear pending modem
 2459: 		 * status change interrupts.
 2460: 		 */
 2461: 		msr = cd_getreg(com, CD1400_MSVR2);
 2462: 
 2463: 		if (msr & MSR_CTS)
 2464: 			bits |= TIOCM_CTS;
 2465: 		if (msr & MSR_DCD)
 2466: 			bits |= TIOCM_CD;
 2467: 		if (msr & MSR_DSR)
 2468: 			bits |= TIOCM_DSR;
 2469: 		if (msr & MSR_RI)
 2470: 			/* XXX not connected except for Cyclom-16Y? */
 2471: 			bits |= TIOCM_RI;
 2472: 		return (bits);
 2473: 	}
 2474: 	mcr = 0;
 2475: 	if (bits & TIOCM_DTR)
 2476: 		mcr |= com->mcr_dtr;
 2477: 	if (bits & TIOCM_RTS)
 2478: 		mcr |= com->mcr_rts;
 2479: 	disable_intr();
 2480: 	switch (how) {
 2481: 	case DMSET:
 2482: 		com->mcr_image = mcr;
 2483: 		cd_setreg(com, CD1400_MSVR1, mcr);
 2484: 		cd_setreg(com, CD1400_MSVR2, mcr);
 2485: 		break;
 2486: 	case DMBIS:
 2487: 		com->mcr_image = mcr = com->mcr_image | mcr;
 2488: 		cd_setreg(com, CD1400_MSVR1, mcr);
 2489: 		cd_setreg(com, CD1400_MSVR2, mcr);
 2490: 		break;
 2491: 	case DMBIC:
 2492: 		com->mcr_image = mcr = com->mcr_image & ~mcr;
 2493: 		cd_setreg(com, CD1400_MSVR1, mcr);
 2494: 		cd_setreg(com, CD1400_MSVR2, mcr);
 2495: 		break;
 2496: 	}
 2497: 	enable_intr();
 2498: 	return (0);
 2499: }
 2500: 
 2501: static void
 2502: siosettimeout()
 2503: {
 2504: 	struct com_s	*com;
 2505: 	bool_t		someopen;
 2506: 	int		unit;
 2507: 
 2508: 	/*
 2509: 	 * Set our timeout period to 1 second if no polled devices are open.
 2510: 	 * Otherwise set it to max(1/200, 1/hz).
 2511: 	 * Enable timeouts iff some device is open.
 2512: 	 */
 2513: 	untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
 2514: 	sio_timeout = hz;
 2515: 	someopen = FALSE;
 2516: 	for (unit = 0; unit < NSIO; ++unit) {
 2517: 		com = com_addr(unit);
 2518: 		if (com != NULL && com->tp != NULL
 2519: 		    && com->tp->t_state & TS_ISOPEN) {
 2520: 			someopen = TRUE;
 2521: #if 0
 2522: 			if (com->poll || com->poll_output) {
 2523: 				sio_timeout = hz > 200 ? hz / 200 : 1;
 2524: 				break;
 2525: 			}
 2526: #endif
 2527: 		}
 2528: 	}
 2529: 	if (someopen) {
 2530: 		sio_timeouts_until_log = hz / sio_timeout;
 2531: 		sio_timeout_handle = timeout(comwakeup, (void *)NULL,
 2532: 					     sio_timeout);
 2533: 	} else {
 2534: 		/* Flush error messages, if any. */
 2535: 		sio_timeouts_until_log = 1;
 2536: 		comwakeup((void *)NULL);
 2537: 		untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
 2538: 	}
 2539: }
 2540: 
 2541: static void
 2542: comwakeup(chan)
 2543: 	void	*chan;
 2544: {
 2545: 	struct com_s	*com;
 2546: 	int		unit;
 2547: 
 2548: 	sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
 2549: 
 2550: #if 0
 2551: 	/*
 2552: 	 * Recover from lost output interrupts.
 2553: 	 * Poll any lines that don't use interrupts.
 2554: 	 */
 2555: 	for (unit = 0; unit < NSIO; ++unit) {
 2556: 		com = com_addr(unit);
 2557: 		if (com != NULL
 2558: 		    && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
 2559: 			disable_intr();
 2560: 			siointr1(com);
 2561: 			enable_intr();
 2562: 		}
 2563: 	}
 2564: #endif
 2565: 
 2566: 	/*
 2567: 	 * Check for and log errors, but not too often.
 2568: 	 */
 2569: 	if (--sio_timeouts_until_log > 0)
 2570: 		return;
 2571: 	sio_timeouts_until_log = hz / sio_timeout;
 2572: 	for (unit = 0; unit < NSIO; ++unit) {
 2573: 		int	errnum;
 2574: 
 2575: 		com = com_addr(unit);
 2576: 		if (com == NULL)
 2577: 			continue;
 2578: 		for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
 2579: 			u_int	delta;
 2580: 			u_long	total;
 2581: 
 2582: 			disable_intr();
 2583: 			delta = com->delta_error_counts[errnum];
 2584: 			com->delta_error_counts[errnum] = 0;
 2585: 			enable_intr();
 2586: 			if (delta == 0)
 2587: 				continue;
 2588: 			total = com->error_counts[errnum] += delta;
 2589: 			log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n",
 2590: 			    unit, delta, error_desc[errnum],
 2591: 			    delta == 1 ? "" : "s", total);
 2592: 		}
 2593: 	}
 2594: }
 2595: 
 2596: static void
 2597: disc_optim(tp, t, com)
 2598: 	struct tty	*tp;
 2599: 	struct termios	*t;
 2600: 	struct com_s	*com;
 2601: {
 2602: #ifndef SOFT_HOTCHAR
 2603: 	u_char	opt;
 2604: #endif
 2605: 
 2606: 	/*
 2607: 	 * XXX can skip a lot more cases if Smarts.  Maybe
 2608: 	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
 2609: 	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
 2610: 	 */
 2611: 	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
 2612: 	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
 2613: 	    && (!(t->c_iflag & PARMRK)
 2614: 		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
 2615: 	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
 2616: 	    && linesw[tp->t_line].l_rint == ttyinput)
 2617: 		tp->t_state |= TS_CAN_BYPASS_L_RINT;
 2618: 	else
 2619: 		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
 2620: 	com->hotchar = linesw[tp->t_line].l_hotchar;
 2621: #ifndef SOFT_HOTCHAR
 2622: 	opt = com->cor[2] & ~CD1400_COR3_SCD34;
 2623: 	if (com->hotchar != 0) {
 2624: 		cd_setreg(com, CD1400_SCHR3, com->hotchar);
 2625: 		cd_setreg(com, CD1400_SCHR4, com->hotchar);
 2626: 		opt |= CD1400_COR3_SCD34;
 2627: 	}
 2628: 	if (opt != com->cor[2]) {
 2629: 		cd_setreg(com, CD1400_COR3, com->cor[2] = opt);
 2630: 		cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3);
 2631: 	}
 2632: #endif
 2633: }
 2634: 
 2635: #ifdef Smarts
 2636: /* standard line discipline input routine */
 2637: int
 2638: cyinput(c, tp)
 2639: 	int		c;
 2640: 	struct tty	*tp;
 2641: {
 2642: 	/* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK
 2643: 	 * bits, as they are done by the CD1400.  Hardly worth the effort,
 2644: 	 * given that high-throughput sessions are raw anyhow.
 2645: 	 */
 2646: }
 2647: #endif /* Smarts */
 2648: 
 2649: static int
 2650: comspeed(speed, cy_clock, prescaler_io)
 2651: 	speed_t	speed;
 2652: 	u_long	cy_clock;
 2653: 	int	*prescaler_io;
 2654: {
 2655: 	int	actual;
 2656: 	int	error;
 2657: 	int	divider;
 2658: 	int	prescaler;
 2659: 	int	prescaler_unit;
 2660: 
 2661: 	if (speed == 0)
 2662: 		return (0);
 2663: 	if (speed < 0 || speed > 150000)
 2664: 		return (-1);
 2665: 
 2666: 	/* determine which prescaler to use */
 2667: 	for (prescaler_unit = 4, prescaler = 2048; prescaler_unit;
 2668: 		prescaler_unit--, prescaler >>= 2) {
 2669: 		if (cy_clock / prescaler / speed > 63)
 2670: 			break;
 2671: 	}
 2672: 
 2673: 	divider = (cy_clock / prescaler * 2 / speed + 1) / 2; /* round off */
 2674: 	if (divider > 255)
 2675: 		divider = 255;
 2676: 	actual = cy_clock/prescaler/divider;
 2677: 
 2678: 	/* 10 times error in percent: */
 2679: 	error = ((actual - (long)speed) * 2000 / (long)speed + 1) / 2;
 2680: 
 2681: 	/* 3.0% max error tolerance */
 2682: 	if (error < -30 || error > 30)
 2683: 		return (-1);
 2684: 
 2685: #if 0
 2686: 	printf("prescaler = %d (%d)\n", prescaler, prescaler_unit);
 2687: 	printf("divider = %d (%x)\n", divider, divider);
 2688: 	printf("actual = %d\n", actual);
 2689: 	printf("error = %d\n", error);
 2690: #endif
 2691: 
 2692: 	*prescaler_io = prescaler_unit;
 2693: 	return (divider);
 2694: }
 2695: 
 2696: static void
 2697: cd1400_channel_cmd(com, cmd)
 2698: 	struct com_s	*com;
 2699: 	int		cmd;
 2700: {
 2701: 	cd1400_channel_cmd_wait(com);
 2702: 	cd_setreg(com, CD1400_CCR, cmd);
 2703: 	cd1400_channel_cmd_wait(com);
 2704: }
 2705: 
 2706: static void
 2707: cd1400_channel_cmd_wait(com)
 2708: 	struct com_s	*com;
 2709: {
 2710: 	struct timeval	start;
 2711: 	struct timeval	tv;
 2712: 	long		usec;
 2713: 
 2714: 	if (cd_getreg(com, CD1400_CCR) == 0)
 2715: 		return;
 2716: 	microtime(&start);
 2717: 	for (;;) {
 2718: 		if (cd_getreg(com, CD1400_CCR) == 0)
 2719: 			return;
 2720: 		microtime(&tv);
 2721: 		usec = 1000000 * (tv.tv_sec - start.tv_sec) +
 2722: 		    tv.tv_usec - start.tv_usec;
 2723: 		if (usec >= 5000) {
 2724: 			log(LOG_ERR,
 2725: 			    "cy%d: channel command timeout (%ld usec)\n",
 2726: 			    com->unit, usec);
 2727: 			return;
 2728: 		}
 2729: 	}
 2730: }
 2731: 
 2732: static void
 2733: cd_etc(com, etc)
 2734: 	struct com_s	*com;
 2735: 	int		etc;
 2736: {
 2737: 	/*
 2738: 	 * We can't change the hardware's ETC state while there are any
 2739: 	 * characters in the tx fifo, since those characters would be
 2740: 	 * interpreted as commands!  Unputting characters from the fifo
 2741: 	 * is difficult, so we wait up to 12 character times for the fifo
 2742: 	 * to drain.  The command will be delayed for up to 2 character
 2743: 	 * times for the tx to become empty.  Unputting characters from
 2744: 	 * the tx holding and shift registers is impossible, so we wait
 2745: 	 * for the tx to become empty so that the command is sure to be
 2746: 	 * executed soon after we issue it.
 2747: 	 */
 2748: 	disable_intr();
 2749: 	if (com->etc == etc) {
 2750: 		enable_intr();
 2751: 		goto wait;
 2752: 	}
 2753: 	if ((etc == CD1400_ETC_SENDBREAK
 2754: 	    && (com->etc == ETC_BREAK_STARTING
 2755: 		|| com->etc == ETC_BREAK_STARTED))
 2756: 	    || (etc == CD1400_ETC_STOPBREAK
 2757: 	       && (com->etc == ETC_BREAK_ENDING || com->etc == ETC_BREAK_ENDED
 2758: 		   || com->etc == ETC_NONE))) {
 2759: 		enable_intr();
 2760: 		return;
 2761: 	}
 2762: 	com->etc = etc;
 2763: 	cd_setreg(com, CD1400_SRER,
 2764: 		  com->intr_enable
 2765: 		  = (com->intr_enable & ~CD1400_SRER_TXRDY) | CD1400_SRER_TXMPTY);
 2766: 	enable_intr();
 2767: wait:
 2768: 	while (com->etc == etc
 2769: 	       && tsleep(&com->etc, PCATCH, "cyetc", 0) == 0)
 2770: 		continue;
 2771: }
 2772: 
 2773: static int
 2774: cd_getreg(com, reg)
 2775: 	struct com_s	*com;
 2776: 	int		reg;
 2777: {
 2778: 	struct com_s	*basecom;
 2779: 	u_char	car;
 2780: 	int	cy_align;
 2781: 	u_long	ef;
 2782: 	cy_addr	iobase;
 2783: 	int	val;
 2784: 
 2785: 	basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
 2786: 	car = com->unit & CD1400_CAR_CHAN;
 2787: 	cy_align = com->cy_align;
 2788: 	iobase = com->iobase;
 2789: 	ef = read_eflags();
 2790: 	if (ef & PSL_I)
 2791: 		disable_intr();
 2792: 	if (basecom->car != car)
 2793: 		cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
 2794: 	val = cd_inb(iobase, reg, cy_align);
 2795: 	if (ef & PSL_I)
 2796: 		enable_intr();
 2797: 	return (val);
 2798: }
 2799: 
 2800: static void
 2801: cd_setreg(com, reg, val)
 2802: 	struct com_s	*com;
 2803: 	int		reg;
 2804: 	int		val;
 2805: {
 2806: 	struct com_s	*basecom;
 2807: 	u_char	car;
 2808: 	int	cy_align;
 2809: 	u_long	ef;
 2810: 	cy_addr	iobase;
 2811: 
 2812: 	basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
 2813: 	car = com->unit & CD1400_CAR_CHAN;
 2814: 	cy_align = com->cy_align;
 2815: 	iobase = com->iobase;
 2816: 	ef = read_eflags();
 2817: 	if (ef & PSL_I)
 2818: 		disable_intr();
 2819: 	if (basecom->car != car)
 2820: 		cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
 2821: 	cd_outb(iobase, reg, cy_align, val);
 2822: 	if (ef & PSL_I)
 2823: 		enable_intr();
 2824: }
 2825: 
 2826: #ifdef CyDebug
 2827: /* useful in ddb */
 2828: void
 2829: cystatus(unit)
 2830: 	int	unit;
 2831: {
 2832: 	struct com_s	*com;
 2833: 	cy_addr		iobase;
 2834: 	u_int		ocount;
 2835: 	struct tty	*tp;
 2836: 
 2837: 	com = com_addr(unit);
 2838: 	printf("info for channel %d\n", unit);
 2839: 	printf("------------------\n");
 2840: 	printf("total cyclom service probes:\t%d\n", cy_svrr_probes);
 2841: 	printf("calls to upper layer:\t\t%d\n", cy_timeouts);
 2842: 	if (com == NULL)
 2843: 		return;
 2844: 	iobase = com->iobase;
 2845: 	printf("\n");
 2846: 	printf("cd1400 base address:\\tt%p\n", iobase);
 2847: 	printf("saved channel_control:\t\t0x%02x\n", com->channel_control);
 2848: 	printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n",
 2849: 	       com->cor[0], com->cor[1], com->cor[2]);
 2850: 	printf("service request enable reg:\t0x%02x (0x%02x cached)\n",
 2851: 	       cd_getreg(com, CD1400_SRER), com->intr_enable);
 2852: 	printf("service request register:\t0x%02x\n",
 2853: 	       cd_inb(iobase, CD1400_SVRR, com->cy_align));
 2854: 	printf("modem status:\t\t\t0x%02x (0x%02x cached)\n",
 2855: 	       cd_getreg(com, CD1400_MSVR2), com->prev_modem_status);
 2856: 	printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n",
 2857: 	       cd_inb(iobase, CD1400_RIR, com->cy_align),
 2858: 	       cd_inb(iobase, CD1400_TIR, com->cy_align),
 2859: 	       cd_inb(iobase, CD1400_MIR, com->cy_align));
 2860: 	printf("\n");
 2861: 	printf("com state:\t\t\t0x%02x\n", com->state);
 2862: 	printf("calls to comstart():\t\t%d (%d useful)\n",
 2863: 	       com->start_count, com->start_real);
 2864: 	printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf);
 2865: 	ocount = 0;
 2866: 	if (com->obufs[0].l_queued)
 2867: 		ocount += com->obufs[0].l_tail - com->obufs[0].l_head;
 2868: 	if (com->obufs[1].l_queued)
 2869: 		ocount += com->obufs[1].l_tail - com->obufs[1].l_head;
 2870: 	printf("tx buffer chars:\t\t%u\n", ocount);
 2871: 	printf("received chars:\t\t\t%d\n", com->bytes_in);
 2872: 	printf("received exceptions:\t\t%d\n", com->recv_exception);
 2873: 	printf("modem signal deltas:\t\t%d\n", com->mdm);
 2874: 	printf("transmitted chars:\t\t%d\n", com->bytes_out);
 2875: 	printf("\n");
 2876: 	tp = com->tp;
 2877: 	if (tp != NULL) {
 2878: 		printf("tty state:\t\t\t0x%08x\n", tp->t_state);
 2879: 		printf(
 2880: 		"upper layer queue lengths:\t%d raw, %d canon, %d output\n",
 2881: 		       tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc);
 2882: 	} else
 2883: 		printf("tty state:\t\t\tclosed\n");
 2884: }
 2885: #endif /* CyDebug */