Home | History | Annotate | Download | only in io
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  1815   rameshc  * Common Development and Distribution License (the "License").
      6  1815   rameshc  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21     0    stevel /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
     22     0    stevel /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
     23     0    stevel /*	  All Rights Reserved					*/
     24     0    stevel 
     25     0    stevel /*
     26  9957        An  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     27     0    stevel  * Use is subject to license terms.
     28     0    stevel  */
     29     0    stevel 
     30     0    stevel 
     31     0    stevel /*
     32  2877   anovick  *	Serial I/O driver for 82510/8250/16450/16550AF/16C554D chips.
     33     0    stevel  *	Modified as sparc keyboard/mouse driver.
     34     0    stevel  */
     35     0    stevel #define	SU_REGISTER_FILE_NO 0
     36     0    stevel #define	SU_REGOFFSET 0
     37     0    stevel #define	SU_REGISTER_LEN 8
     38     0    stevel 
     39     0    stevel #include <sys/param.h>
     40     0    stevel #include <sys/types.h>
     41     0    stevel #include <sys/signal.h>
     42     0    stevel #include <sys/stream.h>
     43     0    stevel #include <sys/termio.h>
     44     0    stevel #include <sys/errno.h>
     45     0    stevel #include <sys/file.h>
     46     0    stevel #include <sys/cmn_err.h>
     47     0    stevel #include <sys/stropts.h>
     48     0    stevel #include <sys/strsubr.h>
     49     0    stevel #include <sys/strsun.h>
     50     0    stevel #include <sys/strtty.h>
     51     0    stevel #include <sys/debug.h>
     52     0    stevel #include <sys/kbio.h>
     53     0    stevel #include <sys/cred.h>
     54     0    stevel #include <sys/modctl.h>
     55     0    stevel #include <sys/stat.h>
     56     0    stevel #include <sys/consdev.h>
     57     0    stevel #include <sys/mkdev.h>
     58     0    stevel #include <sys/kmem.h>
     59     0    stevel #include <sys/cred.h>
     60     0    stevel #ifdef DEBUG
     61     0    stevel #include <sys/promif.h>
     62     0    stevel #endif
     63     0    stevel #include <sys/ddi.h>
     64     0    stevel #include <sys/sunddi.h>
     65     0    stevel #include <sys/sudev.h>
     66     0    stevel #include <sys/note.h>
     67     0    stevel #include <sys/timex.h>
     68     0    stevel #include <sys/policy.h>
     69     0    stevel 
     70     0    stevel #define	async_stopc	async_ttycommon.t_stopc
     71     0    stevel #define	async_startc	async_ttycommon.t_startc
     72     0    stevel 
     73     0    stevel #define	ASY_INIT	1
     74     0    stevel #define	ASY_NOINIT	0
     75     0    stevel 
     76     0    stevel #ifdef DEBUG
     77     0    stevel #define	ASY_DEBUG_INIT	0x001
     78     0    stevel #define	ASY_DEBUG_INPUT	0x002
     79     0    stevel #define	ASY_DEBUG_EOT	0x004
     80     0    stevel #define	ASY_DEBUG_CLOSE	0x008
     81     0    stevel #define	ASY_DEBUG_HFLOW	0x010
     82     0    stevel #define	ASY_DEBUG_PROCS	0x020
     83     0    stevel #define	ASY_DEBUG_STATE	0x040
     84     0    stevel #define	ASY_DEBUG_INTR	0x080
     85     0    stevel static	int asydebug = 0;
     86     0    stevel #endif
     87     0    stevel static	int su_log = 0;
     88     0    stevel 
     89     0    stevel int su_drain_check = 15000000;		/* tunable: exit drain check time */
     90     0    stevel 
     91     0    stevel static	struct ppsclockev asy_ppsev;
     92     0    stevel 
     93     0    stevel static	int max_asy_instance = -1;
     94     0    stevel static	void	*su_asycom;	/* soft state asycom pointer */
     95     0    stevel static	void	*su_asyncline;	/* soft state asyncline pointer */
     96     0    stevel static	boolean_t abort_charseq_recognize(uchar_t ch);
     97     0    stevel 
     98     0    stevel static	uint_t	asysoftintr(caddr_t intarg);
     99     0    stevel static	uint_t	asyintr(caddr_t argasy);
    100     0    stevel 
    101     0    stevel /* The async interrupt entry points */
    102     0    stevel static void	async_txint(struct asycom *asy, uchar_t lsr);
    103     0    stevel static void	async_rxint(struct asycom *asy, uchar_t lsr);
    104     0    stevel static void	async_msint(struct asycom *asy);
    105     0    stevel static int	async_softint(struct asycom *asy);
    106     0    stevel 
    107     0    stevel static void	async_ioctl(struct asyncline *async, queue_t *q, mblk_t *mp,
    108     0    stevel     boolean_t iswput);
    109     0    stevel static void	async_reioctl(void *);
    110     0    stevel static void	async_iocdata(queue_t *q, mblk_t *mp);
    111     0    stevel static void	async_restart(void *);
    112     0    stevel static void	async_start(struct asyncline *async);
    113     0    stevel static void	async_nstart(struct asyncline *async, int mode);
    114     0    stevel static void	async_resume(struct asyncline *async);
    115     0    stevel static int	asy_program(struct asycom *asy, int mode);
    116  5973  zk194757 
    117  5973  zk194757 /* Polled mode functions */
    118  5973  zk194757 static void	asyputchar(cons_polledio_arg_t, uchar_t c);
    119  5973  zk194757 static int	asygetchar(cons_polledio_arg_t);
    120  5973  zk194757 static boolean_t	asyischar(cons_polledio_arg_t);
    121  5973  zk194757 static void	asy_polled_enter(cons_polledio_arg_t);
    122  5973  zk194757 static void	asy_polled_exit(cons_polledio_arg_t);
    123     0    stevel 
    124     0    stevel static int	asymctl(struct asycom *, int, int);
    125     0    stevel static int	asytodm(int, int);
    126     0    stevel static int	dmtoasy(int);
    127     0    stevel static void	asycheckflowcontrol_hw(struct asycom *asy);
    128     0    stevel static boolean_t asycheckflowcontrol_sw(struct asycom *asy);
    129     0    stevel static void	asy_ppsevent(struct asycom *asy, int msr);
    130     0    stevel 
    131     0    stevel extern kcondvar_t lbolt_cv;
    132     0    stevel extern int ddi_create_internal_pathname(dev_info_t *dip, char *name,
    133     0    stevel 		int spec_type, minor_t minor_num);
    134     0    stevel 
    135     0    stevel 
    136     0    stevel /*
    137     0    stevel  * Baud rate table. Indexed by #defines found in sys/termios.h
    138     0    stevel  */
    139     0    stevel ushort_t asyspdtab[] = {
    140     0    stevel 	0,	/* 0 baud rate */
    141     0    stevel 	0x900,	/* 50 baud rate */
    142     0    stevel 	0x600,	/* 75 baud rate */
    143     0    stevel 	0x417,	/* 110 baud rate (%0.026) */
    144     0    stevel 	0x359,	/* 134 baud rate (%0.058) */
    145     0    stevel 	0x300,	/* 150 baud rate */
    146     0    stevel 	0x240,	/* 200 baud rate */
    147     0    stevel 	0x180,	/* 300 baud rate */
    148     0    stevel 	0x0c0,	/* 600 baud rate */
    149     0    stevel 	0x060,	/* 1200 baud rate */
    150     0    stevel 	0x040,	/* 1800 baud rate */
    151     0    stevel 	0x030,	/* 2400 baud rate */
    152     0    stevel 	0x018,	/* 4800 baud rate */
    153     0    stevel 	0x00c,	/* 9600 baud rate */
    154     0    stevel 	0x006,	/* 19200 baud rate */
    155     0    stevel 	0x003,	/* 38400 baud rate */
    156     0    stevel 	0x002,	/* 57600 baud rate */
    157     0    stevel 	0,	/* 76800 baud rate - not supported */
    158     0    stevel 	0x001,	/* 115200 baud rate */
    159     0    stevel 	0,	/* 153600 baud rate - not supported */
    160     0    stevel 	0x8002,	/* 230400 baud rate - supported on specific platforms */
    161     0    stevel 	0,	/* 307200 baud rate - not supported */
    162     0    stevel 	0x8001	/* 460800 baud rate - supported on specific platforms */
    163     0    stevel };
    164     0    stevel 
    165     0    stevel /*
    166     0    stevel  * Number of speeds supported is the number of entries in
    167     0    stevel  * the above table.
    168     0    stevel  */
    169     0    stevel #define	N_SU_SPEEDS	(sizeof (asyspdtab)/sizeof (ushort_t))
    170     0    stevel 
    171     0    stevel /*
    172     0    stevel  * Human-readable baud rate table.
    173     0    stevel  * Indexed by #defines found in sys/termios.h
    174     0    stevel  */
    175     0    stevel int baudtable[] = {
    176     0    stevel 	0,	/* 0 baud rate */
    177     0    stevel 	50,	/* 50 baud rate */
    178     0    stevel 	75,	/* 75 baud rate */
    179     0    stevel 	110,	/* 110 baud rate */
    180     0    stevel 	134,	/* 134 baud rate */
    181     0    stevel 	150,	/* 150 baud rate */
    182     0    stevel 	200,	/* 200 baud rate */
    183     0    stevel 	300,	/* 300 baud rate */
    184     0    stevel 	600,	/* 600 baud rate */
    185     0    stevel 	1200,	/* 1200 baud rate */
    186     0    stevel 	1800,	/* 1800 baud rate */
    187     0    stevel 	2400,	/* 2400 baud rate */
    188     0    stevel 	4800,	/* 4800 baud rate */
    189     0    stevel 	9600,	/* 9600 baud rate */
    190     0    stevel 	19200,	/* 19200 baud rate */
    191     0    stevel 	38400,	/* 38400 baud rate */
    192     0    stevel 	57600,	/* 57600 baud rate */
    193     0    stevel 	76800,	/* 76800 baud rate */
    194     0    stevel 	115200,	/* 115200 baud rate */
    195     0    stevel 	153600,	/* 153600 baud rate */
    196     0    stevel 	230400,	/* 230400 baud rate */
    197     0    stevel 	307200,	/* 307200 baud rate */
    198     0    stevel 	460800	/* 460800 baud rate */
    199     0    stevel };
    200     0    stevel 
    201     0    stevel static int asyopen(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
    202     0    stevel static int asyclose(queue_t *q, int flag);
    203     0    stevel static void asywput(queue_t *q, mblk_t *mp);
    204     0    stevel static void asyrsrv(queue_t *q);
    205     0    stevel 
    206     0    stevel struct module_info asy_info = {
    207     0    stevel 	0,
    208     0    stevel 	"su",
    209     0    stevel 	0,
    210     0    stevel 	INFPSZ,
    211     0    stevel 	32*4096,
    212     0    stevel 	4096
    213     0    stevel };
    214     0    stevel 
    215     0    stevel static struct qinit asy_rint = {
    216     0    stevel 	putq,
    217     0    stevel 	(int (*)())asyrsrv,
    218     0    stevel 	asyopen,
    219     0    stevel 	asyclose,
    220     0    stevel 	NULL,
    221     0    stevel 	&asy_info,
    222     0    stevel 	NULL
    223     0    stevel };
    224     0    stevel 
    225     0    stevel static struct qinit asy_wint = {
    226     0    stevel 	(int (*)())asywput,
    227     0    stevel 	NULL,
    228     0    stevel 	NULL,
    229     0    stevel 	NULL,
    230     0    stevel 	NULL,
    231     0    stevel 	&asy_info,
    232     0    stevel 	NULL
    233     0    stevel };
    234     0    stevel 
    235     0    stevel struct streamtab asy_str_info = {
    236     0    stevel 	&asy_rint,
    237     0    stevel 	&asy_wint,
    238     0    stevel 	NULL,
    239     0    stevel 	NULL
    240     0    stevel };
    241     0    stevel 
    242     0    stevel static int asyinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
    243     0    stevel 		void **result);
    244     0    stevel static int asyprobe(dev_info_t *);
    245     0    stevel static int asyattach(dev_info_t *, ddi_attach_cmd_t);
    246     0    stevel static int asydetach(dev_info_t *, ddi_detach_cmd_t);
    247     0    stevel 
    248     0    stevel static 	struct cb_ops cb_asy_ops = {
    249     0    stevel 	nodev,			/* cb_open */
    250     0    stevel 	nodev,			/* cb_close */
    251     0    stevel 	nodev,			/* cb_strategy */
    252     0    stevel 	nodev,			/* cb_print */
    253     0    stevel 	nodev,			/* cb_dump */
    254     0    stevel 	nodev,			/* cb_read */
    255     0    stevel 	nodev,			/* cb_write */
    256     0    stevel 	nodev,			/* cb_ioctl */
    257     0    stevel 	nodev,			/* cb_devmap */
    258     0    stevel 	nodev,			/* cb_mmap */
    259     0    stevel 	nodev,			/* cb_segmap */
    260     0    stevel 	nochpoll,		/* cb_chpoll */
    261     0    stevel 	ddi_prop_op,		/* cb_prop_op */
    262     0    stevel 	&asy_str_info,		/* cb_stream */
    263     0    stevel 	D_MP			/* cb_flag */
    264     0    stevel };
    265     0    stevel 
    266     0    stevel struct dev_ops asy_ops = {
    267     0    stevel 	DEVO_REV,		/* devo_rev */
    268     0    stevel 	0,			/* devo_refcnt */
    269     0    stevel 	asyinfo,		/* devo_getinfo */
    270     0    stevel 	nulldev,		/* devo_identify */
    271     0    stevel 	asyprobe,		/* devo_probe */
    272     0    stevel 	asyattach,		/* devo_attach */
    273     0    stevel 	asydetach,		/* devo_detach */
    274     0    stevel 	nodev,			/* devo_reset */
    275     0    stevel 	&cb_asy_ops,		/* devo_cb_ops */
    276  7656    Sherry 	NULL,			/* devo_bus_ops */
    277  7656    Sherry 	NULL,			/* devo_power */
    278  7656    Sherry 	ddi_quiesce_not_supported,	/* devo_quiesce */
    279     0    stevel };
    280     0    stevel 
    281     0    stevel /*
    282     0    stevel  * Module linkage information for the kernel.
    283     0    stevel  */
    284     0    stevel 
    285     0    stevel static struct modldrv modldrv = {
    286     0    stevel 	&mod_driverops, /* Type of module.  This one is a driver */
    287  7656    Sherry 	"su driver",
    288     0    stevel 	&asy_ops,	/* driver ops */
    289     0    stevel };
    290     0    stevel 
    291     0    stevel static struct modlinkage modlinkage = {
    292     0    stevel 	MODREV_1,
    293     0    stevel 	&modldrv,
    294     0    stevel 	NULL
    295     0    stevel };
    296     0    stevel 
    297     0    stevel int
    298     0    stevel _init(void)
    299     0    stevel {
    300     0    stevel 	int status;
    301     0    stevel 
    302     0    stevel 	status = ddi_soft_state_init(&su_asycom, sizeof (struct asycom),
    303     0    stevel 	    SU_INITIAL_SOFT_ITEMS);
    304     0    stevel 	if (status != 0)
    305  5973  zk194757 		return (status);
    306     0    stevel 	status = ddi_soft_state_init(&su_asyncline, sizeof (struct asyncline),
    307     0    stevel 	    SU_INITIAL_SOFT_ITEMS);
    308     0    stevel 	if (status != 0) {
    309     0    stevel 		ddi_soft_state_fini(&su_asycom);
    310     0    stevel 		return (status);
    311     0    stevel 	}
    312     0    stevel 
    313     0    stevel 	if ((status = mod_install(&modlinkage)) != 0) {
    314     0    stevel 		ddi_soft_state_fini(&su_asycom);
    315     0    stevel 		ddi_soft_state_fini(&su_asyncline);
    316     0    stevel 	}
    317     0    stevel 
    318     0    stevel 	return (status);
    319     0    stevel }
    320     0    stevel 
    321     0    stevel int
    322     0    stevel _fini(void)
    323     0    stevel {
    324     0    stevel 	int i;
    325     0    stevel 
    326     0    stevel 	i = mod_remove(&modlinkage);
    327     0    stevel 	if (i == 0) {
    328     0    stevel 		ddi_soft_state_fini(&su_asycom);
    329     0    stevel 		ddi_soft_state_fini(&su_asyncline);
    330     0    stevel 	}
    331     0    stevel 
    332     0    stevel 	return (i);
    333     0    stevel }
    334     0    stevel 
    335     0    stevel int
    336     0    stevel _info(struct modinfo *modinfop)
    337     0    stevel {
    338     0    stevel 	return (mod_info(&modlinkage, modinfop));
    339     0    stevel }
    340     0    stevel 
    341     0    stevel static int
    342     0    stevel asyprobe(dev_info_t *devi)
    343     0    stevel {
    344     0    stevel 	int		instance;
    345     0    stevel 	ddi_acc_handle_t handle;
    346     0    stevel 	uchar_t *addr;
    347     0    stevel 	ddi_device_acc_attr_t attr;
    348     0    stevel 
    349     0    stevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
    350     0    stevel 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
    351     0    stevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
    352     0    stevel 	if (ddi_regs_map_setup(devi, SU_REGISTER_FILE_NO, (caddr_t *)&addr,
    353     0    stevel 	    SU_REGOFFSET, SU_REGISTER_LEN, &attr, &handle) != DDI_SUCCESS) {
    354     0    stevel 		cmn_err(CE_WARN, "asyprobe regs map setup failed");
    355     0    stevel 		return (DDI_PROBE_FAILURE);
    356     0    stevel 	}
    357     0    stevel #ifdef DEBUG
    358     0    stevel 	if (asydebug)
    359  5973  zk194757 		printf("Probe address mapped %p\n", (void *)addr);
    360     0    stevel #endif
    361     0    stevel 
    362     0    stevel 	/*
    363     0    stevel 	 * Probe for the device:
    364     0    stevel 	 * 	Ser. int. uses bits 0,1,2; FIFO uses 3,6,7; 4,5 wired low.
    365     0    stevel 	 * 	If bit 4 or 5 appears on inb() ISR, board is not there.
    366     0    stevel 	 */
    367  4125    jesusm 	if (ddi_get8(handle, addr+ISR) & 0x30) {
    368  5973  zk194757 		ddi_regs_map_free(&handle);
    369  5973  zk194757 		return (DDI_PROBE_FAILURE);
    370  4125    jesusm 	}
    371  4125    jesusm 
    372     0    stevel 	instance = ddi_get_instance(devi);
    373     0    stevel 	if (max_asy_instance < instance)
    374  5973  zk194757 		max_asy_instance = instance;
    375     0    stevel 	ddi_regs_map_free(&handle);
    376     0    stevel 
    377     0    stevel 	return (DDI_PROBE_SUCCESS); /* hw is present */
    378     0    stevel }
    379     0    stevel 
    380     0    stevel static int
    381     0    stevel asydetach(dev_info_t *devi, ddi_detach_cmd_t cmd)
    382     0    stevel {
    383     0    stevel 	register int	instance;
    384     0    stevel 	struct asycom	*asy;
    385     0    stevel 	struct asyncline *async;
    386     0    stevel 	char		name[16];
    387     0    stevel 
    388     0    stevel 	instance = ddi_get_instance(devi);	/* find out which unit */
    389     0    stevel 
    390     0    stevel 	asy = (struct asycom *)ddi_get_soft_state(su_asycom, instance);
    391     0    stevel 	async = (struct asyncline *)ddi_get_soft_state(su_asyncline, instance);
    392     0    stevel 
    393     0    stevel 	switch (cmd) {
    394  5973  zk194757 		case DDI_DETACH:
    395  5973  zk194757 			break;
    396  5973  zk194757 		case DDI_SUSPEND:
    397  5973  zk194757 			/* grab both mutex locks */
    398  5973  zk194757 			mutex_enter(asy->asy_excl);
    399  5973  zk194757 			mutex_enter(asy->asy_excl_hi);
    400  5973  zk194757 			if (asy->suspended) {
    401  5973  zk194757 				mutex_exit(asy->asy_excl_hi);
    402  5973  zk194757 				mutex_exit(asy->asy_excl);
    403  5973  zk194757 				return (DDI_SUCCESS);
    404  5973  zk194757 			}
    405  5973  zk194757 			asy->suspended = B_TRUE;
    406  5973  zk194757 
    407  5973  zk194757 			/*
    408  5973  zk194757 			 * The quad UART ST16C554D, version D2 (made by EXAR)
    409  5973  zk194757 			 * has an anomaly of generating spurious interrupts
    410  5973  zk194757 			 * when the ICR is loaded with zero. The workaround
    411  5973  zk194757 			 * would be to read/write any register with DATA1 bit
    412  5973  zk194757 			 * set to 0 before such write.
    413  5973  zk194757 			 */
    414  5973  zk194757 			if (asy->asy_hwtype == ASY16C554D)
    415  5973  zk194757 				OUTB(SPR, 0);
    416  5973  zk194757 
    417  5973  zk194757 			/* Disable further interrupts */
    418  5973  zk194757 			OUTB(ICR, 0);
    419     0    stevel 			mutex_exit(asy->asy_excl_hi);
    420     0    stevel 			mutex_exit(asy->asy_excl);
    421     0    stevel 			return (DDI_SUCCESS);
    422  2119   anovick 
    423  5973  zk194757 		default:
    424  5973  zk194757 			return (DDI_FAILURE);
    425     0    stevel 	}
    426     0    stevel 
    427     0    stevel #ifdef DEBUG
    428     0    stevel 	if (asydebug & ASY_DEBUG_INIT)
    429  5973  zk194757 		cmn_err(CE_NOTE, "su%d: ASY%s shutdown.", instance,
    430  5973  zk194757 		    asy->asy_hwtype == ASY82510 ? "82510" :
    431  5973  zk194757 		    asy->asy_hwtype == ASY16550AF ? "16550AF" :
    432  5973  zk194757 		    asy->asy_hwtype == ASY16C554D ? "16C554D" :
    433  5973  zk194757 		    "8250");
    434     0    stevel #endif
    435     0    stevel 	/*
    436     0    stevel 	 * Before removing interrupts it is always better to disable
    437     0    stevel 	 * interrupts if the chip gives a provision to disable the
    438     0    stevel 	 * serial port interrupts.
    439     0    stevel 	 */
    440     0    stevel 	mutex_enter(asy->asy_excl);
    441     0    stevel 	mutex_enter(asy->asy_excl_hi);
    442  2119   anovick 	/* disable interrupts, see EXAR bug */
    443  2877   anovick 	if (asy->asy_hwtype == ASY16C554D)
    444  2877   anovick 		OUTB(SPR, 0);
    445  2119   anovick 	OUTB(ICR, 0);
    446     0    stevel 	mutex_exit(asy->asy_excl_hi);
    447     0    stevel 	mutex_exit(asy->asy_excl);
    448     0    stevel 
    449     0    stevel 	/* remove minor device node(s) for this device */
    450     0    stevel 	(void) sprintf(name, "%c", (instance+'a'));	/* serial-port */
    451     0    stevel 	ddi_remove_minor_node(devi, name);
    452     0    stevel 	(void) sprintf(name, "%c,cu", (instance+'a')); /* serial-port:dailout */
    453     0    stevel 	ddi_remove_minor_node(devi, name);
    454     0    stevel 
    455     0    stevel 	mutex_destroy(asy->asy_excl);
    456     0    stevel 	mutex_destroy(asy->asy_excl_hi);
    457     0    stevel 	kmem_free(asy->asy_excl, sizeof (kmutex_t));
    458     0    stevel 	kmem_free(asy->asy_excl_hi, sizeof (kmutex_t));
    459     0    stevel 	cv_destroy(&async->async_flags_cv);
    460     0    stevel 	kstat_delete(asy->sukstat);
    461     0    stevel 	ddi_remove_intr(devi, 0, asy->asy_iblock);
    462     0    stevel 	ddi_regs_map_free(&asy->asy_handle);
    463     0    stevel 	ddi_remove_softintr(asy->asy_softintr_id);
    464     0    stevel 	mutex_destroy(asy->asy_soft_lock);
    465     0    stevel 	kmem_free(asy->asy_soft_lock, sizeof (kmutex_t));
    466     0    stevel 	ddi_soft_state_free(su_asycom, instance);
    467     0    stevel 	ddi_soft_state_free(su_asyncline, instance);
    468     0    stevel 	return (DDI_SUCCESS);
    469     0    stevel }
    470     0    stevel 
    471     0    stevel static int
    472     0    stevel asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd)
    473     0    stevel {
    474     0    stevel 	register int	instance;
    475     0    stevel 	struct asycom	*asy;
    476     0    stevel 	struct asyncline *async;
    477     0    stevel 	char		name[40];
    478     0    stevel 	ddi_device_acc_attr_t attr;
    479     0    stevel 	enum states { EMPTY, SOFTSTATE, REGSMAP, MUTEXES, ADDINTR,
    480     0    stevel 	    SOFTINTR, ASYINIT, KSTAT, MINORNODE };
    481     0    stevel 	enum states state = EMPTY;
    482  2877   anovick 	char *hwtype;
    483     0    stevel 
    484     0    stevel 	instance = ddi_get_instance(devi);	/* find out which unit */
    485     0    stevel 
    486     0    stevel 	/* cannot attach a device that has not been probed first */
    487     0    stevel 	if (instance > max_asy_instance)
    488  5973  zk194757 		return (DDI_FAILURE);
    489     0    stevel 
    490     0    stevel 	if (cmd != DDI_RESUME) {
    491     0    stevel 		/* Allocate soft state space */
    492     0    stevel 		if (ddi_soft_state_zalloc(su_asycom, instance) != DDI_SUCCESS) {
    493     0    stevel 			cmn_err(CE_WARN, "su%d: cannot allocate soft state",
    494     0    stevel 			    instance);
    495     0    stevel 			goto error;
    496     0    stevel 		}
    497     0    stevel 	}
    498     0    stevel 	state = SOFTSTATE;
    499     0    stevel 
    500     0    stevel 	asy = (struct asycom *)ddi_get_soft_state(su_asycom, instance);
    501     0    stevel 
    502     0    stevel 	if (asy == NULL) {
    503     0    stevel 		cmn_err(CE_WARN, "su%d: cannot get soft state", instance);
    504     0    stevel 		goto error;
    505     0    stevel 	}
    506     0    stevel 
    507     0    stevel 	switch (cmd) {
    508  5973  zk194757 		case DDI_ATTACH:
    509  5973  zk194757 			break;
    510  5973  zk194757 		case DDI_RESUME: {
    511  5973  zk194757 			struct asyncline *async;
    512     0    stevel 
    513  5973  zk194757 			/* grab both mutex locks */
    514  5973  zk194757 			mutex_enter(asy->asy_excl);
    515  5973  zk194757 			mutex_enter(asy->asy_excl_hi);
    516  5973  zk194757 			if (!asy->suspended) {
    517  5973  zk194757 				mutex_exit(asy->asy_excl_hi);
    518  5973  zk194757 				mutex_exit(asy->asy_excl);
    519  5973  zk194757 				return (DDI_SUCCESS);
    520  5973  zk194757 			}
    521  5973  zk194757 			/*
    522  5973  zk194757 			 * re-setup all the registers and enable interrupts if
    523  5973  zk194757 			 * needed
    524  5973  zk194757 			 */
    525  5973  zk194757 			async = (struct asyncline *)asy->asy_priv;
    526  5973  zk194757 			if ((async) && (async->async_flags & ASYNC_ISOPEN))
    527  5973  zk194757 				(void) asy_program(asy, ASY_INIT);
    528  5973  zk194757 			asy->suspended = B_FALSE;
    529     0    stevel 			mutex_exit(asy->asy_excl_hi);
    530     0    stevel 			mutex_exit(asy->asy_excl);
    531     0    stevel 			return (DDI_SUCCESS);
    532     0    stevel 		}
    533  5973  zk194757 		default:
    534  5973  zk194757 			goto error;
    535     0    stevel 	}
    536     0    stevel 
    537     0    stevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
    538     0    stevel 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
    539     0    stevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
    540     0    stevel 
    541     0    stevel 	if (ddi_regs_map_setup(devi, SU_REGISTER_FILE_NO,
    542     0    stevel 	    (caddr_t *)&asy->asy_ioaddr, SU_REGOFFSET, SU_REGISTER_LEN,
    543     0    stevel 	    &attr, &asy->asy_handle) != DDI_SUCCESS) {
    544     0    stevel 		cmn_err(CE_WARN, "asyprobe regs map setup failed");
    545     0    stevel 		goto error;
    546     0    stevel 	}
    547     0    stevel 	state = REGSMAP;
    548     0    stevel 
    549     0    stevel #ifdef DEBUG
    550     0    stevel 	if (asydebug)
    551  5973  zk194757 		printf("su attach mapped %p\n", (void *)asy->asy_ioaddr);
    552     0    stevel #endif
    553     0    stevel 
    554     0    stevel 	/*
    555     0    stevel 	 * Initialize the port with default settings.
    556     0    stevel 	 */
    557     0    stevel 	asy->asy_fifo_buf = 1;
    558     0    stevel 	asy->asy_use_fifo = FIFO_OFF;
    559     0    stevel 
    560     0    stevel 	/*
    561     0    stevel 	 * Check for baudrate generator's "baud-divisor-factor" property setup
    562     0    stevel 	 * by OBP, since different UART chips might have different baudrate
    563     0    stevel 	 * generator divisor. e.g., in case of NSPG's Sputnik platform, the
    564     0    stevel 	 * baud-divisor-factor is 13, it uses dedicated 16552 "DUART" chip
    565     0    stevel 	 * instead of SuperIO. Since the baud-divisor-factor must be a positive
    566     0    stevel 	 * integer, the divisors will always be at least as large as the values
    567     0    stevel 	 * in asyspdtab[].  Make the default factor 1.
    568     0    stevel 	 */
    569     0    stevel 	asy->asy_baud_divisor_factor = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
    570     0    stevel 	    DDI_PROP_DONTPASS, "baud-divisor-factor", 1);
    571     0    stevel 
    572     0    stevel 	/* set speed cap */
    573     0    stevel 	asy->asy_speed_cap = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
    574     0    stevel 	    DDI_PROP_DONTPASS, "serial-speed-cap", 115200);
    575     0    stevel 
    576     0    stevel 	/* check for ASY82510 chip */
    577     0    stevel 	OUTB(ISR, 0x20);
    578     0    stevel 	if (INB(ISR) & 0x20) { /* 82510 chip is present */
    579     0    stevel 		/*
    580     0    stevel 		 * Since most of the general operation of the 82510 chip
    581     0    stevel 		 * can be done from BANK 0 (8250A/16450 compatable mode)
    582     0    stevel 		 * we will default to BANK 0.
    583     0    stevel 		 */
    584     0    stevel 		asy->asy_hwtype = ASY82510;
    585     0    stevel 		OUTB(DAT+7, 0x04); /* clear status */
    586     0    stevel 		OUTB(ISR, 0x40); /* set to bank 2 */
    587     0    stevel 		OUTB(MCR, 0x08); /* IMD */
    588     0    stevel 		OUTB(DAT, 0x21); /* FMD */
    589     0    stevel 		OUTB(ISR, 0x00); /* set to bank 0 */
    590     0    stevel 		asy->asy_trig_level = 0;
    591     0    stevel 	} else { /* Set the UART in FIFO mode if it has FIFO buffers */
    592     0    stevel 		asy->asy_hwtype = ASY16550AF;
    593     0    stevel 		OUTB(FIFOR, 0x00); /* clear fifo register */
    594     0    stevel 		asy->asy_trig_level = 0x00; /* sets the fifo Threshold to 1 */
    595     0    stevel 
    596     0    stevel 		/* set/Enable FIFO */
    597     0    stevel 		OUTB(FIFOR, FIFO_ON | FIFODMA | FIFOTXFLSH | FIFORXFLSH |
    598     0    stevel 		    (asy->asy_trig_level & 0xff));
    599     0    stevel 
    600     0    stevel 		if ((INB(ISR) & 0xc0) == 0xc0)
    601  5973  zk194757 			asy->asy_use_fifo = FIFO_ON;
    602     0    stevel 		else {
    603     0    stevel 			asy->asy_hwtype = ASY8250;
    604     0    stevel 			OUTB(FIFOR, 0x00); /* NO FIFOs */
    605     0    stevel 			asy->asy_trig_level = 0;
    606     0    stevel 		}
    607     0    stevel 	}
    608     0    stevel 
    609  2877   anovick 	/* check for ST16C554D chip */
    610  2877   anovick 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, DDI_PROP_NOTPROM |
    611  2877   anovick 	    DDI_PROP_DONTPASS, "hwtype", &hwtype)) == DDI_PROP_SUCCESS) {
    612  2877   anovick 		if (strcmp(hwtype, "ST16C554D") == 0)
    613  2877   anovick 			asy->asy_hwtype = ASY16C554D;
    614  2877   anovick 		ddi_prop_free(hwtype);
    615  2877   anovick 	}
    616  2877   anovick 
    617  2119   anovick 	/* disable interrupts, see EXAR bug */
    618  2877   anovick 	if (asy->asy_hwtype == ASY16C554D)
    619  2877   anovick 		OUTB(SPR, 0);
    620  2119   anovick 	OUTB(ICR, 0);
    621     0    stevel 	OUTB(LCR, DLAB); /* select baud rate generator */
    622     0    stevel 	/* Set the baud rate to 9600 */
    623     0    stevel 	OUTB(DAT+DLL, (ASY9600*asy->asy_baud_divisor_factor) & 0xff);
    624     0    stevel 	OUTB(DAT+DLH, ((ASY9600*asy->asy_baud_divisor_factor) >> 8) & 0xff);
    625     0    stevel 	OUTB(LCR, STOP1|BITS8);
    626     0    stevel 	OUTB(MCR, (DTR | RTS| OUT2));
    627     0    stevel 
    628     0    stevel 	/*
    629     0    stevel 	 * Set up the other components of the asycom structure for this port.
    630     0    stevel 	 */
    631     0    stevel 	asy->asy_excl = (kmutex_t *)
    632     0    stevel 	    kmem_zalloc(sizeof (kmutex_t), KM_SLEEP);
    633     0    stevel 	asy->asy_excl_hi = (kmutex_t *)
    634     0    stevel 	    kmem_zalloc(sizeof (kmutex_t), KM_SLEEP);
    635     0    stevel 	asy->asy_soft_lock = (kmutex_t *)
    636     0    stevel 	    kmem_zalloc(sizeof (kmutex_t), KM_SLEEP);
    637     0    stevel 	asy->asy_unit = instance;
    638     0    stevel 	asy->asy_dip = devi;
    639     0    stevel 
    640     0    stevel 	if (ddi_get_iblock_cookie(devi, 0, &asy->asy_iblock) != DDI_SUCCESS) {
    641     0    stevel 		cmn_err(CE_NOTE,
    642     0    stevel 		    "Get iblock_cookie failed-Device interrupt%x\n", instance);
    643     0    stevel 		goto error;
    644     0    stevel 	}
    645     0    stevel 
    646     0    stevel 	if (ddi_get_soft_iblock_cookie(devi, DDI_SOFTINT_HIGH,
    647     0    stevel 	    &asy->asy_soft_iblock) != DDI_SUCCESS) {
    648     0    stevel 		cmn_err(CE_NOTE, "Get iblock_cookie failed -soft interrupt%x\n",
    649     0    stevel 		    instance);
    650     0    stevel 		goto error;
    651     0    stevel 	}
    652     0    stevel 
    653     0    stevel 	mutex_init(asy->asy_soft_lock, NULL, MUTEX_DRIVER,
    654     0    stevel 	    (void *)asy->asy_soft_iblock);
    655     0    stevel 	mutex_init(asy->asy_excl, NULL, MUTEX_DRIVER, NULL);
    656     0    stevel 	mutex_init(asy->asy_excl_hi, NULL, MUTEX_DRIVER,
    657     0    stevel 	    (void *)asy->asy_iblock);
    658     0    stevel 	state = MUTEXES;
    659     0    stevel 
    660     0    stevel 	/*
    661     0    stevel 	 * Install interrupt handlers for this device.
    662     0    stevel 	 */
    663     0    stevel 	if (ddi_add_intr(devi, 0, &(asy->asy_iblock), 0, asyintr,
    664     0    stevel 	    (caddr_t)asy) != DDI_SUCCESS) {
    665     0    stevel 		cmn_err(CE_CONT,
    666     0    stevel 		    "Cannot set device interrupt for su driver\n");
    667     0    stevel 		goto error;
    668     0    stevel 	}
    669     0    stevel 	state = ADDINTR;
    670     0    stevel 
    671     0    stevel 	if (ddi_add_softintr(devi, DDI_SOFTINT_HIGH, &(asy->asy_softintr_id),
    672     0    stevel 	    &asy->asy_soft_iblock, 0, asysoftintr, (caddr_t)asy)
    673     0    stevel 	    != DDI_SUCCESS) {
    674     0    stevel 		cmn_err(CE_CONT, "Cannot set soft interrupt for su driver\n");
    675     0    stevel 		goto error;
    676     0    stevel 	}
    677     0    stevel 	state = SOFTINTR;
    678     0    stevel 
    679     0    stevel 	/* initialize the asyncline structure */
    680     0    stevel 	if (ddi_soft_state_zalloc(su_asyncline, instance) != DDI_SUCCESS) {
    681     0    stevel 		cmn_err(CE_CONT, "su%d: cannot allocate soft state", instance);
    682     0    stevel 		goto error;
    683     0    stevel 	}
    684     0    stevel 	state = ASYINIT;
    685     0    stevel 
    686     0    stevel 	async = (struct asyncline *)ddi_get_soft_state(su_asyncline, instance);
    687     0    stevel 
    688     0    stevel 	mutex_enter(asy->asy_excl);
    689     0    stevel 	async->async_common = asy;
    690     0    stevel 	cv_init(&async->async_flags_cv, NULL, CV_DEFAULT, NULL);
    691     0    stevel 	mutex_exit(asy->asy_excl);
    692     0    stevel 
    693     0    stevel 	if ((asy->sukstat = kstat_create("su", instance, "serialstat",
    694     0    stevel 	    "misc", KSTAT_TYPE_NAMED, 2, KSTAT_FLAG_VIRTUAL)) != NULL) {
    695     0    stevel 		asy->sukstat->ks_data = &asy->kstats;
    696     0    stevel 		kstat_named_init(&asy->kstats.ringover, "ring buffer overflow",
    697     0    stevel 		    KSTAT_DATA_UINT64);
    698     0    stevel 		kstat_named_init(&asy->kstats.siloover, "silo overflow",
    699     0    stevel 		    KSTAT_DATA_UINT64);
    700     0    stevel 		kstat_install(asy->sukstat);
    701     0    stevel 	}
    702     0    stevel 	state = KSTAT;
    703     0    stevel 
    704     0    stevel 	if (strcmp(ddi_node_name(devi), "rsc-console") == 0) {
    705     0    stevel 		/*
    706     0    stevel 		 * If the device is configured as the 'rsc-console'
    707     0    stevel 		 * create the minor device for this node.
    708     0    stevel 		 */
    709     0    stevel 		if (ddi_create_minor_node(devi, "ssp", S_IFCHR,
    710     0    stevel 		    asy->asy_unit | RSC_DEVICE, DDI_PSEUDO, NULL)
    711     0    stevel 		    == DDI_FAILURE) {
    712     0    stevel 			cmn_err(CE_WARN,
    713     0    stevel 			    "%s%d: Failed to create node rsc-console",
    714     0    stevel 			    ddi_get_name(devi), ddi_get_instance(devi));
    715     0    stevel 			goto error;
    716     0    stevel 		}
    717     0    stevel 
    718     0    stevel 		asy->asy_lom_console = 0;
    719     0    stevel 		asy->asy_rsc_console = 1;
    720     0    stevel 		asy->asy_rsc_control = 0;
    721     0    stevel 		asy->asy_device_type = ASY_SERIAL;
    722     0    stevel 		asy->asy_flags |= ASY_IGNORE_CD;
    723     0    stevel 
    724     0    stevel 	} else if (strcmp(ddi_node_name(devi), "lom-console") == 0) {
    725     0    stevel 		/*
    726     0    stevel 		 * If the device is configured as the 'lom-console'
    727     0    stevel 		 * create the minor device for this node.
    728     0    stevel 		 * Do not create a dialout device.
    729     0    stevel 		 * Use the same minor numbers as would be used for standard
    730     0    stevel 		 * serial instances.
    731     0    stevel 		 */
    732     0    stevel 		if (ddi_create_minor_node(devi, "lom-console", S_IFCHR,
    733     0    stevel 		    instance, DDI_NT_SERIAL_LOMCON, NULL) == DDI_FAILURE) {
    734     0    stevel 			cmn_err(CE_WARN,
    735     0    stevel 			    "%s%d: Failed to create node lom-console",
    736     0    stevel 			    ddi_get_name(devi), ddi_get_instance(devi));
    737     0    stevel 			goto error;
    738     0    stevel 		}
    739     0    stevel 		asy->asy_lom_console = 1;
    740     0    stevel 		asy->asy_rsc_console = 0;
    741     0    stevel 		asy->asy_rsc_control = 0;
    742     0    stevel 		asy->asy_device_type = ASY_SERIAL;
    743     0    stevel 		asy->asy_flags |= ASY_IGNORE_CD;
    744     0    stevel 
    745     0    stevel 	} else if (strcmp(ddi_node_name(devi), "rsc-control") == 0) {
    746     0    stevel 		/*
    747     0    stevel 		 * If the device is configured as the 'rsc-control'
    748     0    stevel 		 * create the minor device for this node.
    749     0    stevel 		 */
    750     0    stevel 		if (ddi_create_minor_node(devi, "sspctl", S_IFCHR,
    751     0    stevel 		    asy->asy_unit | RSC_DEVICE, DDI_PSEUDO, NULL)
    752     0    stevel 		    == DDI_FAILURE) {
    753     0    stevel 			cmn_err(CE_WARN, "%s%d: Failed to create rsc-control",
    754     0    stevel 			    ddi_get_name(devi), ddi_get_instance(devi));
    755     0    stevel 			goto error;
    756     0    stevel 		}
    757     0    stevel 
    758     0    stevel 		asy->asy_lom_console = 0;
    759     0    stevel 		asy->asy_rsc_console = 0;
    760     0    stevel 		asy->asy_rsc_control = 1;
    761     0    stevel 		asy->asy_device_type = ASY_SERIAL;
    762     0    stevel 		asy->asy_flags |= ASY_IGNORE_CD;
    763     0    stevel 
    764     0    stevel 	} else if (ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
    765  5973  zk194757 	    "keyboard", 0)) {
    766     0    stevel 		/*
    767     0    stevel 		 * If the device is a keyboard, then create an internal
    768     0    stevel 		 * pathname so that the dacf code will link the node into
    769     0    stevel 		 * the keyboard console stream.  See dacf.conf.
    770     0    stevel 		 */
    771     0    stevel 		if (ddi_create_internal_pathname(devi, "keyboard",
    772     0    stevel 		    S_IFCHR, instance) == DDI_FAILURE) {
    773     0    stevel 			goto error;
    774     0    stevel 		}
    775     0    stevel 		asy->asy_flags |= ASY_IGNORE_CD;	/* ignore cd */
    776     0    stevel 		asy->asy_device_type = ASY_KEYBOARD; 	/* Device type */
    777     0    stevel 	} else if (ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
    778  5973  zk194757 	    "mouse", 0)) {
    779     0    stevel 		/*
    780     0    stevel 		 * If the device is a mouse, then create an internal
    781     0    stevel 		 * pathname so that the dacf code will link the node into
    782     0    stevel 		 * the mouse stream.  See dacf.conf.
    783     0    stevel 		 */
    784     0    stevel 		if (ddi_create_internal_pathname(devi, "mouse", S_IFCHR,
    785     0    stevel 		    instance) == DDI_FAILURE) {
    786     0    stevel 			goto error;
    787     0    stevel 		}
    788     0    stevel 		asy->asy_flags |= ASY_IGNORE_CD;	/* ignore cd */
    789     0    stevel 		asy->asy_device_type = ASY_MOUSE;
    790     0    stevel 	} else {
    791     0    stevel 		/*
    792     0    stevel 		 * If not used for keyboard/mouse, create minor devices nodes
    793     0    stevel 		 * for this device
    794     0    stevel 		 */
    795     0    stevel 		/* serial-port */
    796     0    stevel 		(void) sprintf(name, "%c", (instance+'a'));
    797     0    stevel 		if (ddi_create_minor_node(devi, name, S_IFCHR, instance,
    798     0    stevel 		    DDI_NT_SERIAL_MB, NULL) == DDI_FAILURE) {
    799     0    stevel 			goto error;
    800     0    stevel 		}
    801     0    stevel 		state = MINORNODE;
    802     0    stevel 		/* serial-port:dailout */
    803     0    stevel 		(void) sprintf(name, "%c,cu", (instance+'a'));
    804     0    stevel 		if (ddi_create_minor_node(devi, name, S_IFCHR, instance|OUTLINE,
    805     0    stevel 		    DDI_NT_SERIAL_MB_DO, NULL) == DDI_FAILURE) {
    806     0    stevel 			goto error;
    807     0    stevel 		}
    808     0    stevel 		/* Property for ignoring DCD */
    809     0    stevel 		if (ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
    810     0    stevel 		    "ignore-cd", 0)) {
    811     0    stevel 			asy->asy_flags |= ASY_IGNORE_CD;  /* ignore cd */
    812     0    stevel 		} else {
    813     0    stevel 			asy->asy_flags &= ~ASY_IGNORE_CD;
    814     0    stevel 			/*
    815     0    stevel 			 * if ignore-cd is not available it could be
    816     0    stevel 			 * some old legacy platform, try to see
    817     0    stevel 			 * whether the old legacy property exists
    818     0    stevel 			 */
    819     0    stevel 			(void) sprintf(name,
    820     0    stevel 			    "port-%c-ignore-cd", (instance+ 'a'));
    821     0    stevel 			if (ddi_getprop(DDI_DEV_T_ANY, devi,
    822     0    stevel 			    DDI_PROP_DONTPASS, name, 0))
    823     0    stevel 				asy->asy_flags |= ASY_IGNORE_CD;
    824     0    stevel 		}
    825     0    stevel 		asy->asy_device_type = ASY_SERIAL;
    826     0    stevel 	}
    827  5973  zk194757 
    828  5973  zk194757 	/*
    829  5973  zk194757 	 * Fill in the polled I/O structure
    830  5973  zk194757 	 */
    831  5973  zk194757 	asy->polledio.cons_polledio_version = CONSPOLLEDIO_V0;
    832  5973  zk194757 	asy->polledio.cons_polledio_argument = (cons_polledio_arg_t)asy;
    833  5973  zk194757 	asy->polledio.cons_polledio_putchar =  asyputchar;
    834  5973  zk194757 	asy->polledio.cons_polledio_getchar = asygetchar;
    835  5973  zk194757 	asy->polledio.cons_polledio_ischar = asyischar;
    836  5973  zk194757 	asy->polledio.cons_polledio_enter = asy_polled_enter;
    837  5973  zk194757 	asy->polledio.cons_polledio_exit = asy_polled_exit;
    838  5973  zk194757 
    839  5973  zk194757 	/* Initialize saved ICR and polled_enter */
    840  5973  zk194757 	asy->polled_icr = 0;
    841  5973  zk194757 	asy->polled_enter = B_FALSE;
    842  5973  zk194757 
    843     0    stevel 	ddi_report_dev(devi);
    844     0    stevel 	return (DDI_SUCCESS);
    845     0    stevel 
    846     0    stevel error:
    847     0    stevel 	if (state == MINORNODE) {
    848     0    stevel 		(void) sprintf(name, "%c", (instance+'a'));
    849     0    stevel 		ddi_remove_minor_node(devi, name);
    850     0    stevel 	}
    851     0    stevel 	if (state >= KSTAT)
    852     0    stevel 		kstat_delete(asy->sukstat);
    853     0    stevel 	if (state >= ASYINIT) {
    854     0    stevel 		cv_destroy(&async->async_flags_cv);
    855     0    stevel 		ddi_soft_state_free(su_asyncline, instance);
    856     0    stevel 	}
    857     0    stevel 	if (state >= SOFTINTR)
    858     0    stevel 		ddi_remove_softintr(asy->asy_softintr_id);
    859     0    stevel 	if (state >= ADDINTR)
    860     0    stevel 		ddi_remove_intr(devi, 0, asy->asy_iblock);
    861     0    stevel 	if (state >= MUTEXES) {
    862     0    stevel 		mutex_destroy(asy->asy_excl_hi);
    863     0    stevel 		mutex_destroy(asy->asy_excl);
    864     0    stevel 		mutex_destroy(asy->asy_soft_lock);
    865     0    stevel 		kmem_free(asy->asy_excl_hi, sizeof (kmutex_t));
    866     0    stevel 		kmem_free(asy->asy_excl, sizeof (kmutex_t));
    867     0    stevel 		kmem_free(asy->asy_soft_lock, sizeof (kmutex_t));
    868     0    stevel 	}
    869     0    stevel 	if (state >= REGSMAP)
    870     0    stevel 		ddi_regs_map_free(&asy->asy_handle);
    871     0    stevel 	if (state >= SOFTSTATE)
    872     0    stevel 		ddi_soft_state_free(su_asycom, instance);
    873     0    stevel 	/* no action for EMPTY state */
    874     0    stevel 	return (DDI_FAILURE);
    875     0    stevel }
    876     0    stevel 
    877     0    stevel static int
    878     0    stevel asyinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
    879     0    stevel 	void **result)
    880     0    stevel {
    881     0    stevel 	_NOTE(ARGUNUSED(dip))
    882     0    stevel 	register dev_t dev = (dev_t)arg;
    883     0    stevel 	register int instance, error;
    884     0    stevel 	struct asycom *asy;
    885     0    stevel 
    886     0    stevel 	if ((instance = UNIT(dev)) > max_asy_instance)
    887     0    stevel 		return (DDI_FAILURE);
    888     0    stevel 
    889     0    stevel 	switch (infocmd) {
    890  5973  zk194757 		case DDI_INFO_DEVT2DEVINFO:
    891  5973  zk194757 			asy = (struct asycom *)ddi_get_soft_state(su_asycom,
    892  5973  zk194757 			    instance);
    893  5973  zk194757 			if (asy->asy_dip == NULL)
    894  5973  zk194757 				error = DDI_FAILURE;
    895  5973  zk194757 			else {
    896  5973  zk194757 				*result = (void *) asy->asy_dip;
    897  5973  zk194757 				error = DDI_SUCCESS;
    898  5973  zk194757 			}
    899  5973  zk194757 			break;
    900  5973  zk194757 		case DDI_INFO_DEVT2INSTANCE:
    901  5973  zk194757 			*result = (void *)(uintptr_t)instance;
    902     0    stevel 			error = DDI_SUCCESS;
    903  5973  zk194757 			break;
    904  5973  zk194757 		default:
    905  5973  zk194757 			error = DDI_FAILURE;
    906     0    stevel 	}
    907     0    stevel 	return (error);
    908     0    stevel }
    909     0    stevel 
    910     0    stevel static int
    911     0    stevel asyopen(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
    912     0    stevel {
    913     0    stevel 	_NOTE(ARGUNUSED(sflag))
    914     0    stevel 	struct asycom	*asy;
    915     0    stevel 	struct asyncline *async;
    916     0    stevel 	int		mcr;
    917     0    stevel 	int		unit;
    918     0    stevel 	int 		len;
    919     0    stevel 	struct termios 	*termiosp;
    920     0    stevel 
    921     0    stevel #ifdef DEBUG
    922     0    stevel 	if (asydebug & ASY_DEBUG_CLOSE)
    923     0    stevel 		printf("open\n");
    924     0    stevel #endif
    925     0    stevel 	unit = UNIT(*dev);
    926     0    stevel 	if (unit > max_asy_instance)
    927     0    stevel 		return (ENXIO);		/* unit not configured */
    928     0    stevel 
    929     0    stevel 	async = (struct asyncline *)ddi_get_soft_state(su_asyncline, unit);
    930     0    stevel 	if (async == NULL)
    931     0    stevel 		return (ENXIO);
    932     0    stevel 
    933     0    stevel 	asy = async->async_common;
    934     0    stevel 	if (asy == NULL)
    935     0    stevel 		return (ENXIO);		/* device not found by autoconfig */
    936     0    stevel 
    937     0    stevel 	mutex_enter(asy->asy_excl);
    938     0    stevel 	asy->asy_priv = (caddr_t)async;
    939     0    stevel 
    940     0    stevel again:
    941     0    stevel 	mutex_enter(asy->asy_excl_hi);
    942     0    stevel 	/*
    943     0    stevel 	 * Block waiting for carrier to come up, unless this is a no-delay open.
    944     0    stevel 	 */
    945     0    stevel 	if (!(async->async_flags & ASYNC_ISOPEN)) {
    946     0    stevel 		/*
    947     0    stevel 		 * If this port is for a RSC console or control
    948     0    stevel 		 * use the following termio info
    949     0    stevel 		 */
    950     0    stevel 		if (asy->asy_rsc_console || asy->asy_rsc_control) {
    951     0    stevel 			async->async_ttycommon.t_cflag = CIBAUDEXT | CBAUDEXT |
    952     0    stevel 			    (B115200 & CBAUD);
    953     0    stevel 			async->async_ttycommon.t_cflag |= ((B115200 << IBSHIFT)
    954     0    stevel 			    & CIBAUD);
    955     0    stevel 			async->async_ttycommon.t_cflag |= CS8 | CREAD | CLOCAL;
    956     0    stevel 		} else if (asy->asy_lom_console) {
    957     0    stevel 			async->async_ttycommon.t_cflag = B9600 & CBAUD;
    958     0    stevel 			async->async_ttycommon.t_cflag |= ((B9600 << IBSHIFT)
    959     0    stevel 			    & CIBAUD);
    960     0    stevel 			async->async_ttycommon.t_cflag |= CS8 | CREAD | CLOCAL;
    961     0    stevel 		} else {
    962     0    stevel 
    963     0    stevel 			/*
    964     0    stevel 			 * Set the default termios settings (cflag).
    965     0    stevel 			 * Others are set in ldterm.  Release the spin
    966     0    stevel 			 * mutex as we can block here, reaquire before
    967     0    stevel 			 * calling asy_program.
    968     0    stevel 			 */
    969     0    stevel 			mutex_exit(asy->asy_excl_hi);
    970     0    stevel 			if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(),
    971     0    stevel 			    0, "ttymodes", (caddr_t)&termiosp, &len)
    972     0    stevel 			    == DDI_PROP_SUCCESS &&
    973     0    stevel 			    len == sizeof (struct termios)) {
    974     0    stevel 				async->async_ttycommon.t_cflag =
    975     0    stevel 				    termiosp->c_cflag;
    976     0    stevel 				kmem_free(termiosp, len);
    977     0    stevel 			} else {
    978     0    stevel 				cmn_err(CE_WARN,
    979     0    stevel 					"su: couldn't get ttymodes property!");
    980     0    stevel 			}
    981     0    stevel 			mutex_enter(asy->asy_excl_hi);
    982     0    stevel 		}
    983     0    stevel 		async->async_ttycommon.t_iflag = 0;
    984     0    stevel 		async->async_ttycommon.t_iocpending = NULL;
    985     0    stevel 		async->async_ttycommon.t_size.ws_row = 0;
    986     0    stevel 		async->async_ttycommon.t_size.ws_col = 0;
    987     0    stevel 		async->async_ttycommon.t_size.ws_xpixel = 0;
    988     0    stevel 		async->async_ttycommon.t_size.ws_ypixel = 0;
    989     0    stevel 		async->async_dev = *dev;
    990     0    stevel 		async->async_wbufcid = 0;
    991     0    stevel 
    992     0    stevel 		async->async_startc = CSTART;
    993     0    stevel 		async->async_stopc = CSTOP;
    994     0    stevel 		(void) asy_program(asy, ASY_INIT);
    995     0    stevel 	} else if ((async->async_ttycommon.t_flags & TS_XCLUDE) &&
    996  5973  zk194757 	    secpolicy_excl_open(cr) != 0) {
    997     0    stevel 		mutex_exit(asy->asy_excl_hi);
    998     0    stevel 		mutex_exit(asy->asy_excl);
    999     0    stevel 		return (EBUSY);
   1000     0    stevel 	} else if ((*dev & OUTLINE) && !(async->async_flags & ASYNC_OUT)) {
   1001     0    stevel 		mutex_exit(asy->asy_excl_hi);
   1002     0    stevel 		mutex_exit(asy->asy_excl);
   1003     0    stevel 		return (EBUSY);
   1004     0    stevel 	}
   1005     0    stevel 
   1006     0    stevel 	if (*dev & OUTLINE)
   1007     0    stevel 		async->async_flags |= ASYNC_OUT;
   1008     0    stevel 
   1009     0    stevel 	/* Raise DTR on every open */
   1010     0    stevel 	mcr = INB(MCR);
   1011     0    stevel 	OUTB(MCR, mcr|DTR);
   1012     0    stevel 
   1013     0    stevel 	/*
   1014     0    stevel 	 * Check carrier.
   1015     0    stevel 	 */
   1016     0    stevel 	if (asy->asy_flags & ASY_IGNORE_CD)
   1017     0    stevel 		async->async_ttycommon.t_flags |= TS_SOFTCAR;
   1018     0    stevel 	if ((async->async_ttycommon.t_flags & TS_SOFTCAR) ||
   1019  5973  zk194757 	    (INB(MSR) & DCD))
   1020     0    stevel 		async->async_flags |= ASYNC_CARR_ON;
   1021     0    stevel 	else
   1022     0    stevel 		async->async_flags &= ~ASYNC_CARR_ON;
   1023     0    stevel 	mutex_exit(asy->asy_excl_hi);
   1024     0    stevel 
   1025     0    stevel 	/*
   1026     0    stevel 	 * If FNDELAY and FNONBLOCK are clear, block until carrier up.
   1027     0    stevel 	 * Quit on interrupt.
   1028     0    stevel 	 */
   1029     0    stevel 	if (!(flag & (FNDELAY|FNONBLOCK)) &&
   1030  5973  zk194757 	    !(async->async_ttycommon.t_cflag & CLOCAL)) {
   1031     0    stevel 		if (!(async->async_flags & (ASYNC_CARR_ON|ASYNC_OUT)) ||
   1032  5973  zk194757 		    ((async->async_flags & ASYNC_OUT) &&
   1033  5973  zk194757 		    !(*dev & OUTLINE))) {
   1034  5973  zk194757 				async->async_flags |= ASYNC_WOPEN;
   1035  5973  zk194757 				if (cv_wait_sig(&async->async_flags_cv,
   1036  5973  zk194757 				    asy->asy_excl) == 0) {
   1037  5973  zk194757 					async->async_flags &= ~ASYNC_WOPEN;
   1038  5973  zk194757 					mutex_exit(asy->asy_excl);
   1039  5973  zk194757 					return (EINTR);
   1040  5973  zk194757 				}
   1041     0    stevel 				async->async_flags &= ~ASYNC_WOPEN;
   1042  5973  zk194757 				goto again;
   1043     0    stevel 		}
   1044     0    stevel 	} else if ((async->async_flags & ASYNC_OUT) && !(*dev & OUTLINE)) {
   1045  5973  zk194757 		mutex_exit(asy->asy_excl);
   1046  5973  zk194757 		return (EBUSY);
   1047     0    stevel 	}
   1048     0    stevel 
   1049     0    stevel 	if (asy->suspended) {
   1050     0    stevel 		mutex_exit(asy->asy_excl);
   1051     0    stevel 		(void) ddi_dev_is_needed(asy->asy_dip, 0, 1);
   1052     0    stevel 		mutex_enter(asy->asy_excl);
   1053     0    stevel 	}
   1054     0    stevel 
   1055     0    stevel 	async->async_ttycommon.t_readq = rq;
   1056     0    stevel 	async->async_ttycommon.t_writeq = WR(rq);
   1057     0    stevel 	rq->q_ptr = WR(rq)->q_ptr = (caddr_t)async;
   1058     0    stevel 	mutex_exit(asy->asy_excl);
   1059     0    stevel 	qprocson(rq);
   1060     0    stevel 	async->async_flags |= ASYNC_ISOPEN;
   1061     0    stevel 	async->async_polltid = 0;
   1062     0    stevel 	return (0);
   1063     0    stevel }
   1064     0    stevel 
   1065     0    stevel static void
   1066     0    stevel async_progress_check(void *arg)
   1067     0    stevel {
   1068     0    stevel 	struct asyncline *async = arg;
   1069     0    stevel 	struct asycom	 *asy = async->async_common;
   1070     0    stevel 	mblk_t *bp;
   1071     0    stevel 
   1072     0    stevel 	/*
   1073     0    stevel 	 * We define "progress" as either waiting on a timed break or delay, or
   1074     0    stevel 	 * having had at least one transmitter interrupt.  If none of these are
   1075     0    stevel 	 * true, then just terminate the output and wake up that close thread.
   1076     0    stevel 	 */
   1077     0    stevel 	mutex_enter(asy->asy_excl);
   1078     0    stevel 	mutex_enter(asy->asy_excl_hi);
   1079     0    stevel 	if (!(async->async_flags & (ASYNC_BREAK|ASYNC_DELAY|ASYNC_PROGRESS))) {
   1080     0    stevel 		async->async_ocnt = 0;
   1081     0    stevel 		async->async_flags &= ~ASYNC_BUSY;
   1082     0    stevel 		async->async_timer = 0;
   1083     0    stevel 		bp = async->async_xmitblk;
   1084     0    stevel 		async->async_xmitblk = NULL;
   1085     0    stevel 		mutex_exit(asy->asy_excl_hi);
   1086     0    stevel 		if (bp != NULL)
   1087     0    stevel 			freeb(bp);
   1088     0    stevel 		/*
   1089     0    stevel 		 * Since this timer is running, we know that we're in exit(2).
   1090     0    stevel 		 * That means that the user can't possibly be waiting on any
   1091     0    stevel 		 * valid ioctl(2) completion anymore, and we should just flush
   1092     0    stevel 		 * everything.
   1093     0    stevel 		 */
   1094     0    stevel 		flushq(async->async_ttycommon.t_writeq, FLUSHALL);
   1095     0    stevel 		cv_broadcast(&async->async_flags_cv);
   1096     0    stevel 	} else {
   1097     0    stevel 		async->async_flags &= ~ASYNC_PROGRESS;
   1098     0    stevel 		async->async_timer = timeout(async_progress_check, async,
   1099     0    stevel 		    drv_usectohz(su_drain_check));
   1100     0    stevel 		mutex_exit(asy->asy_excl_hi);
   1101     0    stevel 	}
   1102     0    stevel 	mutex_exit(asy->asy_excl);
   1103     0    stevel }
   1104     0    stevel 
   1105     0    stevel /*
   1106     0    stevel  * Close routine.
   1107     0    stevel  */
   1108     0    stevel static int
   1109     0    stevel asyclose(queue_t *q, int flag)
   1110     0    stevel {
   1111     0    stevel 	struct asyncline *async;
   1112     0    stevel 	struct asycom	 *asy;
   1113     0    stevel 	int icr, lcr;
   1114     0    stevel 	int		nohupcl;
   1115     0    stevel 
   1116     0    stevel 
   1117     0    stevel #ifdef DEBUG
   1118     0    stevel 	if (asydebug & ASY_DEBUG_CLOSE)
   1119     0    stevel 		printf("close\n");
   1120     0    stevel #endif
   1121     0    stevel 	async = q->q_ptr;
   1122     0    stevel 	ASSERT(async != NULL);
   1123     0    stevel 	asy = async->async_common;
   1124     0    stevel 
   1125     0    stevel 	/* get the nohupcl OBP property of this device */
   1126     0    stevel 	nohupcl = ddi_getprop(DDI_DEV_T_ANY, asy->asy_dip, DDI_PROP_DONTPASS,
   1127     0    stevel 	    "nohupcl", 0);
   1128     0    stevel 
   1129     0    stevel 	mutex_enter(asy->asy_excl);
   1130     0    stevel 	async->async_flags |= ASYNC_CLOSING;
   1131     0    stevel 
   1132     0    stevel 	/*
   1133     0    stevel 	 * Turn off PPS handling early to avoid events occuring during
   1134     0    stevel 	 * close.  Also reset the DCD edge monitoring bit.
   1135     0    stevel 	 */
   1136     0    stevel 	mutex_enter(asy->asy_excl_hi);
   1137     0    stevel 	asy->asy_flags &= ~(ASY_PPS | ASY_PPS_EDGE);
   1138     0    stevel 	mutex_exit(asy->asy_excl_hi);
   1139     0    stevel 
   1140     0    stevel 	/*
   1141     0    stevel 	 * There are two flavors of break -- timed (M_BREAK or TCSBRK) and
   1142     0    stevel 	 * untimed (TIOCSBRK).  For the timed case, these are enqueued on our
   1143     0    stevel 	 * write queue and there's a timer running, so we don't have to worry
   1144     0    stevel 	 * about them.  For the untimed case, though, the user obviously made a
   1145     0    stevel 	 * mistake, because these are handled immediately.  We'll terminate the
   1146     0    stevel 	 * break now and honor his implicit request by discarding the rest of
   1147     0    stevel 	 * the data.
   1148     0    stevel 	 */
   1149     0    stevel 	if (!(async->async_flags & ASYNC_BREAK)) {
   1150     0    stevel 		mutex_enter(asy->asy_excl_hi);
   1151     0    stevel 		lcr = INB(LCR);
   1152     0    stevel 		if (lcr & SETBREAK) {
   1153     0    stevel 			OUTB(LCR, (lcr & ~SETBREAK));
   1154     0    stevel 		}
   1155     0    stevel 		mutex_exit(asy->asy_excl_hi);
   1156     0    stevel 		if (lcr & SETBREAK)
   1157     0    stevel 			goto nodrain;
   1158     0    stevel 	}
   1159     0    stevel 
   1160     0    stevel 	/*
   1161     0    stevel 	 * If the user told us not to delay the close ("non-blocking"), then
   1162     0    stevel 	 * don't bother trying to drain.
   1163     0    stevel 	 *
   1164     0    stevel 	 * If the user did M_STOP (ASYNC_STOPPED), there's no hope of ever
   1165     0    stevel 	 * getting an M_START (since these messages aren't enqueued), and the
   1166     0    stevel 	 * only other way to clear the stop condition is by loss of DCD, which
   1167     0    stevel 	 * would discard the queue data.  Thus, we drop the output data if
   1168     0    stevel 	 * ASYNC_STOPPED is set.
   1169     0    stevel 	 */
   1170     0    stevel 	if ((flag & (FNDELAY|FNONBLOCK)) ||
   1171     0    stevel 	    (async->async_flags & ASYNC_STOPPED)) {
   1172     0    stevel 		goto nodrain;
   1173     0    stevel 	}
   1174     0    stevel 
   1175     0    stevel 	/*
   1176     0    stevel 	 * If there's any pending output, then we have to try to drain it.
   1177     0    stevel 	 * There are two main cases to be handled:
   1178     0    stevel 	 *	- called by close(2): need to drain until done or until
   1179     0    stevel 	 *	  a signal is received.  No timeout.
   1180     0    stevel 	 *	- called by exit(2): need to drain while making progress
   1181     0    stevel 	 *	  or until a timeout occurs.  No signals.
   1182     0    stevel 	 *
   1183     0    stevel 	 * If we can't rely on receiving a signal to get us out of a hung
   1184     0    stevel 	 * session, then we have to use a timer.  In this case, we set a timer
   1185     0    stevel 	 * to check for progress in sending the output data -- all that we ask
   1186     0    stevel 	 * (at each interval) is that there's been some progress made.  Since
   1187     0    stevel 	 * the interrupt routine grabs buffers from the write queue, we can't
   1188     0    stevel 	 * trust async_ocnt.  Instead, we use a flag.
   1189     0    stevel 	 *
   1190     0    stevel 	 * Note that loss of carrier will cause the output queue to be flushed,
   1191     0    stevel 	 * and we'll wake up again and finish normally.
   1192     0    stevel 	 */
   1193     0    stevel 	if (!ddi_can_receive_sig() && su_drain_check != 0) {
   1194     0    stevel 		async->async_flags &= ~ASYNC_PROGRESS;
   1195     0    stevel 		async->async_timer = timeout(async_progress_check, async,
   1196     0    stevel 		    drv_usectohz(su_drain_check));
   1197     0    stevel 	}
   1198     0    stevel 
   1199     0    stevel 	while (async->async_ocnt > 0 ||
   1200     0    stevel 	    async->async_ttycommon.t_writeq->q_first != NULL ||
   1201     0    stevel 	    (async->async_flags & (ASYNC_BUSY|ASYNC_BREAK|ASYNC_DELAY))) {
   1202     0    stevel 		if (cv_wait_sig(&async->async_flags_cv, asy->asy_excl) == 0)
   1203     0    stevel 			break;
   1204     0    stevel 	}
   1205     0    stevel 	if (async->async_timer != 0) {
   1206     0    stevel 		(void) untimeout(async->async_timer);
   1207     0    stevel 		async->async_timer = 0;
   1208     0    stevel 	}
   1209     0    stevel 
   1210     0    stevel nodrain:
   1211     0    stevel 	mutex_enter(asy->asy_excl_hi);
   1212     0    stevel 
   1213     0    stevel 	/* turn off the loopback mode */
   1214     0    stevel 	if ((async->async_dev != rconsdev) &&
   1215     0    stevel 	    (async->async_dev != kbddev) &&
   1216     0    stevel 	    (async->async_dev != stdindev)) {
   1217     0    stevel 		OUTB(MCR, INB(MCR) & ~ ASY_LOOP);
   1218     0    stevel 	}
   1219     0    stevel 
   1220     0    stevel 	async->async_ocnt = 0;
   1221     0    stevel 	if (async->async_xmitblk != NULL)
   1222     0    stevel 		freeb(async->async_xmitblk);
   1223     0    stevel 	async->async_xmitblk = NULL;
   1224     0    stevel 
   1225     0    stevel 	/*
   1226     0    stevel 	 * If the "nohupcl" OBP property is set for this device, do
   1227     0    stevel 	 * not turn off DTR and RTS no matter what.  Otherwise, if the
   1228     0    stevel 	 * line has HUPCL set or is incompletely opened, turn off DTR
   1229     0    stevel 	 * and RTS to fix the modem line.
   1230     0    stevel 	 */
   1231     0    stevel 	if (!nohupcl && ((async->async_ttycommon.t_cflag & HUPCL) ||
   1232     0    stevel 	    (async->async_flags & ASYNC_WOPEN))) {
   1233     0    stevel 		/* turn off DTR, RTS but NOT interrupt to 386 */
   1234     0    stevel 		OUTB(MCR, OUT2);
   1235     0    stevel 		mutex_exit(asy->asy_excl_hi);
   1236     0    stevel 		/*
   1237     0    stevel 		 * Don't let an interrupt in the middle of close
   1238     0    stevel 		 * bounce us back to the top; just continue closing
   1239     0    stevel 		 * as if nothing had happened.
   1240     0    stevel 		 */
   1241     0    stevel 		if (cv_wait_sig(&lbolt_cv, asy->asy_excl) == 0)
   1242     0    stevel 			goto out;
   1243     0    stevel 		mutex_enter(asy->asy_excl_hi);
   1244     0    stevel 	}
   1245     0    stevel 
   1246     0    stevel 	/*
   1247     0    stevel 	 * If nobody's using it now, turn off receiver interrupts.
   1248     0    stevel 	 */
   1249     0    stevel 	if ((async->async_flags & (ASYNC_WOPEN|ASYNC_ISOPEN)) == 0) {
   1250     0    stevel 		icr = INB(ICR);
   1251     0    stevel 		OUTB(ICR, (icr & ~RIEN));
   1252     0    stevel 	}
   1253     0    stevel 	mutex_exit(asy->asy_excl_hi);
   1254     0    stevel out:
   1255     0    stevel 	/*
   1256     0    stevel 	 * Clear out device state.
   1257     0    stevel 	 */
   1258     0    stevel 	async->async_flags = 0;
   1259     0    stevel 	ttycommon_close(&async->async_ttycommon);
   1260     0    stevel 	cv_broadcast(&async->async_flags_cv);
   1261     0    stevel 
   1262     0    stevel 	/*
   1263     0    stevel 	 * Clear ASY_DOINGSOFT and ASY_NEEDSOFT in case we were in
   1264     0    stevel 	 * async_softint or an interrupt was pending when the process
   1265     0    stevel 	 * using the port exited.
   1266     0    stevel 	 */
   1267     0    stevel 	asy->asy_flags &= ~ASY_DOINGSOFT & ~ASY_NEEDSOFT;
   1268     0    stevel 
   1269     0    stevel 	/*
   1270     0    stevel 	 * Cancel outstanding "bufcall" request.
   1271     0    stevel 	 */
   1272     0    stevel 	if (async->async_wbufcid) {
   1273     0    stevel 		unbufcall(async->async_wbufcid);
   1274     0    stevel 		async->async_wbufcid = 0;
   1275     0    stevel 	}
   1276     0    stevel 
   1277     0    stevel 	/*
   1278     0    stevel 	 * If inperim is true, it means the port is closing while there's
   1279     0    stevel 	 * a pending software interrupt.  async_flags has been zeroed out,
   1280     0    stevel 	 * so this instance of leaveq() needs to be called before we call
   1281     0    stevel 	 * qprocsoff() to disable services on the q.  If inperim is false,
   1282     0    stevel 	 * leaveq() has already been called or we're not in a perimeter.
   1283     0    stevel 	 */
   1284     0    stevel 	if (asy->inperim == B_TRUE) {
   1285     0    stevel 		asy->inperim = B_FALSE;
   1286     0    stevel 		mutex_exit(asy->asy_excl);
   1287     0    stevel 		leaveq(q);
   1288     0    stevel 	} else {
   1289     0    stevel 		mutex_exit(asy->asy_excl);
   1290     0    stevel 	}
   1291     0    stevel 
   1292     0    stevel 	/* Note that qprocsoff can't be done until after interrupts are off */
   1293     0    stevel 	qprocsoff(q);
   1294     0    stevel 	q->q_ptr = WR(q)->q_ptr = NULL;
   1295     0    stevel 	async->async_ttycommon.t_readq = NULL;
   1296     0    stevel 	async->async_ttycommon.t_writeq = NULL;
   1297     0    stevel 
   1298     0    stevel 	return (0);
   1299     0    stevel }
   1300     0    stevel 
   1301     0    stevel /*
   1302     0    stevel  * Checks to see if the serial port is still transmitting
   1303     0    stevel  * characters.  It returns true when there are characters
   1304     0    stevel  * queued to transmit,  when the holding register contains
   1305     0    stevel  * a byte, or when the shifting register still contains
   1306     0    stevel  * data to send.
   1307     0    stevel  *
   1308     0    stevel  */
   1309     0    stevel static boolean_t
   1310     0    stevel asy_isbusy(struct asycom *asy)
   1311     0    stevel {
   1312     0    stevel 	struct asyncline *async;
   1313     0    stevel 
   1314     0    stevel #ifdef DEBUG
   1315     0    stevel 	if (asydebug & ASY_DEBUG_EOT)
   1316     0    stevel 		printf("isbusy\n");
   1317     0    stevel #endif
   1318     0    stevel 	async = (struct asyncline *)asy->asy_priv;
   1319     0    stevel 	ASSERT(mutex_owned(asy->asy_excl));
   1320     0    stevel 	ASSERT(mutex_owned(asy->asy_excl_hi));
   1321     0    stevel 	return ((async->async_ocnt > 0) ||
   1322  5973  zk194757 	    ((INB(LSR) & XSRE) == 0));
   1323     0    stevel }
   1324     0    stevel 
   1325     0    stevel /*
   1326     0    stevel  * Program the ASY port. Most of the async operation is based on the values
   1327     0    stevel  * of 'c_iflag' and 'c_cflag'.
   1328     0    stevel  */
   1329     0    stevel static int
   1330     0    stevel asy_program(struct asycom *asy, int mode)
   1331     0    stevel {
   1332     0    stevel 	struct asyncline *async;
   1333     0    stevel 	int baudrate, c_flag;
   1334     0    stevel 	int icr, lcr;
   1335     0    stevel 	int ocflags;
   1336     0    stevel 	int error = 0;
   1337     0    stevel 
   1338     0    stevel 	ASSERT(mutex_owned(asy->asy_excl));
   1339     0    stevel 	ASSERT(mutex_owned(asy->asy_excl_hi));
   1340     0    stevel 
   1341     0    stevel #ifdef DEBUG
   1342     0    stevel 	if (asydebug & ASY_DEBUG_PROCS)
   1343     0    stevel 		printf("program\n");
   1344     0    stevel #endif
   1345     0    stevel 	async = (struct asyncline *)asy->asy_priv;
   1346     0    stevel 
   1347     0    stevel 	baudrate = async->async_ttycommon.t_cflag & CBAUD;
   1348     0    stevel 	if (async->async_ttycommon.t_cflag & CBAUDEXT)
   1349     0    stevel 		baudrate += 16;
   1350     0    stevel 
   1351     0    stevel 	/* Limit baudrate so it can't index out of baudtable */
   1352     0    stevel 	if (baudrate >= N_SU_SPEEDS) baudrate = B9600;
   1353     0    stevel 
   1354     0    stevel 	/*
   1355     0    stevel 	 * If baud rate requested is greater than the speed cap
   1356     0    stevel 	 * or is an unsupported baud rate then reset t_cflag baud
   1357     0    stevel 	 * to the last valid baud rate.  If this is the initial
   1358     0    stevel 	 * pass through asy_program then set it to 9600.
   1359     0    stevel 	 */
   1360     0    stevel 	if (((baudrate > 0) && (asyspdtab[baudrate] == 0)) ||
   1361     0    stevel 	    (baudtable[baudrate] > asy->asy_speed_cap)) {
   1362     0    stevel 		async->async_ttycommon.t_cflag &= ~CBAUD & ~CBAUDEXT &
   1363     0    stevel 		    ~CIBAUD & ~CIBAUDEXT;
   1364     0    stevel 		if (mode == ASY_INIT) {
   1365     0    stevel 			async->async_ttycommon.t_cflag |= B9600;
   1366  2422   kc28005 			async->async_ttycommon.t_cflag |= B9600 << IBSHIFT;
   1367     0    stevel 			baudrate = B9600;
   1368     0    stevel 		} else {
   1369     0    stevel 			async->async_ttycommon.t_cflag |=
   1370     0    stevel 			    (asy->asy_ocflags & (CBAUD | CBAUDEXT |
   1371     0    stevel 			    CIBAUD | CIBAUDEXT));
   1372  2422   kc28005 			error = EINVAL;
   1373  2422   kc28005 			goto end;
   1374     0    stevel 		}
   1375     0    stevel 	}
   1376     0    stevel 
   1377  2422   kc28005 	/*
   1378  2422   kc28005 	 * If CIBAUD and CIBAUDEXT are zero then we should set them to
   1379  2422   kc28005 	 * the equivelant output baud bits.  Else, if CIBAUD and CIBAUDEXT
   1380  2422   kc28005 	 * don't match CBAUD and CBAUDEXT respectively then we should
   1381  2422   kc28005 	 * notify the requestor that we do not support split speeds.
   1382  2422   kc28005 	 */
   1383  2422   kc28005 	if ((async->async_ttycommon.t_cflag  & (CIBAUD|CIBAUDEXT)) == 0) {
   1384  2422   kc28005 		async->async_ttycommon.t_cflag |=
   1385  2422   kc28005 		    (async->async_ttycommon.t_cflag & CBAUD) << IBSHIFT;
   1386  2422   kc28005 		if (async->async_ttycommon.t_cflag & CBAUDEXT)
   1387  5973  zk194757 			async->async_ttycommon.t_cflag |= CIBAUDEXT;
   1388  2422   kc28005 	} else {
   1389  2422   kc28005 		if ((((async->async_ttycommon.t_cflag & CBAUD) << IBSHIFT) !=
   1390  2422   kc28005 		    (async->async_ttycommon.t_cflag & CIBAUD)) ||
   1391  2422   kc28005 		    !(((async->async_ttycommon.t_cflag & (CBAUDEXT |
   1392  2422   kc28005 		    CIBAUDEXT)) == (CBAUDEXT | CIBAUDEXT)) ||
   1393  2422   kc28005 		    ((async->async_ttycommon.t_cflag & (CBAUDEXT |
   1394  2422   kc28005 		    CIBAUDEXT)) == 0))) {
   1395  2422   kc28005 			async->async_ttycommon.t_cflag &= ~CBAUD & ~CBAUDEXT &
   1396  2422   kc28005 			    ~CIBAUD & ~CIBAUDEXT;
   1397     0    stevel 			async->async_ttycommon.t_cflag |=
   1398  2422   kc28005 			    (asy->asy_ocflags & (CBAUD | CBAUDEXT |
   1399  2422   kc28005 			    CIBAUD | CIBAUDEXT));
   1400  2422   kc28005 			error = EINVAL;
   1401  2422   kc28005 			goto end;
   1402     0    stevel 		}
   1403     0    stevel 	}
   1404     0    stevel 
   1405     0    stevel 	c_flag = async->async_ttycommon.t_cflag &
   1406     0    stevel 	    (CLOCAL | CREAD | CSTOPB | CSIZE | PARENB | PARODD | CBAUD |
   1407     0    stevel 	    CBAUDEXT | CIBAUD | CIBAUDEXT);
   1408  2119   anovick 
   1409  2119   anovick 	/* disable interrupts, see EXAR bug */
   1410  2877   anovick 	if (asy->asy_hwtype == ASY16C554D)
   1411  2877   anovick 		OUTB(SPR, 0);
   1412  2119   anovick 	OUTB(ICR, 0);
   1413     0    stevel 
   1414     0    stevel 	ocflags = asy->asy_ocflags;
   1415     0    stevel 
   1416     0    stevel 	/* flush/reset the status registers */
   1417     0    stevel 	if (mode == ASY_INIT) {
   1418     0    stevel 		(void) INB(DAT);
   1419     0    stevel 		(void) INB(ISR);
   1420     0    stevel 		(void) INB(LSR);
   1421     0    stevel 		(void) INB(MSR);
   1422     0    stevel 	}
   1423     0    stevel 
   1424     0    stevel 	if (ocflags != (c_flag & ~CLOCAL) || mode == ASY_INIT) {
   1425     0    stevel 		/* Set line control */
   1426     0    stevel 		lcr = INB(LCR);
   1427     0    stevel 		lcr &= ~(WLS0|WLS1|STB|PEN|EPS);
   1428     0    stevel 
   1429     0    stevel 		if (c_flag & CSTOPB)
   1430     0    stevel 			lcr |= STB;	/* 2 stop bits */
   1431     0    stevel 
   1432     0    stevel 		if (c_flag & PARENB)
   1433     0    stevel 			lcr |= PEN;
   1434     0    stevel 
   1435     0    stevel 		if ((c_flag & PARODD) == 0)
   1436     0    stevel 			lcr |= EPS;
   1437     0    stevel 
   1438     0    stevel 		switch (c_flag & CSIZE) {
   1439     0    stevel 		case CS5:
   1440     0    stevel 			lcr |= BITS5;
   1441     0    stevel 			break;
   1442     0    stevel 		case CS6:
   1443     0    stevel 			lcr |= BITS6;
   1444     0    stevel 			break;
   1445     0    stevel 		case CS7:
   1446     0    stevel 			lcr |= BITS7;
   1447     0    stevel 			break;
   1448     0    stevel 		case CS8:
   1449     0    stevel 			lcr |= BITS8;
   1450     0    stevel 			break;
   1451     0    stevel 		}
   1452     0    stevel 
   1453     0    stevel 		/* set the baud rate when the rate is NOT B0 */
   1454     0    stevel 		if (baudrate != 0) {
   1455     0    stevel 			OUTB(LCR, DLAB);
   1456     0    stevel 			OUTB(DAT, (asyspdtab[baudrate] *
   1457  5973  zk194757 			    asy->asy_baud_divisor_factor) & 0xff);
   1458     0    stevel 			OUTB(ICR, ((asyspdtab[baudrate] *
   1459  5973  zk194757 			    asy->asy_baud_divisor_factor) >> 8) & 0xff);
   1460     0    stevel 		}
   1461     0    stevel 		/* set the line control modes */
   1462     0    stevel 		OUTB(LCR, lcr);
   1463     0    stevel 
   1464     0    stevel 		/*
   1465     0    stevel 		 * if transitioning from CREAD off to CREAD on,
   1466     0    stevel 		 * flush the FIFO buffer if we have one.
   1467     0    stevel 		 */
   1468     0    stevel 		if ((ocflags & CREAD) == 0 && (c_flag & CREAD)) {
   1469     0    stevel 			if (asy->asy_use_fifo == FIFO_ON) {
   1470     0    stevel 				OUTB(FIFOR, FIFO_ON | FIFODMA | FIFORXFLSH |
   1471     0    stevel 				    (asy->asy_trig_level & 0xff));
   1472     0    stevel 			}
   1473     0    stevel 		}
   1474     0    stevel 
   1475     0    stevel 		/* remember the new cflags */
   1476     0    stevel 		asy->asy_ocflags = c_flag & ~CLOCAL;
   1477     0    stevel 	}
   1478     0    stevel 
   1479     0    stevel 	/* whether or not CLOCAL is set, modify the modem control lines */
   1480     0    stevel 	if (baudrate == 0)
   1481     0    stevel 		/* B0 has been issued, lower DTR */
   1482     0    stevel 		OUTB(MCR, RTS|OUT2);
   1483     0    stevel 	else
   1484     0    stevel 		/* raise DTR */
   1485     0    stevel 		OUTB(MCR, DTR|RTS|OUT2);
   1486     0    stevel 
   1487     0    stevel 	/*
   1488     0    stevel 	 * Call the modem status interrupt handler to check for the carrier
   1489     0    stevel 	 * in case CLOCAL was turned off after the carrier came on.
   1490     0    stevel 	 * (Note: Modem status interrupt is not enabled if CLOCAL is ON.)
   1491     0    stevel 	 */
   1492     0    stevel 	async_msint(asy);
   1493     0    stevel 
   1494     0    stevel 	/* Set interrupt control */
   1495     0    stevel 	if ((c_flag & CLOCAL) && !(async->async_ttycommon.t_cflag & CRTSCTS))
   1496     0    stevel 		/*
   1497     0    stevel 		 * direct-wired line ignores DCD, so we don't enable modem
   1498     0    stevel 		 * status interrupts.
   1499     0    stevel 		 */
   1500     0    stevel 		icr = (TIEN | SIEN);
   1501     0    stevel 	else
   1502     0    stevel 		icr = (TIEN | SIEN | MIEN);
   1503     0    stevel 
   1504     0    stevel 	if (c_flag & CREAD)
   1505     0    stevel 		icr |= RIEN;
   1506     0    stevel 
   1507     0    stevel 	OUTB(ICR, icr);
   1508     0    stevel end:
   1509     0    stevel 	return (error);
   1510     0    stevel }
   1511     0    stevel 
   1512     0    stevel /*
   1513  5973  zk194757  * Polled mode support -- all functions called with interrupts
   1514  5973  zk194757  * disabled.
   1515  5973  zk194757  */
   1516  5973  zk194757 
   1517  5973  zk194757 static void
   1518  5973  zk194757 asyputchar(cons_polledio_arg_t arg, uchar_t c)
   1519  5973  zk194757 {
   1520  5973  zk194757 	struct asycom *asy = (struct asycom *)arg;
   1521  5973  zk194757 
   1522  5973  zk194757 	/*
   1523  5973  zk194757 	 * If we see a line feed make sure to also
   1524  5973  zk194757 	 * put out a carriage return.
   1525  5973  zk194757 	 */
   1526  5973  zk194757 	if (c == '\n')
   1527  5973  zk194757 		asyputchar(arg, '\r');
   1528  5973  zk194757 
   1529  5973  zk194757 	while ((INB(LSR) & XHRE) == 0) {
   1530  5973  zk194757 		/* wait for the transmission to complete */
   1531  5973  zk194757 		drv_usecwait(10);
   1532  5973  zk194757 	}
   1533  5973  zk194757 
   1534  5973  zk194757 	/* ouput the character */
   1535  5973  zk194757 	OUTB(DAT, c);
   1536  5973  zk194757 }
   1537  5973  zk194757 
   1538  5973  zk194757 /*
   1539  5973  zk194757  * Determines if there is a character avaialable for
   1540  5973  zk194757  * reading.
   1541  5973  zk194757  */
   1542  5973  zk194757 static boolean_t
   1543  5973  zk194757 asyischar(cons_polledio_arg_t arg)
   1544  5973  zk194757 {
   1545  5973  zk194757 	struct asycom *asy = (struct asycom *)arg;
   1546  5973  zk194757 	return ((INB(LSR) & RCA) != 0);
   1547  5973  zk194757 }
   1548  5973  zk194757 
   1549  5973  zk194757 static int
   1550  5973  zk194757 asygetchar(cons_polledio_arg_t arg)
   1551  5973  zk194757 {
   1552  5973  zk194757 	struct asycom *asy = (struct asycom *)arg;
   1553  5973  zk194757 
   1554  5973  zk194757 	/*
   1555  5973  zk194757 	 * Spin waiting for a character to be
   1556  5973  zk194757 	 * available to read.
   1557  5973  zk194757 	 */
   1558  5973  zk194757 	while (!asyischar(arg))
   1559  5973  zk194757 		drv_usecwait(10);
   1560  5973  zk194757 
   1561  5973  zk194757 	return (INB(DAT));
   1562  5973  zk194757 }
   1563  5973  zk194757 
   1564  5973  zk194757 /*
   1565  5973  zk194757  * Called when machine is transitioning to polled mode
   1566  5973  zk194757  */
   1567  5973  zk194757 static void
   1568  5973  zk194757 asy_polled_enter(cons_polledio_arg_t arg)
   1569  5973  zk194757 {
   1570  5973  zk194757 	struct asycom *asy = (struct asycom *)arg;
   1571  5973  zk194757 
   1572  5973  zk194757 	mutex_enter(asy->asy_excl);
   1573  5973  zk194757 	mutex_enter(asy->asy_excl_hi);
   1574  5973  zk194757 
   1575  5973  zk194757 	/*
   1576  5973  zk194757 	 * If this is the first time that asy_polled_enter()
   1577  5973  zk194757 	 * has been called, during this transition request,
   1578  5973  zk194757 	 * save the ICR. Clear the software interrupt
   1579  5973  zk194757 	 * flags since we won't be able to handle these when
   1580  5973  zk194757 	 * we are in polled mode.
   1581  5973  zk194757 	 */
   1582  5973  zk194757 	if (!asy->polled_enter) {
   1583  5973  zk194757 		asy->polled_enter = B_TRUE;
   1584  5973  zk194757 		asy->polled_icr = INB(ICR);
   1585  5973  zk194757 
   1586  5973  zk194757 		/* Disable HW interrupts */
   1587  5973  zk194757 		if (asy->asy_hwtype == ASY16C554D)
   1588  5973  zk194757 			OUTB(SPR, 0);
   1589  5973  zk194757 		OUTB(ICR, 0);
   1590  5973  zk194757 
   1591  5973  zk194757 		asy->asy_flags &= ~ASY_DOINGSOFT & ~ASY_NEEDSOFT;
   1592  5973  zk194757 	}
   1593  5973  zk194757 	mutex_exit(asy->asy_excl_hi);
   1594  5973  zk194757 	mutex_exit(asy->asy_excl);
   1595  5973  zk194757 }
   1596  5973  zk194757 
   1597  5973  zk194757 /*
   1598  5973  zk194757  * Called when machine is transitioning from polled mode.
   1599  5973  zk194757  */
   1600  5973  zk194757 static void
   1601  5973  zk194757 asy_polled_exit(cons_polledio_arg_t arg)
   1602  5973  zk194757 {
   1603  5973  zk194757 	struct asycom *asy = (struct asycom *)arg;
   1604  5973  zk194757 
   1605  5973  zk194757 	mutex_enter(asy->asy_excl);
   1606  5973  zk194757 	mutex_enter(asy->asy_excl_hi);
   1607  5973  zk194757 
   1608  5973  zk194757 	/* Restore the ICR */
   1609  5973  zk194757 	OUTB(ICR, asy->polled_icr);
   1610  5973  zk194757 
   1611  5973  zk194757 	/*
   1612  5973  zk194757 	 * We have finished this polled IO transition.
   1613  5973  zk194757 	 * Set polled_enter to B_FALSE to note this.
   1614  5973  zk194757 	 */
   1615  5973  zk194757 	asy->polled_enter = B_FALSE;
   1616  5973  zk194757 	mutex_exit(asy->asy_excl_hi);
   1617  5973  zk194757 	mutex_exit(asy->asy_excl);
   1618  5973  zk194757 }
   1619  5973  zk194757 
   1620  5973  zk194757 /*
   1621     0    stevel  * asyintr() is the High Level Interrupt Handler.
   1622     0    stevel  *
   1623     0    stevel  * There are four different interrupt types indexed by ISR register values:
   1624     0    stevel  *		0: modem
   1625     0    stevel  *		1: Tx holding register is empty, ready for next char
   1626     0    stevel  *		2: Rx register now holds a char to be picked up
   1627     0    stevel  *		3: error or break on line
   1628     0    stevel  * This routine checks the Bit 0 (interrupt-not-pending) to determine if
   1629     0    stevel  * the interrupt is from this port.
   1630     0    stevel  */
   1631     0    stevel uint_t
   1632     0    stevel asyintr(caddr_t argasy)
   1633     0    stevel {
   1634     0    stevel 	struct asycom		*asy = (struct asycom *)argasy;
   1635     0    stevel 	struct asyncline	*async;
   1636     0    stevel 	int			ret_status = DDI_INTR_UNCLAIMED;
   1637     0    stevel 	uchar_t			interrupt_id, lsr;
   1638     0    stevel 
   1639     0    stevel 	interrupt_id = INB(ISR) & 0x0F;
   1640     0    stevel 	async = (struct asyncline *)asy->asy_priv;
   1641     0    stevel 	if ((async == NULL) ||
   1642  5973  zk194757 	    !(async->async_flags & (ASYNC_ISOPEN|ASYNC_WOPEN))) {
   1643     0    stevel 		if (interrupt_id & NOINTERRUPT)  {
   1644     0    stevel 			return (DDI_INTR_UNCLAIMED);
   1645     0    stevel 		} else {
   1646     0    stevel 			lsr = INB(LSR);
   1647     0    stevel 			if ((lsr & BRKDET) &&
   1648     0    stevel 			    ((abort_enable == KIOCABORTENABLE) &&
   1649     0    stevel 			    (async->async_dev == rconsdev)))
   1650     0    stevel 				abort_sequence_enter((char *)NULL);
   1651     0    stevel 			else {
   1652     0    stevel 				/* reset line status */
   1653     0    stevel 				(void) INB(LSR);
   1654     0    stevel 				/* discard any data */
   1655     0    stevel 				(void) INB(DAT);
   1656     0    stevel 				/* reset modem status */
   1657     0    stevel 				(void) INB(MSR);
   1658     0    stevel 				return (DDI_INTR_CLAIMED);
   1659     0    stevel 			}
   1660     0    stevel 		}
   1661     0    stevel 	}
   1662     0    stevel 	/*
   1663     0    stevel 	 * Spurious interrupts happen in this driver
   1664     0    stevel 	 * because of the transmission on serial port not handled
   1665     0    stevel 	 * properly.
   1666     0    stevel 	 *
   1667     0    stevel 	 * The reasons for Spurious interrupts are:
   1668     0    stevel 	 *    1. There is a path in async_nstart which transmits
   1669     0    stevel 	 *	 characters without going through interrupt services routine
   1670     0    stevel 	 *	 which causes spurious interrupts to happen.
   1671     0    stevel 	 *    2. In the async_txint more than one character is sent
   1672     0    stevel 	 *	 in one interrupt service.
   1673     0    stevel 	 *    3. In async_rxint more than one characters are received in
   1674     0    stevel 	 *	 in one interrupt service.
   1675     0    stevel 	 *
   1676     0    stevel 	 * Hence we have flags to indicate that such scenerio has happened.
   1677     0    stevel 	 * and claim only such interrupts and others we donot claim it
   1678     0    stevel 	 * as it could be a indicator of some hardware problem.
   1679     0    stevel 	 *
   1680     0    stevel 	 */
   1681     0    stevel 	if (interrupt_id & NOINTERRUPT) {
   1682     0    stevel 		mutex_enter(asy->asy_excl_hi);
   1683     0    stevel 		if ((asy->asy_xmit_count > 1) ||
   1684  5973  zk194757 		    (asy->asy_out_of_band_xmit > 0) ||
   1685  5973  zk194757 		    (asy->asy_rx_count > 1)) {
   1686     0    stevel 			asy->asy_xmit_count = 0;
   1687     0    stevel 			asy->asy_out_of_band_xmit = 0;
   1688     0    stevel 			asy->asy_rx_count = 0;
   1689     0    stevel 			mutex_exit(asy->asy_excl_hi);
   1690     0    stevel 			return (DDI_INTR_CLAIMED);
   1691     0    stevel 		} else {
   1692     0    stevel 			mutex_exit(asy->asy_excl_hi);
   1693     0    stevel 			return (DDI_INTR_UNCLAIMED);
   1694     0    stevel 		}
   1695     0    stevel 	}
   1696     0    stevel 	ret_status = DDI_INTR_CLAIMED;
   1697     0    stevel 	mutex_enter(asy->asy_excl_hi);
   1698     0    stevel 	if (asy->asy_hwtype == ASY82510)
   1699     0    stevel 		OUTB(ISR, 0x00); /* set bank 0 */
   1700     0    stevel 
   1701     0    stevel #ifdef DEBUG
   1702     0    stevel 	if (asydebug & ASY_DEBUG_INTR)
   1703     0    stevel 		prom_printf("l");
   1704     0    stevel #endif
   1705     0    stevel 	lsr = INB(LSR);
   1706     0    stevel 	switch (interrupt_id) {
   1707     0    stevel 	case RxRDY:
   1708     0    stevel 	case RSTATUS:
   1709     0    stevel 	case FFTMOUT:
   1710     0    stevel 		/* receiver interrupt or receiver errors */
   1711     0    stevel 		async_rxint(asy, lsr);
   1712     0    stevel 		break;
   1713     0    stevel 	case TxRDY:
   1714     0    stevel 		/* transmit interrupt */
   1715     0    stevel 		async_txint(asy, lsr);
   1716     0    stevel 		break;
   1717     0    stevel 	case MSTATUS:
   1718     0    stevel 		/* modem status interrupt */
   1719     0    stevel 		async_msint(asy);
   1720     0    stevel 		break;
   1721     0    stevel 	}
   1722     0    stevel 	mutex_exit(asy->asy_excl_hi);
   1723     0    stevel 	return (ret_status);
   1724     0    stevel }
   1725     0    stevel 
   1726     0    stevel /*
   1727     0    stevel  * Transmitter interrupt service routine.
   1728     0    stevel  * If there is more data to transmit in the current pseudo-DMA block,
   1729     0    stevel  * send the next character if output is not stopped or draining.
   1730     0    stevel  * Otherwise, queue up a soft interrupt.
   1731     0    stevel  *
   1732     0    stevel  * XXX -  Needs review for HW FIFOs.
   1733     0    stevel  */
   1734     0    stevel static void
   1735     0    stevel async_txint(struct asycom *asy, uchar_t lsr)
   1736     0    stevel {
   1737     0    stevel 	struct asyncline *async = (struct asyncline *)asy->asy_priv;
   1738     0    stevel 	int		fifo_len;
   1739     0    stevel 	int		xmit_progress;
   1740     0    stevel 
   1741     0    stevel 	asycheckflowcontrol_hw(asy);
   1742     0    stevel 
   1743     0    stevel 	/*
   1744     0    stevel 	 * If ASYNC_BREAK has been set, return to asyintr()'s context to
   1745     0    stevel 	 * claim the interrupt without performing any action.
   1746     0    stevel 	 */
   1747     0    stevel 	if (async->async_flags & ASYNC_BREAK)
   1748     0    stevel 		return;
   1749     0    stevel 
   1750     0    stevel 	fifo_len = asy->asy_fifo_buf; /* with FIFO buffers */
   1751     0    stevel 
   1752     0    stevel 	/*
   1753     0    stevel 	 * Check for flow control and do the needed action.
   1754     0    stevel 	 */
   1755     0    stevel 	if (asycheckflowcontrol_sw(asy)) {
   1756     0    stevel 		return;
   1757     0    stevel 	}
   1758     0    stevel 
   1759     0    stevel 	if (async->async_ocnt > 0 &&
   1760     0    stevel 	    !(async->async_flags & (ASYNC_HW_OUT_FLW|ASYNC_STOPPED))) {
   1761     0    stevel 		xmit_progress = 0;
   1762     0    stevel 		while (fifo_len > 0 && async->async_ocnt > 0) {
   1763     0    stevel 			if (lsr & XHRE) {
   1764     0    stevel 				OUTB(DAT, *async->async_optr++);
   1765     0    stevel 				fifo_len--;
   1766     0    stevel 				async->async_ocnt--;
   1767     0    stevel 				xmit_progress++;
   1768     0    stevel 			}
   1769     0    stevel 			/*
   1770     0    stevel 			 * Reading the lsr, (moved reading at the end of
   1771     0    stevel 			 * while loop) as already we have read once at
   1772     0    stevel 			 * the beginning of interrupt service
   1773     0    stevel 			 */
   1774     0    stevel 			lsr = INB(LSR);
   1775     0    stevel 		}
   1776     0    stevel 		asy->asy_xmit_count = xmit_progress;
   1777     0    stevel 		if (xmit_progress > 0)
   1778     0    stevel 			async->async_flags |= ASYNC_PROGRESS;
   1779     0    stevel 	}
   1780     0    stevel 
   1781     0    stevel 	if (fifo_len == 0) {
   1782     0    stevel 		return;
   1783     0    stevel 	}
   1784     0    stevel 
   1785     0    stevel 
   1786     0    stevel 	ASYSETSOFT(asy);
   1787     0    stevel }
   1788     0    stevel 
   1789     0    stevel /*
   1790     0    stevel  * Receiver interrupt: RxRDY interrupt, FIFO timeout interrupt or receive
   1791     0    stevel  * error interrupt.
   1792     0    stevel  * Try to put the character into the circular buffer for this line; if it
   1793     0    stevel  * overflows, indicate a circular buffer overrun. If this port is always
   1794     0    stevel  * to be serviced immediately, or the character is a STOP character, or
   1795     0    stevel  * more than 15 characters have arrived, queue up a soft interrupt to
   1796     0    stevel  * drain the circular buffer.
   1797     0    stevel  * XXX - needs review for hw FIFOs support.
   1798     0    stevel  */
   1799     0    stevel 
   1800     0    stevel static void
   1801     0    stevel async_rxint(struct asycom *asy, uchar_t lsr)
   1802     0    stevel {
   1803     0    stevel 	struct asyncline *async = (struct asyncline *)asy->asy_priv;
   1804     0    stevel 	uchar_t c = 0;
   1805     0    stevel 	uint_t s = 0, needsoft = 0;
   1806     0    stevel 	register tty_common_t *tp;
   1807     0    stevel 
   1808     0    stevel 	tp = &async->async_ttycommon;
   1809     0    stevel 	if (!(tp->t_cflag & CREAD)) {
   1810     0    stevel 		if (lsr & (RCA|PARERR|FRMERR|BRKDET|OVRRUN)) {
   1811     0    stevel 			(void) (INB(DAT) & 0xff);
   1812     0    stevel 		}
   1813     0    stevel 		return; /* line is not open for read? */
   1814     0    stevel 	}
   1815     0    stevel 	asy->asy_rx_count = 0;
   1816     0    stevel 	while (lsr & (RCA|PARERR|FRMERR|BRKDET|OVRRUN)) {
   1817     0    stevel 		c = 0;
   1818     0    stevel 		s = 0;
   1819     0    stevel 		asy->asy_rx_count++;
   1820     0    stevel 		if (lsr & RCA) {
   1821     0    stevel 			c = INB(DAT) & 0xff;
   1822     0    stevel 			/*
   1823     0    stevel 			 * Even a single character is received
   1824     0    stevel 			 * we need Soft interrupt to pass it to
   1825     0    stevel 			 * higher layers.
   1826     0    stevel 			 */
   1827     0    stevel 			needsoft = 1;
   1828     0    stevel 		}
   1829     0    stevel 
   1830     0    stevel 		/* Check for character break sequence */
   1831     0    stevel 		if ((abort_enable == KIOCABORTALTERNATE) &&
   1832     0    stevel 		    (async->async_dev == rconsdev)) {
   1833     0    stevel 			if (abort_charseq_recognize(c))
   1834     0    stevel 				abort_sequence_enter((char *)NULL);
   1835     0    stevel 			}
   1836     0    stevel 
   1837     0    stevel 		/* Handle framing errors */
   1838     0    stevel 		if (lsr & (PARERR|FRMERR|BRKDET|OVRRUN)) {
   1839     0    stevel 			if (lsr & PARERR) {
   1840     0    stevel 				if (tp->t_iflag & INPCK) /* parity enabled */
   1841     0    stevel 					s |= PERROR;
   1842     0    stevel 			}
   1843     0    stevel 			if (lsr & (FRMERR|BRKDET))
   1844     0    stevel 				s |= FRERROR;
   1845     0    stevel 			if (lsr & OVRRUN) {
   1846     0    stevel 				async->async_hw_overrun = 1;
   1847     0    stevel 				s |= OVERRUN;
   1848     0    stevel 			}
   1849     0    stevel 		}
   1850     0    stevel 
   1851     0    stevel 		if (s == 0)
   1852     0    stevel 			if ((tp->t_iflag & PARMRK) &&
   1853  5973  zk194757 			    !(tp->t_iflag & (IGNPAR|ISTRIP)) &&
   1854  5973  zk194757 			    (c == 0377))
   1855     0    stevel 				if (RING_POK(async, 2)) {
   1856     0    stevel 					RING_PUT(async, 0377);
   1857     0    stevel 					RING_PUT(async, c);
   1858     0    stevel 				} else
   1859     0    stevel 					async->async_sw_overrun = 1;
   1860     0    stevel 			else
   1861     0    stevel 				if (RING_POK(async, 1))
   1862     0    stevel 					RING_PUT(async, c);
   1863     0    stevel 				else
   1864     0    stevel 					async->async_sw_overrun = 1;
   1865     0    stevel 		else
   1866     0    stevel 			if (s & FRERROR) { /* Handle framing errors */
   1867     0    stevel 				if (c == 0)  {
   1868     0    stevel 		/* Look for break on kbd, stdin, or rconsdev */
   1869     0    stevel 					if ((async->async_dev == kbddev) ||
   1870     0    stevel 					    ((async->async_dev == rconsdev) ||
   1871     0    stevel 					    (async->async_dev == stdindev)) &&
   1872     0    stevel 					    (abort_enable !=
   1873     0    stevel 					    KIOCABORTALTERNATE))
   1874     0    stevel 						abort_sequence_enter((char *)0);
   1875     0    stevel 					else
   1876     0    stevel 						async->async_break++;
   1877     0    stevel 				} else {
   1878     0    stevel 					if (RING_POK(async, 1))
   1879     0    stevel 						RING_MARK(async, c, s);
   1880     0    stevel 					else
   1881     0    stevel 						async->async_sw_overrun = 1;
   1882     0    stevel 				}
   1883     0    stevel 			} else  { /* Parity errors  handled by ldterm */
   1884     0    stevel 				if (RING_POK(async, 1))
   1885     0    stevel 					RING_MARK(async, c, s);
   1886     0    stevel 				else
   1887     0    stevel 					async->async_sw_overrun = 1;
   1888     0    stevel 			}
   1889     0    stevel 		lsr = INB(LSR);
   1890     0    stevel 		if (asy->asy_rx_count > 16) break;
   1891     0    stevel 	}
   1892     0    stevel 	/* Check whether there is a request for hw/sw inbound/input flow ctrl */
   1893     0    stevel 	if ((async->async_ttycommon.t_cflag & CRTSXOFF) ||
   1894  5973  zk194757 	    (async->async_ttycommon.t_iflag & IXOFF))
   1895     0    stevel 		if ((int)(RING_CNT(async)) > (RINGSIZE * 3)/4) {
   1896     0    stevel #ifdef DEBUG
   1897     0    stevel 			if (asydebug & ASY_DEBUG_HFLOW)
   1898     0    stevel 				printf("asy%d: hardware flow stop input.\n",
   1899  5973  zk194757 				    UNIT(async->async_dev));
   1900     0    stevel #endif
   1901     0    stevel 			async->async_flags |= ASYNC_HW_IN_FLOW;
   1902     0    stevel 			async->async_flowc = async->async_stopc;
   1903     0    stevel 			async->async_ringbuf_overflow = 1;
   1904     0    stevel 		}
   1905     0    stevel 
   1906     0    stevel 	if ((async->async_flags & ASYNC_SERVICEIMM) || needsoft ||
   1907  5973  zk194757 	    (RING_FRAC(async)) || (async->async_polltid == 0))
   1908     0    stevel 		ASYSETSOFT(asy);	/* need a soft interrupt */
   1909     0    stevel }
   1910     0    stevel 
   1911     0    stevel /*
   1912     0    stevel  * Interrupt on port: handle PPS event.  This function is only called
   1913     0    stevel  * for a port on which PPS event handling has been enabled.
   1914     0    stevel  */
   1915     0    stevel static void
   1916     0    stevel asy_ppsevent(struct asycom *asy, int msr)
   1917     0    stevel {
   1918     0    stevel 	if (asy->asy_flags & ASY_PPS_EDGE) {
   1919     0    stevel 		/* Have seen leading edge, now look for and record drop */
   1920     0    stevel 		if ((msr & DCD) == 0)
   1921     0    stevel 			asy->asy_flags &= ~ASY_PPS_EDGE;
   1922     0    stevel 		/*
   1923     0    stevel 		 * Waiting for leading edge, look for rise; stamp event and
   1924     0    stevel 		 * calibrate kernel clock.
   1925     0    stevel 		 */
   1926     0    stevel 	} else if (msr & DCD) {
   1927     0    stevel 		/*
   1928     0    stevel 		 * This code captures a timestamp at the designated
   1929     0    stevel 		 * transition of the PPS signal (DCD asserted).  The
   1930     0    stevel 		 * code provides a pointer to the timestamp, as well
   1931     0    stevel 		 * as the hardware counter value at the capture.
   1932     0    stevel 		 *
   1933     0    stevel 		 * Note: the kernel has nano based time values while
   1934     0    stevel 		 * NTP requires micro based, an in-line fast algorithm
   1935     0    stevel 		 * to convert nsec to usec is used here -- see hrt2ts()
   1936     0    stevel 		 * in common/os/timers.c for a full description.
   1937     0    stevel 		 */
   1938     0    stevel 		struct timeval *tvp = &asy_ppsev.tv;
   1939     0    stevel 		timestruc_t ts;
   1940     0    stevel 		long nsec, usec;
   1941     0    stevel 
   1942     0    stevel 		asy->asy_flags |= ASY_PPS_EDGE;
   1943     0    stevel 		gethrestime(&ts);
   1944     0    stevel 		nsec = ts.tv_nsec;
   1945     0    stevel 		usec = nsec + (nsec >> 2);
   1946     0    stevel 		usec = nsec + (usec >> 1);
   1947     0    stevel 		usec = nsec + (usec >> 2);
   1948     0    stevel 		usec = nsec + (usec >> 4);
   1949     0    stevel 		usec = nsec - (usec >> 3);
   1950     0    stevel 		usec = nsec + (usec >> 2);
   1951     0    stevel 		usec = nsec + (usec >> 3);
   1952     0    stevel 		usec = nsec + (usec >> 4);
   1953     0    stevel 		usec = nsec + (usec >> 1);
   1954     0    stevel 		usec = nsec + (usec >> 6);
   1955     0    stevel 		tvp->tv_usec = usec >> 10;
   1956     0    stevel 		tvp->tv_sec = ts.tv_sec;
   1957     0    stevel 
   1958     0    stevel 		++asy_ppsev.serial;
   1959     0    stevel 
   1960     0    stevel 		/*
   1961     0    stevel 		 * Because the kernel keeps a high-resolution time,
   1962     0    stevel 		 * pass the current highres timestamp in tvp and zero
   1963     0    stevel 		 * in usec.
   1964     0    stevel 		 */
   1965     0    stevel 		ddi_hardpps(tvp, 0);
   1966     0    stevel 	}
   1967     0    stevel }
   1968     0    stevel 
   1969     0    stevel /*
   1970     0    stevel  * Modem status interrupt.
   1971     0    stevel  *
   1972     0    stevel  * (Note: It is assumed that the MSR hasn't been read by asyintr().)
   1973     0    stevel  */
   1974     0    stevel 
   1975     0    stevel static void
   1976     0    stevel async_msint(struct asycom *asy)
   1977     0    stevel {
   1978     0    stevel 	struct asyncline *async = (struct asyncline *)asy->asy_priv;
   1979     0    stevel 	int msr;
   1980     0    stevel 
   1981     0    stevel 	msr = INB(MSR);	/* this resets the interrupt */
   1982     0    stevel 	asy->asy_cached_msr = msr;
   1983     0    stevel #ifdef DEBUG
   1984     0    stevel 	if (asydebug & ASY_DEBUG_STATE) {
   1985     0    stevel 		printf("   transition: %3s %3s %3s %3s\n"
   1986  5973  zk194757 		    "current state: %3s %3s %3s %3s\n",
   1987  5973  zk194757 		    (msr & DCTS) ? "CTS" : "   ",
   1988  5973  zk194757 		    (msr & DDSR) ? "DSR" : "   ",
   1989  5973  zk194757 		    (msr & DRI) ?  "RI " : "   ",
   1990  5973  zk194757 		    (msr & DDCD) ? "DCD" : "   ",
   1991  5973  zk194757 		    (msr & CTS) ?  "CTS" : "   ",
   1992  5973  zk194757 		    (msr & DSR) ?  "DSR" : "   ",
   1993  5973  zk194757 		    (msr & RI) ?   "RI " : "   ",
   1994  5973  zk194757 		    (msr & DCD) ?  "DCD" : "   ");
   1995     0    stevel 	}
   1996     0    stevel #endif
   1997     0    stevel 	if (async->async_ttycommon.t_cflag & CRTSCTS && !(msr & CTS)) {
   1998     0    stevel #ifdef DEBUG
   1999     0    stevel 		if (asydebug & ASY_DEBUG_HFLOW)
   2000     0    stevel 			printf("asy%d: hflow start\n",
   2001  5973  zk194757 			    UNIT(async->async_dev));
   2002     0    stevel #endif
   2003     0    stevel 		async->async_flags |= ASYNC_HW_OUT_FLW;
   2004     0    stevel 	}
   2005     0    stevel 	if (asy->asy_hwtype == ASY82510)
   2006     0    stevel 		OUTB(MSR, (msr & 0xF0));
   2007     0    stevel 
   2008     0    stevel 	/* Handle PPS event */
   2009     0    stevel 	if (asy->asy_flags & ASY_PPS)
   2010     0    stevel 		asy_ppsevent(asy, msr);
   2011     0    stevel 
   2012     0    stevel 	async->async_ext++;
   2013     0    stevel 	ASYSETSOFT(asy);
   2014     0    stevel }
   2015     0    stevel 
   2016     0    stevel /*
   2017     0    stevel  * Handle a second-stage interrupt.
   2018     0    stevel  */
   2019     0    stevel uint_t
   2020     0    stevel asysoftintr(caddr_t intarg)
   2021     0    stevel {
   2022     0    stevel 	struct asycom *asy = (struct asycom *)intarg;
   2023     0    stevel 	struct asyncline *async;
   2024     0    stevel 	int rv;
   2025     0    stevel 	int cc;
   2026     0    stevel 	/*
   2027     0    stevel 	 * Test and clear soft interrupt.
   2028     0    stevel 	 */
   2029     0    stevel 	mutex_enter(asy->asy_soft_lock);
   2030     0    stevel #ifdef DEBUG
   2031     0    stevel 	if (asydebug & ASY_DEBUG_PROCS)
   2032     0    stevel 		printf("softintr\n");
   2033     0    stevel #endif
   2034     0    stevel 	rv = asy->asysoftpend;
   2035     0    stevel 	if (rv != 0)
   2036     0    stevel 		asy->asysoftpend = 0;
   2037     0    stevel 	mutex_exit(asy->asy_soft_lock);
   2038     0    stevel 
   2039     0    stevel 	if (rv) {
   2040     0    stevel 		if (asy->asy_priv == NULL)
   2041     0    stevel 			return (rv);
   2042     0    stevel 		async = (struct asyncline *)asy->asy_priv;
   2043     0    stevel 		mutex_enter(asy->asy_excl_hi);
   2044     0    stevel 		if (asy->asy_flags & ASY_NEEDSOFT) {
   2045     0    stevel 			asy->asy_flags &= ~ASY_NEEDSOFT;
   2046     0    stevel 			mutex_exit(asy->asy_excl_hi);
   2047     0    stevel 			(void) async_softint(asy);
   2048     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2049     0    stevel 		}
   2050     0    stevel 		/*
   2051     0    stevel 		 * There are some instances where the softintr is not
   2052     0    stevel 		 * scheduled and hence not called. It so happened that makes
   2053     0    stevel 		 * the last few characters to be stuck in ringbuffer.
   2054     0    stevel 		 * Hence, call once again the  handler so that the last few
   2055     0    stevel 		 * characters are cleared.
   2056     0    stevel 		 */
   2057     0    stevel 		cc = RING_CNT(async);
   2058     0    stevel 		mutex_exit(asy->asy_excl_hi);
   2059     0    stevel 		if (cc > 0) {
   2060     0    stevel 			(void) async_softint(asy);
   2061     0    stevel 		}
   2062     0    stevel 	}
   2063     0    stevel 	return (rv);
   2064     0    stevel }
   2065     0    stevel 
   2066     0    stevel /*
   2067     0    stevel  * Handle a software interrupt.
   2068     0    stevel  */
   2069     0    stevel static int
   2070     0    stevel async_softint(struct asycom *asy)
   2071     0    stevel {
   2072     0    stevel 	struct asyncline *async = (struct asyncline *)asy->asy_priv;
   2073     0    stevel 	uint_t	cc;
   2074     0    stevel 	mblk_t	*bp;
   2075     0    stevel 	queue_t	*q;
   2076     0    stevel 	uchar_t	val;
   2077     0    stevel 	uchar_t	c;
   2078     0    stevel 	tty_common_t	*tp;
   2079     0    stevel 
   2080     0    stevel #ifdef DEBUG
   2081     0    stevel 	if (asydebug & ASY_DEBUG_PROCS)
   2082     0    stevel 		printf("process\n");
   2083     0    stevel #endif
   2084     0    stevel 	mutex_enter(asy->asy_excl);
   2085     0    stevel 	if (asy->asy_flags & ASY_DOINGSOFT) {
   2086     0    stevel 		mutex_exit(asy->asy_excl);
   2087     0    stevel 		return (0);
   2088     0    stevel 	}
   2089     0    stevel 	tp = &async->async_ttycommon;
   2090     0    stevel 	q = tp->t_readq;
   2091     0    stevel 	if (q != NULL) {
   2092     0    stevel 		mutex_exit(asy->asy_excl);
   2093     0    stevel 		enterq(q);
   2094     0    stevel 		mutex_enter(asy->asy_excl);
   2095     0    stevel 	}
   2096     0    stevel 	mutex_enter(asy->asy_excl_hi);
   2097     0    stevel 	asy->asy_flags |= ASY_DOINGSOFT;
   2098     0    stevel 
   2099     0    stevel 	if (INB(ICR) & MIEN)
   2100     0    stevel 		val = asy->asy_cached_msr & 0xFF;
   2101     0    stevel 	else
   2102     0    stevel 		val = INB(MSR) & 0xFF;
   2103     0    stevel 
   2104     0    stevel 	if (async->async_ttycommon.t_cflag & CRTSCTS) {
   2105     0    stevel 		if ((val & CTS) && (async->async_flags & ASYNC_HW_OUT_FLW)) {
   2106     0    stevel #ifdef DEBUG
   2107     0    stevel 			if (asydebug & ASY_DEBUG_HFLOW)
   2108     0    stevel 				printf("asy%d: hflow start\n",
   2109  5973  zk194757 				    UNIT(async->async_dev));
   2110     0    stevel #endif
   2111     0    stevel 			async->async_flags &= ~ASYNC_HW_OUT_FLW;
   2112     0    stevel 			mutex_exit(asy->asy_excl_hi);
   2113     0    stevel 			if (async->async_ocnt > 0) {
   2114     0    stevel 				mutex_enter(asy->asy_excl_hi);
   2115     0    stevel 				async_resume(async);
   2116     0    stevel 				mutex_exit(asy->asy_excl_hi);
   2117     0    stevel 			} else {
   2118     0    stevel 				async_start(async);
   2119     0    stevel 			}
   2120     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2121     0    stevel 		}
   2122     0    stevel 	}
   2123     0    stevel 	if (async->async_ext) {
   2124     0    stevel 		async->async_ext = 0;
   2125     0    stevel 		/* check for carrier up */
   2126     0    stevel 		if ((val & DCD) || (tp->t_flags & TS_SOFTCAR)) {
   2127     0    stevel 			/* carrier present */
   2128     0    stevel 			if ((async->async_flags & ASYNC_CARR_ON) == 0) {
   2129     0    stevel 				async->async_flags |= ASYNC_CARR_ON;
   2130     0    stevel 				mutex_exit(asy->asy_excl_hi);
   2131     0    stevel 				mutex_exit(asy->asy_excl);
   2132     0    stevel 				if (async->async_flags & ASYNC_ISOPEN)
   2133     0    stevel 					(void) putctl(q, M_UNHANGUP);
   2134     0    stevel 				cv_broadcast(&async->async_flags_cv);
   2135     0    stevel 				mutex_enter(asy->asy_excl);
   2136     0    stevel 				mutex_enter(asy->asy_excl_hi);
   2137     0    stevel 			}
   2138     0    stevel 		} else {
   2139     0    stevel 			if ((async->async_flags & ASYNC_CARR_ON) &&
   2140     0    stevel 			    !(tp->t_cflag & CLOCAL)) {
   2141     0    stevel 				int flushflag;
   2142     0    stevel 
   2143     0    stevel 				/*
   2144     0    stevel 				 * Carrier went away.
   2145     0    stevel 				 * Drop DTR, abort any output in
   2146     0    stevel 				 * progress, indicate that output is
   2147     0    stevel 				 * not stopped, and send a hangup
   2148     0    stevel 				 * notification upstream.
   2149     0    stevel 				 *
   2150     0    stevel 				 * If we're in the midst of close, then flush
   2151     0    stevel 				 * everything.  Don't leave stale ioctls lying
   2152     0    stevel 				 * about.
   2153     0    stevel 				 */
   2154     0    stevel 				val = INB(MCR);
   2155     0    stevel 				OUTB(MCR, (val & ~DTR));
   2156     0    stevel 				flushflag = (async->async_flags &
   2157     0    stevel 				    ASYNC_CLOSING) ? FLUSHALL : FLUSHDATA;
   2158  9957        An 				if (tp->t_writeq != NULL) {
   2159  9957        An 					flushq(tp->t_writeq, flushflag);
   2160  9957        An 				}
   2161     0    stevel 				if (async->async_xmitblk != NULL) {
   2162     0    stevel 					freeb(async->async_xmitblk);
   2163     0    stevel 					async->async_xmitblk = NULL;
   2164     0    stevel 				}
   2165     0    stevel 				if (async->async_flags & ASYNC_BUSY) {
   2166     0    stevel 					async->async_ocnt = 0;
   2167     0    stevel 					async->async_flags &= ~ASYNC_BUSY;
   2168     0    stevel 				}
   2169     0    stevel 				async->async_flags &= ~ASYNC_STOPPED;
   2170     0    stevel 				if (async->async_flags & ASYNC_ISOPEN) {
   2171     0    stevel 					mutex_exit(asy->asy_excl_hi);
   2172     0    stevel 					mutex_exit(asy->asy_excl);
   2173     0    stevel 					(void) putctl(q, M_HANGUP);
   2174     0    stevel 					mutex_enter(asy->asy_excl);
   2175     0    stevel 					mutex_enter(asy->asy_excl_hi);
   2176     0    stevel 				}
   2177  1815   rameshc 				async->async_flags &= ~ASYNC_CARR_ON;
   2178  1815   rameshc 				mutex_exit(asy->asy_excl_hi);
   2179  1815   rameshc 				cv_broadcast(&async->async_flags_cv);
   2180  1815   rameshc 				mutex_enter(asy->asy_excl_hi);
   2181     0    stevel 			}
   2182     0    stevel 		}
   2183     0    stevel 	}
   2184     0    stevel 
   2185     0    stevel 	/*
   2186     0    stevel 	 * If data has been added to the circular buffer, remove
   2187     0    stevel 	 * it from the buffer, and send it up the stream if there's
   2188     0    stevel 	 * somebody listening. Try to do it 16 bytes at a time. If we
   2189     0    stevel 	 * have more than 16 bytes to move, move 16 byte chunks and
   2190     0    stevel 	 * leave the rest for next time around (maybe it will grow).
   2191     0    stevel 	 */
   2192     0    stevel 	if (!(async->async_flags & ASYNC_ISOPEN)) {
   2193     0    stevel 		RING_INIT(async);
   2194     0    stevel 		goto rv;
   2195     0    stevel 	}
   2196     0    stevel 	if ((cc = RING_CNT(async)) == 0) {
   2197     0    stevel 		goto rv;
   2198     0    stevel 	}
   2199     0    stevel 	mutex_exit(asy->asy_excl_hi);
   2200     0    stevel 
   2201     0    stevel 	if (!canput(q)) {
   2202     0    stevel 		if ((async->async_flags & ASYNC_HW_IN_FLOW) == 0) {
   2203     0    stevel #ifdef DEBUG
   2204     0    stevel 			if (!(asydebug & ASY_DEBUG_HFLOW)) {
   2205     0    stevel 				printf("asy%d: hflow stop input.\n",
   2206  5973  zk194757 				    UNIT(async->async_dev));
   2207     0    stevel 				if (canputnext(q))
   2208     0    stevel 					printf("asy%d: next queue is "
   2209  5973  zk194757 					    "ready\n",
   2210  5973  zk194757 					    UNIT(async->async_dev));
   2211     0    stevel 			}
   2212     0    stevel #endif
   2213     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2214     0    stevel 			async->async_flags |= ASYNC_HW_IN_FLOW;
   2215     0    stevel 			async->async_flowc = async->async_stopc;
   2216     0    stevel 		} else mutex_enter(asy->asy_excl_hi);
   2217     0    stevel 		goto rv;
   2218     0    stevel 	}
   2219     0    stevel 
   2220     0    stevel 	if (async->async_ringbuf_overflow) {
   2221     0    stevel 		if ((async->async_flags & ASYNC_HW_IN_FLOW) &&
   2222  5973  zk194757 		    ((int)(RING_CNT(async)) < (RINGSIZE/4))) {
   2223     0    stevel #ifdef DEBUG
   2224     0    stevel 			if (asydebug & ASY_DEBUG_HFLOW)
   2225     0    stevel 				printf("asy%d: hflow start input.\n",
   2226  5973  zk194757 				    UNIT(async->async_dev));
   2227     0    stevel #endif
   2228     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2229     0    stevel 			async->async_flags &= ~ASYNC_HW_IN_FLOW;
   2230     0    stevel 			async->async_flowc = async->async_startc;
   2231     0    stevel 			async->async_ringbuf_overflow = 0;
   2232     0    stevel 			goto rv;
   2233     0    stevel 		}
   2234     0    stevel 	}
   2235     0    stevel #ifdef DEBUG
   2236     0    stevel 	if (asydebug & ASY_DEBUG_INPUT)
   2237     0    stevel 		printf("asy%d: %d char(s) in queue.\n",
   2238  5973  zk194757 		    UNIT(async->async_dev), cc);
   2239     0    stevel #endif
   2240     0    stevel 	/*
   2241     0    stevel 	 * Before you pull the characters from the RING BUF
   2242     0    stevel 	 * Check whether you can put into the queue again
   2243     0    stevel 	 */
   2244     0    stevel 	if ((!canputnext(q)) || (!canput(q))) {
   2245     0    stevel 		mutex_enter(asy->asy_excl_hi);
   2246     0    stevel 		if ((async->async_flags & ASYNC_HW_IN_FLOW) == 0) {
   2247     0    stevel 			async->async_flags |= ASYNC_HW_IN_FLOW;
   2248     0    stevel 			async->async_flowc = async->async_stopc;
   2249     0    stevel 			async->async_queue_full = 1;
   2250     0    stevel 		}
   2251     0    stevel 		goto rv;
   2252     0    stevel 	}
   2253     0    stevel 	mutex_enter(asy->asy_excl_hi);
   2254     0    stevel 	if (async->async_queue_full) {
   2255     0    stevel 		/*
   2256     0    stevel 		 * Last time the Stream queue didnot allow
   2257     0    stevel 		 * now it allows so, relax, the flow control
   2258     0    stevel 		 */
   2259     0    stevel 		if (async->async_flags & ASYNC_HW_IN_FLOW) {
   2260     0    stevel 			async->async_flags &= ~ASYNC_HW_IN_FLOW;
   2261     0    stevel 			async->async_queue_full = 0;
   2262     0    stevel 			async->async_flowc = async->async_startc;
   2263     0    stevel 			goto rv;
   2264     0    stevel 		} else
   2265     0    stevel 			async->async_queue_full = 0;
   2266     0    stevel 	}
   2267     0    stevel 	mutex_exit(asy->asy_excl_hi);
   2268     0    stevel 	if (!(bp = allocb(cc, BPRI_MED))) {
   2269     0    stevel 		ttycommon_qfull(&async->async_ttycommon, q);
   2270     0    stevel 		mutex_enter(asy->asy_excl_hi);
   2271     0    stevel 		goto rv;
   2272     0    stevel 	}
   2273     0    stevel 	mutex_enter(asy->asy_excl_hi);
   2274     0    stevel 	do {
   2275     0    stevel 		if (RING_ERR(async, S_ERRORS)) {
   2276     0    stevel 			RING_UNMARK(async);
   2277     0    stevel 			c = RING_GET(async);
   2278     0    stevel 			break;
   2279     0    stevel 		} else {
   2280     0    stevel 			*bp->b_wptr++ = RING_GET(async);
   2281     0    stevel 		}
   2282     0    stevel 	} while (--cc);
   2283     0    stevel 
   2284     0    stevel 	mutex_exit(asy->asy_excl_hi);
   2285     0    stevel 	mutex_exit(asy->asy_excl);
   2286     0    stevel 	if (bp->b_wptr > bp->b_rptr) {
   2287     0    stevel 		if (!canputnext(q)) {
   2288     0    stevel 			if (!canput(q)) {
   2289     0    stevel 				/*
   2290     0    stevel 				 * Even after taking all precautions that
   2291     0    stevel 				 * Still we are unable to queue, then we
   2292     0    stevel 				 * cannot do anything, just drop the block
   2293     0    stevel 				 */
   2294     0    stevel 				cmn_err(CE_NOTE,
   2295  5973  zk194757 				    "su%d: local queue full\n",
   2296  5973  zk194757 				    UNIT(async->async_dev));
   2297     0    stevel 				freemsg(bp);
   2298     0    stevel 				mutex_enter(asy->asy_excl_hi);
   2299     0    stevel 				if ((async->async_flags &
   2300  5973  zk194757 				    ASYNC_HW_IN_FLOW) == 0) {
   2301     0    stevel 					async->async_flags |=
   2302  5973  zk194757 					    ASYNC_HW_IN_FLOW;
   2303     0    stevel 					async->async_flowc =
   2304  5973  zk194757 					    async->async_stopc;
   2305     0    stevel 					async->async_queue_full = 1;
   2306     0    stevel 				}
   2307     0    stevel 				mutex_exit(asy->asy_excl_hi);
   2308     0    stevel 			} else {
   2309     0    stevel 				(void) putq(q, bp);
   2310     0    stevel 			}
   2311     0    stevel 		} else {
   2312     0    stevel 			putnext(q, bp);
   2313     0    stevel 		}
   2314     0    stevel 	} else {
   2315     0    stevel 		freemsg(bp);
   2316     0    stevel 	}
   2317     0    stevel 	/*
   2318     0    stevel 	 * If we have a parity error, then send
   2319     0    stevel 	 * up an M_BREAK with the "bad"
   2320     0    stevel 	 * character as an argument. Let ldterm
   2321     0    stevel 	 * figure out what to do with the error.
   2322     0    stevel 	 */
   2323     0    stevel 	if (cc)
   2324     0    stevel 		(void) putctl1(q, M_BREAK, c);
   2325     0    stevel 	mutex_enter(asy->asy_excl);
   2326     0    stevel 	mutex_enter(asy->asy_excl_hi);
   2327     0    stevel rv:
   2328     0    stevel 	/*
   2329     0    stevel 	 * If a transmission has finished, indicate that it's finished,
   2330     0    stevel 	 * and start that line up again.
   2331     0    stevel 	 */
   2332     0    stevel 	if (async->async_break) {
   2333     0    stevel 		async->async_break = 0;
   2334     0    stevel 		if (async->async_flags & ASYNC_ISOPEN) {
   2335     0    stevel 			mutex_exit(asy->asy_excl_hi);
   2336     0    stevel 			mutex_exit(asy->asy_excl);
   2337     0    stevel 			(void) putctl(q, M_BREAK);
   2338     0    stevel 			mutex_enter(asy->asy_excl);
   2339     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2340     0    stevel 		}
   2341     0    stevel 	}
   2342     0    stevel 	if ((async->async_ocnt <= 0 && (async->async_flags & ASYNC_BUSY)) ||
   2343   859   kc28005 	    (async->async_flowc != '\0')) {
   2344     0    stevel 		async->async_flags &= ~ASYNC_BUSY;
   2345     0    stevel 		mutex_exit(asy->asy_excl_hi);
   2346     0    stevel 		if (async->async_xmitblk)
   2347     0    stevel 			freeb(async->async_xmitblk);
   2348     0    stevel 		async->async_xmitblk = NULL;
   2349     0    stevel 		if (async->async_flags & ASYNC_ISOPEN) {
   2350     0    stevel 			asy->inperim = B_TRUE;
   2351     0    stevel 			mutex_exit(asy->asy_excl);
   2352     0    stevel 			enterq(async->async_ttycommon.t_writeq);
   2353     0    stevel 			mutex_enter(asy->asy_excl);
   2354     0    stevel 		}
   2355     0    stevel 		async_start(async);
   2356     0    stevel 		/*
   2357     0    stevel 		 * We need to check for inperim and ISOPEN due to
   2358     0    stevel 		 * multi-threading implications; it's possible to close the
   2359     0    stevel 		 * port and nullify async_flags while completing the software
   2360     0    stevel 		 * interrupt.  If the port is closed, leaveq() will have already
   2361     0    stevel 		 * been called.  We don't want to call it twice.
   2362     0    stevel 		 */
   2363     0    stevel 		if ((asy->inperim) && (async->async_flags & ASYNC_ISOPEN)) {
   2364     0    stevel 			mutex_exit(asy->asy_excl);
   2365     0    stevel 			leaveq(async->async_ttycommon.t_writeq);
   2366     0    stevel 			mutex_enter(asy->asy_excl);
   2367     0    stevel 			asy->inperim = B_FALSE;
   2368     0    stevel 		}
   2369     0    stevel 		if (!(async->async_flags & ASYNC_BUSY))
   2370     0    stevel 			cv_broadcast(&async->async_flags_cv);
   2371     0    stevel 		mutex_enter(asy->asy_excl_hi);
   2372     0    stevel 	}
   2373     0    stevel 	/*
   2374     0    stevel 	 * A note about these overrun bits: all they do is *tell* someone
   2375     0    stevel 	 * about an error- They do not track multiple errors. In fact,
   2376     0    stevel 	 * you could consider them latched register bits if you like.
   2377     0    stevel 	 * We are only interested in printing the error message once for
   2378     0    stevel 	 * any cluster of overrun errrors.
   2379     0    stevel 	 */
   2380     0    stevel 	if (async->async_hw_overrun) {
   2381     0    stevel 		if (async->async_flags & ASYNC_ISOPEN) {
   2382     0    stevel 			if (su_log > 0) {
   2383     0    stevel 				mutex_exit(asy->asy_excl_hi);
   2384     0    stevel 				mutex_exit(asy->asy_excl);
   2385     0    stevel 				cmn_err(CE_NOTE, "su%d: silo overflow\n",
   2386     0    stevel 				    UNIT(async->async_dev));
   2387     0    stevel 				mutex_enter(asy->asy_excl);
   2388     0    stevel 				mutex_enter(asy->asy_excl_hi);
   2389     0    stevel 			}
   2390     0    stevel 			INC64_KSTAT(asy, siloover);
   2391     0    stevel 		}
   2392     0    stevel 		async->async_hw_overrun = 0;
   2393     0    stevel 	}
   2394     0    stevel 	if (async->async_sw_overrun) {
   2395     0    stevel 		if (async->async_flags & ASYNC_ISOPEN) {
   2396     0    stevel 			if (su_log > 0) {
   2397     0    stevel 				mutex_exit(asy->asy_excl_hi);
   2398     0    stevel 				mutex_exit(asy->asy_excl);
   2399     0    stevel 				cmn_err(CE_NOTE, "su%d: ring buffer overflow\n",
   2400     0    stevel 				    UNIT(async->async_dev));
   2401     0    stevel 				mutex_enter(asy->asy_excl);
   2402     0    stevel 				mutex_enter(asy->asy_excl_hi);
   2403     0    stevel 			}
   2404     0    stevel 			INC64_KSTAT(asy, ringover);
   2405     0    stevel 		}
   2406     0    stevel 		async->async_sw_overrun = 0;
   2407     0    stevel 	}
   2408     0    stevel 	asy->asy_flags &= ~ASY_DOINGSOFT;
   2409     0    stevel 	mutex_exit(asy->asy_excl_hi);
   2410     0    stevel 	mutex_exit(asy->asy_excl);
   2411     0    stevel 	if (q != NULL)
   2412     0    stevel 		leaveq(q);
   2413     0    stevel 	return (0);
   2414     0    stevel }
   2415     0    stevel 
   2416     0    stevel /*
   2417     0    stevel  * Restart output on a line after a delay or break timer expired.
   2418     0    stevel  */
   2419     0    stevel static void
   2420     0    stevel async_restart(void *arg)
   2421     0    stevel {
   2422     0    stevel 	struct asyncline *async = arg;
   2423     0    stevel 	struct asycom *asy = async->async_common;
   2424     0    stevel 	queue_t *q;
   2425     0    stevel 	uchar_t lcr;
   2426     0    stevel 
   2427     0    stevel 	/*
   2428     0    stevel 	 * If break timer expired, turn off the break bit.
   2429     0    stevel 	 */
   2430     0    stevel #ifdef DEBUG
   2431     0    stevel 	if (asydebug & ASY_DEBUG_PROCS)
   2432     0    stevel 		printf("restart\n");
   2433     0    stevel #endif
   2434     0    stevel 	mutex_enter(asy->asy_excl);
   2435     0    stevel 	if (async->async_flags & ASYNC_BREAK) {
   2436  1434   kc28005 		unsigned int rate;
   2437  1434   kc28005 
   2438     0    stevel 		mutex_enter(asy->asy_excl_hi);
   2439     0    stevel 		lcr = INB(LCR);
   2440     0    stevel 		OUTB(LCR, (lcr & ~SETBREAK));
   2441  1434   kc28005 
   2442  1434   kc28005 		/*
   2443  1434   kc28005 		 * Go to sleep for the time it takes for at least one
   2444  1434   kc28005 		 * stop bit to be received by the device at the other
   2445  1434   kc28005 		 * end of the line as stated in the RS-232 specification.
   2446  1434   kc28005 		 * The wait period is equal to:
   2447  1434   kc28005 		 * 2 clock cycles * (1 MICROSEC / baud rate)
   2448  1434   kc28005 		 */
   2449  1434   kc28005 		rate = async->async_ttycommon.t_cflag & CBAUD;
   2450  1434   kc28005 		if (async->async_ttycommon.t_cflag & CBAUDEXT)
   2451  1434   kc28005 			rate += 16;
   2452  1434   kc28005 		if (rate >= N_SU_SPEEDS || rate == B0) {
   2453  1434   kc28005 			rate = B9600;
   2454  1434   kc28005 		}
   2455  1434   kc28005 
   2456     0    stevel 		mutex_exit(asy->asy_excl_hi);
   2457  1434   kc28005 		mutex_exit(asy->asy_excl);
   2458  1434   kc28005 		drv_usecwait(2 * MICROSEC / baudtable[rate]);
   2459  1434   kc28005 		mutex_enter(asy->asy_excl);
   2460     0    stevel 	}
   2461     0    stevel 	async->async_flags &= ~(ASYNC_DELAY|ASYNC_BREAK|ASYNC_DRAINING);
   2462     0    stevel 	if ((q = async->async_ttycommon.t_writeq) != NULL) {
   2463     0    stevel 		mutex_exit(asy->asy_excl);
   2464     0    stevel 		enterq(q);
   2465     0    stevel 		mutex_enter(asy->asy_excl);
   2466     0    stevel 	}
   2467     0    stevel 	async_start(async);
   2468     0    stevel 	mutex_exit(asy->asy_excl);
   2469     0    stevel 	if (q != NULL)
   2470     0    stevel 		leaveq(q);
   2471     0    stevel 
   2472     0    stevel 	/* cleared break or delay flag; may have made some output progress */
   2473     0    stevel 	cv_broadcast(&async->async_flags_cv);
   2474     0    stevel }
   2475     0    stevel 
   2476     0    stevel static void
   2477     0    stevel async_start(struct asyncline *async)
   2478     0    stevel {
   2479     0    stevel 	async_nstart(async, 0);
   2480     0    stevel }
   2481     0    stevel 
   2482     0    stevel /*
   2483     0    stevel  * Start output on a line, unless it's busy, frozen, or otherwise.
   2484     0    stevel  */
   2485     0    stevel static void
   2486     0    stevel async_nstart(struct asyncline *async, int mode)
   2487     0    stevel {
   2488     0    stevel 	register struct asycom *asy = async->async_common;
   2489     0    stevel 	register int cc;
   2490     0    stevel 	register queue_t *q;
   2491     0    stevel 	mblk_t *bp, *nbp;
   2492     0    stevel 	uchar_t *xmit_addr;
   2493     0    stevel 	uchar_t	val;
   2494     0    stevel 	int	fifo_len = 1;
   2495     0    stevel 	int	xmit_progress;
   2496     0    stevel 
   2497     0    stevel #ifdef DEBUG
   2498     0    stevel 	if (asydebug & ASY_DEBUG_PROCS)
   2499     0    stevel 		printf("start\n");
   2500     0    stevel #endif
   2501     0    stevel 	if (asy->asy_use_fifo == FIFO_ON)
   2502     0    stevel 		fifo_len = asy->asy_fifo_buf; /* with FIFO buffers */
   2503     0    stevel 
   2504     0    stevel 	ASSERT(mutex_owned(asy->asy_excl));
   2505     0    stevel 	mutex_enter(asy->asy_excl_hi);
   2506     0    stevel 	asycheckflowcontrol_hw(asy);
   2507     0    stevel 
   2508     0    stevel 	/*
   2509     0    stevel 	 * If the chip is busy (i.e., we're waiting for a break timeout
   2510     0    stevel 	 * to expire, or for the current transmission to finish, or for
   2511     0    stevel 	 * output to finish draining from chip), don't grab anything new.
   2512     0    stevel 	 */
   2513     0    stevel 	if (async->async_flags & (ASYNC_BREAK|ASYNC_BUSY|ASYNC_DRAINING)) {
   2514     0    stevel 		mutex_exit(asy->asy_excl_hi);
   2515     0    stevel #ifdef DEBUG
   2516     0    stevel 		if (mode && asydebug & ASY_DEBUG_CLOSE)
   2517     0    stevel 			printf("asy%d: start %s.\n",
   2518  5973  zk194757 			    UNIT(async->async_dev),
   2519  5973  zk194757 			    async->async_flags & ASYNC_BREAK
   2520  5973  zk194757 			    ? "break" : "busy");
   2521     0    stevel #endif
   2522     0    stevel 		return;
   2523     0    stevel 	}
   2524     0    stevel 
   2525     0    stevel 	/*
   2526     0    stevel 	 * If we have a flow-control character to transmit, do it now.
   2527     0    stevel 	 */
   2528     0    stevel 	if (asycheckflowcontrol_sw(asy)) {
   2529     0    stevel 		mutex_exit(asy->asy_excl_hi);
   2530     0    stevel 		return;
   2531     0    stevel 	}
   2532     0    stevel 	mutex_exit(asy->asy_excl_hi);
   2533     0    stevel 	/*
   2534     0    stevel 	 * If we're waiting for a delay timeout to expire, don't grab
   2535     0    stevel 	 * anything new.
   2536     0    stevel 	 */
   2537     0    stevel 	if (async->async_flags & ASYNC_DELAY) {
   2538     0    stevel #ifdef DEBUG
   2539     0    stevel 		if (mode && asydebug & ASY_DEBUG_CLOSE)
   2540     0    stevel 			printf("asy%d: start ASYNC_DELAY.\n",
   2541  5973  zk194757 			    UNIT(async->async_dev));
   2542     0    stevel #endif
   2543     0    stevel 		return;
   2544     0    stevel 	}
   2545     0    stevel 
   2546     0    stevel 	if ((q = async->async_ttycommon.t_writeq) == NULL) {
   2547     0    stevel #ifdef DEBUG
   2548     0    stevel 		if (mode && asydebug & ASY_DEBUG_CLOSE)
   2549     0    stevel 			printf("asy%d: start writeq is null.\n",
   2550  5973  zk194757 			    UNIT(async->async_dev));
   2551     0    stevel #endif
   2552     0    stevel 		return;	/* not attached to a stream */
   2553     0    stevel 	}
   2554     0    stevel 
   2555     0    stevel 	for (;;) {
   2556     0    stevel 		if ((bp = getq(q)) == NULL)
   2557     0    stevel 			return;	/* no data to transmit */
   2558     0    stevel 
   2559     0    stevel 		/*
   2560     0    stevel 		 * We have a message block to work on.
   2561     0    stevel 		 * Check whether it's a break, a delay, or an ioctl (the latter
   2562     0    stevel 		 * occurs if the ioctl in question was waiting for the output
   2563     0    stevel 		 * to drain).  If it's one of those, process it immediately.
   2564     0    stevel 		 */
   2565     0    stevel 		switch (bp->b_datap->db_type) {
   2566     0    stevel 
   2567     0    stevel 		case M_BREAK:
   2568     0    stevel 			/*
   2569     0    stevel 			 * Set the break bit, and arrange for "async_restart"
   2570     0    stevel 			 * to be called in 1/4 second; it will turn the
   2571     0    stevel 			 * break bit off, and call "async_start" to grab
   2572     0    stevel 			 * the next message.
   2573     0    stevel 			 */
   2574     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2575     0    stevel 			val = INB(LCR);
   2576     0    stevel 			OUTB(LCR, (val | SETBREAK));
   2577     0    stevel 			mutex_exit(asy->asy_excl_hi);
   2578     0    stevel 			async->async_flags |= ASYNC_BREAK;
   2579     0    stevel 			(void) timeout(async_restart, async, hz / 4);
   2580     0    stevel 			freemsg(bp);
   2581     0    stevel 			return;	/* wait for this to finish */
   2582     0    stevel 
   2583     0    stevel 		case M_DELAY:
   2584     0    stevel 			/*
   2585     0    stevel 			 * Arrange for "async_restart" to be called when the
   2586     0    stevel 			 * delay expires; it will turn ASYNC_DELAY off,
   2587     0    stevel 			 * and call "async_start" to grab the next message.
   2588     0    stevel 			 */
   2589     0    stevel 			(void) timeout(async_restart, async,
   2590  5973  zk194757 			    (clock_t)(*(unsigned char *)bp->b_rptr + 6));
   2591     0    stevel 			async->async_flags |= ASYNC_DELAY;
   2592     0    stevel 			freemsg(bp);
   2593     0    stevel 			return;	/* wait for this to finish */
   2594     0    stevel 
   2595     0    stevel 		case M_IOCTL:
   2596     0    stevel 			/*
   2597     0    stevel 			 * This ioctl needs to wait for the output ahead of
   2598     0    stevel 			 * it to drain.  Try to do it, and then either
   2599     0    stevel 			 * redo the ioctl at a later time or grab the next
   2600     0    stevel 			 * message after it.
   2601     0    stevel 			 */
   2602     0    stevel 
   2603     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2604     0    stevel 			if (asy_isbusy(asy)) {
   2605     0    stevel 				/*
   2606     0    stevel 				 * Get the divisor by calculating the rate
   2607     0    stevel 				 */
   2608     0    stevel 				unsigned int rate;
   2609     0    stevel 
   2610     0    stevel 				mutex_exit(asy->asy_excl_hi);
   2611     0    stevel 				rate = async->async_ttycommon.t_cflag & CBAUD;
   2612     0    stevel 				if (async->async_ttycommon.t_cflag & CBAUDEXT)
   2613     0    stevel 					rate += 16;
   2614     0    stevel 				if (rate >= N_SU_SPEEDS || rate == B0) {
   2615     0    stevel 					rate = B9600;
   2616     0    stevel 				}
   2617     0    stevel 
   2618     0    stevel 				/*
   2619     0    stevel 				 * We need to do a callback as the port will
   2620     0    stevel 				 * be set to drain
   2621     0    stevel 				 */
   2622     0    stevel 				async->async_flags |= ASYNC_DRAINING;
   2623     0    stevel 
   2624     0    stevel 				/*
   2625     0    stevel 				 * Put the message we just processed back onto
   2626     0    stevel 				 * the end of the queue
   2627     0    stevel 				 */
   2628     0    stevel 				if (putq(q, bp) == 0)
   2629     0    stevel 					freemsg(bp);
   2630     0    stevel 
   2631     0    stevel 				/*
   2632     0    stevel 				 * We need to delay until the TSR and THR
   2633     0    stevel 				 * have been exhausted.  We base the delay on
   2634     0    stevel 				 * the amount of time it takes to transmit
   2635     0    stevel 				 * 2 chars at the current baud rate in
   2636     0    stevel 				 * microseconds.
   2637     0    stevel 				 *
   2638     0    stevel 				 * Therefore, the wait period is:
   2639     0    stevel 				 *
   2640     0    stevel 				 * (#TSR bits + #THR bits) *
   2641     0    stevel 				 * 	1 MICROSEC / baud rate
   2642     0    stevel 				 */
   2643     0    stevel 				(void) timeout(async_restart, async,
   2644  5973  zk194757 				    drv_usectohz(16 * MICROSEC /
   2645  5973  zk194757 				    baudtable[rate]));
   2646     0    stevel 				return;
   2647     0    stevel 			}
   2648     0    stevel 			mutex_exit(asy->asy_excl_hi);
   2649     0    stevel 			mutex_exit(asy->asy_excl);
   2650     0    stevel 			async_ioctl(async, q, bp, B_FALSE);
   2651     0    stevel 			mutex_enter(asy->asy_excl);
   2652     0    stevel 			continue;
   2653     0    stevel 		}
   2654     0    stevel 
   2655     0    stevel 		while (bp != NULL && (cc = bp->b_wptr - bp->b_rptr) == 0) {
   2656     0    stevel 			nbp = bp->b_cont;
   2657     0    stevel 			freeb(bp);
   2658     0    stevel 			bp = nbp;
   2659     0    stevel 		}
   2660     0    stevel 		if (bp != NULL)
   2661     0    stevel 			break;
   2662     0    stevel 	}
   2663     0    stevel 
   2664     0    stevel 	/*
   2665     0    stevel 	 * We have data to transmit.  If output is stopped, put
   2666     0    stevel 	 * it back and try again later.
   2667     0    stevel 	 */
   2668     0    stevel 	if (async->async_flags & (ASYNC_HW_OUT_FLW|ASYNC_STOPPED)) {
   2669     0    stevel #ifdef DEBUG
   2670     0    stevel 		if (asydebug & ASY_DEBUG_HFLOW &&
   2671  5973  zk194757 		    async->async_flags & ASYNC_HW_OUT_FLW)
   2672     0    stevel 			printf("asy%d: output hflow in effect.\n",
   2673  5973  zk194757 			    UNIT(async->async_dev));
   2674     0    stevel #endif
   2675     0    stevel 		mutex_exit(asy->asy_excl);
   2676     0    stevel 		(void) putbq(q, bp);
   2677     0    stevel 		/*
   2678     0    stevel 		 * We entered the routine owning the lock, we need to
   2679     0    stevel 		 * exit the routine owning the lock.
   2680     0    stevel 		 */
   2681     0    stevel 		mutex_enter(asy->asy_excl);
   2682     0    stevel 		return;
   2683     0    stevel 	}
   2684     0    stevel 
   2685     0    stevel 	async->async_xmitblk = bp;
   2686     0    stevel 	xmit_addr = bp->b_rptr;
   2687     0    stevel 	bp = bp->b_cont;
   2688     0    stevel 	if (bp != NULL) {
   2689     0    stevel 		mutex_exit(asy->asy_excl);
   2690     0    stevel 		(void) putbq(q, bp);	/* not done with this message yet */
   2691     0    stevel 		mutex_enter(asy->asy_excl);
   2692     0    stevel 	}
   2693     0    stevel 
   2694     0    stevel 	/*
   2695     0    stevel 	 * In 5-bit mode, the high order bits are used
   2696     0    stevel 	 * to indicate character sizes less than five,
   2697     0    stevel 	 * so we need to explicitly mask before transmitting
   2698     0    stevel 	 */
   2699     0    stevel 	if ((async->async_ttycommon.t_cflag & CSIZE) == CS5) {
   2700     0    stevel 		register unsigned char *p = xmit_addr;
   2701     0    stevel 		register int cnt = cc;
   2702     0    stevel 
   2703     0    stevel 		while (cnt--)
   2704     0    stevel 			*p++ &= (unsigned char) 0x1f;
   2705     0    stevel 	}
   2706     0    stevel 
   2707     0    stevel 	/*
   2708     0    stevel 	 * Set up this block for pseudo-DMA.
   2709     0    stevel 	 */
   2710     0    stevel 	mutex_enter(asy->asy_excl_hi);
   2711     0    stevel 	async->async_optr = xmit_addr;
   2712     0    stevel 	async->async_ocnt = cc;
   2713     0    stevel 	/*
   2714     0    stevel 	 * If the transmitter is ready, shove some
   2715     0    stevel 	 * characters out.
   2716     0    stevel 	 */
   2717     0    stevel 	xmit_progress = 0;
   2718     0    stevel 	while (fifo_len-- && async->async_ocnt) {
   2719     0    stevel 		if (INB(LSR) & XHRE) {
   2720     0    stevel 			OUTB(DAT, *async->async_optr++);
   2721     0    stevel 			async->async_ocnt--;
   2722     0    stevel 			xmit_progress++;
   2723     0    stevel 		}
   2724     0    stevel 	}
   2725     0    stevel 	asy->asy_out_of_band_xmit = xmit_progress;
   2726     0    stevel 	if (xmit_progress > 0)
   2727     0    stevel 		async->async_flags |= ASYNC_PROGRESS;
   2728     0    stevel 	async->async_flags |= ASYNC_BUSY;
   2729     0    stevel 	mutex_exit(asy->asy_excl_hi);
   2730     0    stevel }
   2731     0    stevel 
   2732     0    stevel /*
   2733     0    stevel  * Resume output by poking the transmitter.
   2734     0    stevel  */
   2735     0    stevel static void
   2736     0    stevel async_resume(struct asyncline *async)
   2737     0    stevel {
   2738     0    stevel 	register struct asycom *asy = async->async_common;
   2739     0    stevel 
   2740     0    stevel 	ASSERT(mutex_owned(asy->asy_excl_hi));
   2741     0    stevel #ifdef DEBUG
   2742     0    stevel 	if (asydebug & ASY_DEBUG_PROCS)
   2743     0    stevel 		printf("resume\n");
   2744     0    stevel #endif
   2745     0    stevel 
   2746     0    stevel 	asycheckflowcontrol_hw(asy);
   2747     0    stevel 
   2748     0    stevel 	if (INB(LSR) & XHRE) {
   2749     0    stevel 		if (asycheckflowcontrol_sw(asy)) {
   2750     0    stevel 			return;
   2751     0    stevel 		} else if (async->async_ocnt > 0) {
   2752     0    stevel 			OUTB(DAT, *async->async_optr++);
   2753     0    stevel 			async->async_ocnt--;
   2754     0    stevel 			async->async_flags |= ASYNC_PROGRESS;
   2755     0    stevel 		}
   2756     0    stevel 	}
   2757     0    stevel }
   2758     0    stevel 
   2759     0    stevel /*
   2760     0    stevel  * Process an "ioctl" message sent down to us.
   2761     0    stevel  * Note that we don't need to get any locks until we are ready to access
   2762     0    stevel  * the hardware.  Nothing we access until then is going to be altered
   2763     0    stevel  * outside of the STREAMS framework, so we should be safe.
   2764     0    stevel  */
   2765     0    stevel static void
   2766     0    stevel async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp, boolean_t iswput)
   2767     0    stevel {
   2768     0    stevel 	register struct asycom *asy = async->async_common;
   2769     0    stevel 	register tty_common_t  *tp = &async->async_ttycommon;
   2770     0    stevel 	register struct iocblk *iocp;
   2771     0    stevel 	register unsigned datasize;
   2772  2211  zk194757 	size_t ioc_count;
   2773     0    stevel 	mblk_t *datamp;
   2774     0    stevel 	int error = 0;
   2775     0    stevel 	uchar_t val, icr;
   2776     0    stevel #ifdef DEBUG
   2777     0    stevel 	if (asydebug & ASY_DEBUG_PROCS)
   2778     0    stevel 		printf("ioctl\n");
   2779     0    stevel #endif
   2780     0    stevel 
   2781     0    stevel 	if (tp->t_iocpending != NULL) {
   2782     0    stevel 		/*
   2783     0    stevel 		 * We were holding an "ioctl" response pending the
   2784     0    stevel 		 * availability of an "mblk" to hold data to be passed up;
   2785     0    stevel 		 * another "ioctl" came through, which means that "ioctl"
   2786     0    stevel 		 * must have timed out or been aborted.
   2787     0    stevel 		 */
   2788     0    stevel 		freemsg(async->async_ttycommon.t_iocpending);
   2789     0    stevel 		async->async_ttycommon.t_iocpending = NULL;
   2790     0    stevel 	}
   2791     0    stevel 
   2792     0    stevel 	iocp = (struct iocblk *)mp->b_rptr;
   2793  2211  zk194757 
   2794  2211  zk194757 	/*
   2795  2211  zk194757 	 * Save off the ioc count in case we need to restore it
   2796  2211  zk194757 	 * because we are queuing a message block.
   2797  2211  zk194757 	 */
   2798  2211  zk194757 	ioc_count = iocp->ioc_count;
   2799     0    stevel 
   2800     0    stevel 	/*
   2801     0    stevel 	 * For TIOCMGET, TIOCMBIC, TIOCMBIS, TIOCMSET, and PPS, do NOT call
   2802     0    stevel 	 * ttycommon_ioctl() because this function frees up the message block
   2803     0    stevel 	 * (mp->b_cont) that contains the address of the user variable where
   2804     0    stevel 	 * we need to pass back the bit array.
   2805  5973  zk194757 	 *
   2806  5973  zk194757 	 * Similarly, ttycommon_ioctl() does not know about CONSOPENPOLLEDIO
   2807  5973  zk194757 	 * and CONSCLOSEPOLLEDIO, so don't let ttycommon_ioctl() touch them.
   2808     0    stevel 	 */
   2809     0    stevel 	if (iocp->ioc_cmd == TIOCMGET ||
   2810  5973  zk194757 	    iocp->ioc_cmd == TIOCMBIC ||
   2811  5973  zk194757 	    iocp->ioc_cmd == TIOCMBIS ||
   2812  5973  zk194757 	    iocp->ioc_cmd == TIOCMSET ||
   2813  5973  zk194757 	    iocp->ioc_cmd == TIOCGPPS ||
   2814  5973  zk194757 	    iocp->ioc_cmd == TIOCSPPS ||
   2815  5973  zk194757 	    iocp->ioc_cmd == TIOCGPPSEV ||
   2816  5973  zk194757 	    iocp->ioc_cmd == CONSOPENPOLLEDIO ||
   2817  5973  zk194757 	    iocp->ioc_cmd == CONSCLOSEPOLLEDIO)
   2818     0    stevel 		error = -1; /* Do Nothing */
   2819     0    stevel 	else
   2820     0    stevel 
   2821     0    stevel 	/*
   2822     0    stevel 	 * The only way in which "ttycommon_ioctl" can fail is if the "ioctl"
   2823     0    stevel 	 * requires a response containing data to be returned to the user,
   2824     0    stevel 	 * and no mblk could be allocated for the data.
   2825     0    stevel 	 * No such "ioctl" alters our state.  Thus, we always go ahead and
   2826     0    stevel 	 * do any state-changes the "ioctl" calls for.  If we couldn't allocate
   2827     0    stevel 	 * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so
   2828     0    stevel 	 * we just call "bufcall" to request that we be called back when we
   2829     0    stevel 	 * stand a better chance of allocating the data.
   2830     0    stevel 	 */
   2831     0    stevel 	if ((datasize = ttycommon_ioctl(tp, wq, mp, &error)) != 0) {
   2832     0    stevel 		if (async->async_wbufcid)
   2833     0    stevel 			unbufcall(async->async_wbufcid);
   2834     0    stevel 		async->async_wbufcid = bufcall(datasize, BPRI_HI, async_reioctl,
   2835     0    stevel 		    async);
   2836     0    stevel 		return;
   2837     0    stevel 	}
   2838     0    stevel 
   2839     0    stevel 	mutex_enter(asy->asy_excl);
   2840     0    stevel 
   2841     0    stevel 	if (error == 0) {
   2842     0    stevel 		/*
   2843     0    stevel 		 * "ttycommon_ioctl" did most of the work; we just use the
   2844     0    stevel 		 * data it set up.
   2845     0    stevel 		 */
   2846     0    stevel 		switch (iocp->ioc_cmd) {
   2847     0    stevel 
   2848     0    stevel 		case TCSETS:
   2849     0    stevel 			if (!(asy->asy_rsc_console || asy->asy_rsc_control ||
   2850     0    stevel 			    asy->asy_lom_console)) {
   2851     0    stevel 				mutex_enter(asy->asy_excl_hi);
   2852     0    stevel 				error = asy_program(asy, ASY_NOINIT);
   2853     0    stevel 				mutex_exit(asy->asy_excl_hi);
   2854     0    stevel 			}
   2855     0    stevel 			break;
   2856     0    stevel 		case TCSETSF:
   2857     0    stevel 		case TCSETSW:
   2858     0    stevel 		case TCSETA:
   2859     0    stevel 		case TCSETAW:
   2860     0    stevel 		case TCSETAF:
   2861     0    stevel 			if (!(asy->asy_rsc_console || asy->asy_rsc_control ||
   2862     0    stevel 			    asy->asy_lom_console)) {
   2863     0    stevel 				mutex_enter(asy->asy_excl_hi);
   2864     0    stevel 				if (iswput && asy_isbusy(asy)) {
   2865  2211  zk194757 					/*
   2866  2211  zk194757 					 * ttycommon_ioctl sets the db_type to
   2867  2211  zk194757 					 * M_IOCACK and ioc_count to zero
   2868  2211  zk194757 					 * we need to undo this when we
   2869  2211  zk194757 					 * queue a control message. This will
   2870  2211  zk194757 					 * allow the control messages to be
   2871  2211  zk194757 					 * processed again when the chip
   2872  2211  zk194757 					 * becomes available.
   2873  2211  zk194757 					 */
   2874  2211  zk194757 					mp->b_datap->db_type = M_IOCTL;
   2875  2211  zk194757 					iocp->ioc_count = ioc_count;
   2876  2211  zk194757 
   2877     0    stevel 					if (putq(wq, mp) == 0)
   2878     0    stevel 						freemsg(mp);
   2879     0    stevel 					mutex_exit(asy->asy_excl_hi);
   2880     0    stevel 					mutex_exit(asy->asy_excl);
   2881     0    stevel 					return;
   2882     0    stevel 				}
   2883  3880  zk194757 
   2884  3880  zk194757 				/*
   2885  3880  zk194757 				 * TCSETA, TCSETAW, and TCSETAF make use of
   2886  3880  zk194757 				 * the termio structure and therefore have
   2887  3880  zk194757 				 * no concept of any speed except what can
   2888  3880  zk194757 				 * be represented by CBAUD. This is because
   2889  3880  zk194757 				 * of legacy SVR4 code. Therefore, if we see
   2890  3880  zk194757 				 * one of the aforementioned IOCTL commands
   2891  3880  zk194757 				 * we should zero out CBAUDEXT, CIBAUD, and
   2892  3880  zk194757 				 * CIBAUDEXT as to not break legacy
   2893  3880  zk194757 				 * functionality. This is because CBAUDEXT,
   2894  3880  zk194757 				 * CIBAUD, and CIBAUDEXT can't be stored in
   2895  3880  zk194757 				 * an unsigned short. By zeroing out CBAUDEXT,
   2896  3880  zk194757 				 * CIBAUD, and CIBAUDEXT in the t_cflag of the
   2897  3880  zk194757 				 * termios structure asy_program() will set the
   2898  3880  zk194757 				 * input baud rate to the output baud rate.
   2899  3880  zk194757 				 */
   2900  3880  zk194757 				if (iocp->ioc_cmd == TCSETA ||
   2901  3880  zk194757 				    iocp->ioc_cmd == TCSETAW ||
   2902  3880  zk194757 				    iocp->ioc_cmd == TCSETAF)
   2903  3880  zk194757 					tp->t_cflag &= ~(CIBAUD |
   2904  3880  zk194757 					    CIBAUDEXT | CBAUDEXT);
   2905  3880  zk194757 
   2906     0    stevel 				error = asy_program(asy, ASY_NOINIT);
   2907     0    stevel 				mutex_exit(asy->asy_excl_hi);
   2908     0    stevel 			}
   2909     0    stevel 			break;
   2910     0    stevel 		case TIOCSSOFTCAR:
   2911     0    stevel 			/* Set the driver state appropriately */
   2912     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2913     0    stevel 			if (tp->t_flags & TS_SOFTCAR)
   2914     0    stevel 				asy->asy_flags |= ASY_IGNORE_CD;
   2915     0    stevel 			else
   2916     0    stevel 				asy->asy_flags &= ~ASY_IGNORE_CD;
   2917     0    stevel 			mutex_exit(asy->asy_excl_hi);
   2918     0    stevel 			break;
   2919     0    stevel 		}
   2920     0    stevel 	} else if (error < 0) {
   2921     0    stevel 		/*
   2922     0    stevel 		 * "ttycommon_ioctl" didn't do anything; we process it here.
   2923     0    stevel 		 */
   2924     0    stevel 		error = 0;
   2925     0    stevel 		switch (iocp->ioc_cmd) {
   2926     0    stevel 
   2927     0    stevel 		case TIOCGPPS:
   2928     0    stevel 			/*
   2929     0    stevel 			 * Get PPS on/off.
   2930     0    stevel 			 */
   2931     0    stevel 			if (mp->b_cont != NULL)
   2932     0    stevel 				freemsg(mp->b_cont);
   2933     0    stevel 
   2934     0    stevel 			mp->b_cont = allocb(sizeof (int), BPRI_HI);
   2935     0    stevel 			if (mp->b_cont == NULL) {
   2936     0    stevel 				error = ENOMEM;
   2937     0    stevel 				break;
   2938     0    stevel 			}
   2939     0    stevel 			if (asy->asy_flags & ASY_PPS)
   2940     0    stevel 				*(int *)mp->b_cont->b_wptr = 1;
   2941     0    stevel 			else
   2942     0    stevel 				*(int *)mp->b_cont->b_wptr = 0;
   2943     0    stevel 			mp->b_cont->b_wptr += sizeof (int);
   2944     0    stevel 			mp->b_datap->db_type = M_IOCACK;
   2945     0    stevel 			iocp->ioc_count = sizeof (int);
   2946     0    stevel 			break;
   2947     0    stevel 
   2948     0    stevel 		case TIOCSPPS:
   2949     0    stevel 			/*
   2950     0    stevel 			 * Set PPS on/off.
   2951     0    stevel 			 */
   2952     0    stevel 			error = miocpullup(mp, sizeof (int));
   2953     0    stevel 			if (error != 0)
   2954     0    stevel 				break;
   2955     0    stevel 
   2956     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2957     0    stevel 			if (*(int *)mp->b_cont->b_rptr)
   2958     0    stevel 				asy->asy_flags |= ASY_PPS;
   2959     0    stevel 			else
   2960     0    stevel 				asy->asy_flags &= ~ASY_PPS;
   2961     0    stevel 			/* Reset edge sense */
   2962     0    stevel 			asy->asy_flags &= ~ASY_PPS_EDGE;
   2963     0    stevel 			mutex_exit(asy->asy_excl_hi);
   2964     0    stevel 			mp->b_datap->db_type = M_IOCACK;
   2965     0    stevel 			break;
   2966     0    stevel 
   2967     0    stevel 		case TIOCGPPSEV: {
   2968     0    stevel 			/*
   2969     0    stevel 			 * Get PPS event data.
   2970     0    stevel 			 */
   2971     0    stevel 			mblk_t *bp;
   2972     0    stevel 			void *buf;
   2973     0    stevel #ifdef _SYSCALL32_IMPL
   2974     0    stevel 			struct ppsclockev32 p32;
   2975     0    stevel #endif
   2976     0    stevel 			struct ppsclockev ppsclockev;
   2977     0    stevel 
   2978     0    stevel 			if (mp->b_cont != NULL) {
   2979     0    stevel 				freemsg(mp->b_cont);
   2980     0    stevel 				mp->b_cont = NULL;
   2981     0    stevel 			}
   2982     0    stevel 
   2983     0    stevel 			if ((asy->asy_flags & ASY_PPS) == 0) {
   2984     0    stevel 				error = ENXIO;
   2985     0    stevel 				break;
   2986     0    stevel 			}
   2987     0    stevel 
   2988     0    stevel 			/* Protect from incomplete asy_ppsev */
   2989     0    stevel 			mutex_enter(asy->asy_excl_hi);
   2990     0    stevel 			ppsclockev = asy_ppsev;
   2991     0    stevel 			mutex_exit(asy->asy_excl_hi);
   2992     0    stevel 
   2993     0    stevel #ifdef _SYSCALL32_IMPL
   2994     0    stevel 			if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
   2995     0    stevel 				TIMEVAL_TO_TIMEVAL32(&p32.tv, &ppsclockev.tv);
   2996     0    stevel 				p32.serial = ppsclockev.serial;
   2997     0    stevel 				buf = &p32;
   2998     0    stevel 				iocp->ioc_count = sizeof (struct ppsclockev32);
   2999     0    stevel 			} else
   3000     0    stevel #endif
   3001     0    stevel 			{
   3002     0    stevel 				buf = &ppsclockev;
   3003     0    stevel 				iocp->ioc_count = sizeof (struct ppsclockev);
   3004     0    stevel 			}
   3005     0    stevel 
   3006     0    stevel 			if ((bp = allocb(iocp->ioc_count, BPRI_HI)) == NULL) {
   3007     0    stevel 				error = ENOMEM;
   3008     0    stevel 				break;
   3009     0    stevel 			}
   3010     0    stevel 			mp->b_cont = bp;
   3011     0    stevel 
   3012     0    stevel 			bcopy(buf, bp->b_wptr, iocp->ioc_count);
   3013     0    stevel 			bp->b_wptr += iocp->ioc_count;
   3014     0    stevel 			mp->b_datap->db_type = M_IOCACK;
   3015     0    stevel 			break;
   3016     0    stevel 		}
   3017     0    stevel 
   3018     0    stevel 		case TCSBRK:
   3019     0    stevel 			error = miocpullup(mp, sizeof (int));
   3020     0    stevel 			if (error != 0)
   3021     0    stevel 				break;
   3022     0    stevel 
   3023     0    stevel 			mutex_enter(asy->asy_excl_hi);
   3024     0    stevel 			if (*(int *)mp->b_cont->b_rptr == 0) {
   3025     0    stevel 				/*
   3026     0    stevel 				 * Get the divisor by calculating the rate
   3027     0    stevel 				 */
   3028     0    stevel 				unsigned int rate, divisor;
   3029     0    stevel 				rate = async->async_ttycommon.t_cflag & CBAUD;
   3030     0    stevel 				if (async->async_ttycommon.t_cflag & CBAUDEXT)
   3031     0    stevel 					rate += 16;
   3032     0    stevel 				if (rate >= N_SU_SPEEDS) rate = B9600;
   3033     0    stevel 				divisor = asyspdtab[rate] & 0xfff;
   3034     0    stevel 
   3035     0    stevel 				/*
   3036     0    stevel 				 * To ensure that erroneous characters are
   3037     0    stevel 				 * not sent out when the break is set, SB
   3038     0    stevel 				 * recommends three steps:
   3039     0    stevel 				 *
   3040     0    stevel 				 * 1) pad the TSR with 0 bits
   3041     0    stevel 				 * 2) When the TSR is full, set break
   3042     0    stevel 				 * 3) When the TSR has been flushed, unset
   3043     0    stevel 				 *    the break when transmission must be
   3044     0    stevel 				 *    restored.
   3045     0    stevel 				 *
   3046     0    stevel 				 * We loop until the TSR is empty and then
   3047     0    stevel 				 * set the break.  ASYNC_BREAK has been set
   3048     0    stevel 				 * to ensure that no characters are
   3049     0    stevel 				 * transmitted while the TSR is being
   3050     0    stevel 				 * flushed and SOUT is being used for the
   3051