1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 23*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 24*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 29*7c478bd9Sstevel@tonic-gate */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate /* 34*7c478bd9Sstevel@tonic-gate * Serial I/O driver for 8250/16450/16550A/16650/16750 chips. 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/signal.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/termio.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/strtty.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/kbio.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/consdev.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 57*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 58*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 59*7c478bd9Sstevel@tonic-gate #endif 60*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 62*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 63*7c478bd9Sstevel@tonic-gate #include <sys/asy.h> 64*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate /* 67*7c478bd9Sstevel@tonic-gate * set the RX FIFO trigger_level to half the RX FIFO size for now 68*7c478bd9Sstevel@tonic-gate * we may want to make this configurable later. 69*7c478bd9Sstevel@tonic-gate */ 70*7c478bd9Sstevel@tonic-gate static int asy_trig_level = FIFO_TRIG_8; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate int asy_drain_check = 15000000; /* tunable: exit drain check time */ 73*7c478bd9Sstevel@tonic-gate int asy_min_dtr_low = 500000; /* tunable: minimum DTR down time */ 74*7c478bd9Sstevel@tonic-gate int asy_min_utbrk = 100000; /* tunable: minumum untimed brk time */ 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate int asymaxchip = ASY16750; /* tunable: limit chip support we look for */ 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * Just in case someone has a chip with broken loopback mode, we provide a 80*7c478bd9Sstevel@tonic-gate * means to disable the loopback test. By default, we only loopback test 81*7c478bd9Sstevel@tonic-gate * UARTs which look like they have FIFOs bigger than 16 bytes. 82*7c478bd9Sstevel@tonic-gate * Set to 0 to suppress test, or to 2 to enable test on any size FIFO. 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate int asy_fifo_test = 1; /* tunable: set to 0, 1, or 2 */ 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate /* 87*7c478bd9Sstevel@tonic-gate * Allow ability to switch off testing of the scratch register. 88*7c478bd9Sstevel@tonic-gate * Some UART emulators might not have it. This will also disable the test 89*7c478bd9Sstevel@tonic-gate * for Exar/Startech ST16C650, as that requires use of the SCR register. 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate int asy_scr_test = 1; /* tunable: set to 0 to disable SCR reg test */ 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate /* 94*7c478bd9Sstevel@tonic-gate * As we don't yet support on-chip flow control, it's a bad idea to put a 95*7c478bd9Sstevel@tonic-gate * large number of characters in the TX FIFO, since if other end tells us 96*7c478bd9Sstevel@tonic-gate * to stop transmitting, we can only stop filling the TX FIFO, but it will 97*7c478bd9Sstevel@tonic-gate * still carry on draining by itself, so remote end still gets what's left 98*7c478bd9Sstevel@tonic-gate * in the FIFO. 99*7c478bd9Sstevel@tonic-gate */ 100*7c478bd9Sstevel@tonic-gate int asy_max_tx_fifo = 16; /* tunable: max fill of TX FIFO */ 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate #define async_stopc async_ttycommon.t_stopc 103*7c478bd9Sstevel@tonic-gate #define async_startc async_ttycommon.t_startc 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate #define ASY_INIT 1 106*7c478bd9Sstevel@tonic-gate #define ASY_NOINIT 0 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate /* enum value for sw and hw flow control action */ 109*7c478bd9Sstevel@tonic-gate typedef enum { 110*7c478bd9Sstevel@tonic-gate FLOW_CHECK, 111*7c478bd9Sstevel@tonic-gate FLOW_STOP, 112*7c478bd9Sstevel@tonic-gate FLOW_START 113*7c478bd9Sstevel@tonic-gate } async_flowc_action; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 116*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_INIT 0x0001 /* Output msgs during driver initialization. */ 117*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_INPUT 0x0002 /* Report characters received during int. */ 118*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_EOT 0x0004 /* Output msgs when wait for xmit to finish. */ 119*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_CLOSE 0x0008 /* Output msgs when driver open/close called */ 120*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_HFLOW 0x0010 /* Output msgs when H/W flowcontrol is active */ 121*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_PROCS 0x0020 /* Output each proc name as it is entered. */ 122*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_STATE 0x0040 /* Output value of Interrupt Service Reg. */ 123*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_INTR 0x0080 /* Output value of Interrupt Service Reg. */ 124*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_OUT 0x0100 /* Output msgs about output events. */ 125*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_BUSY 0x0200 /* Output msgs when xmit is enabled/disabled */ 126*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_MODEM 0x0400 /* Output msgs about modem status & control. */ 127*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_MODM2 0x0800 /* Output msgs about modem status & control. */ 128*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_IOCTL 0x1000 /* Output msgs about ioctl messages. */ 129*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_CHIP 0x2000 /* Output msgs about chip identification. */ 130*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG_SFLOW 0x4000 /* Output msgs when S/W flowcontrol is active */ 131*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG(x) (debug & (x)) 132*7c478bd9Sstevel@tonic-gate static int debug = 0; 133*7c478bd9Sstevel@tonic-gate #else 134*7c478bd9Sstevel@tonic-gate #define ASY_DEBUG(x) B_FALSE 135*7c478bd9Sstevel@tonic-gate #endif 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate /* pnpISA compressed device ids */ 138*7c478bd9Sstevel@tonic-gate #define pnpMTS0219 0xb6930219 /* Multitech MT5634ZTX modem */ 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate /* 141*7c478bd9Sstevel@tonic-gate * PPS (Pulse Per Second) support. 142*7c478bd9Sstevel@tonic-gate */ 143*7c478bd9Sstevel@tonic-gate void ddi_hardpps(); 144*7c478bd9Sstevel@tonic-gate /* 145*7c478bd9Sstevel@tonic-gate * This is protected by the asy_excl_hi of the port on which PPS event 146*7c478bd9Sstevel@tonic-gate * handling is enabled. Note that only one port should have this enabled at 147*7c478bd9Sstevel@tonic-gate * any one time. Enabling PPS handling on multiple ports will result in 148*7c478bd9Sstevel@tonic-gate * unpredictable (but benign) results. 149*7c478bd9Sstevel@tonic-gate */ 150*7c478bd9Sstevel@tonic-gate static struct ppsclockev asy_ppsev; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate #ifdef PPSCLOCKLED 153*7c478bd9Sstevel@tonic-gate /* XXX Use these to observe PPS latencies and jitter on a scope */ 154*7c478bd9Sstevel@tonic-gate #define LED_ON 155*7c478bd9Sstevel@tonic-gate #define LED_OFF 156*7c478bd9Sstevel@tonic-gate #else 157*7c478bd9Sstevel@tonic-gate #define LED_ON 158*7c478bd9Sstevel@tonic-gate #define LED_OFF 159*7c478bd9Sstevel@tonic-gate #endif 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate static int max_asy_instance = -1; 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate static uint_t asysoftintr(caddr_t intarg); 164*7c478bd9Sstevel@tonic-gate static uint_t asyintr(caddr_t argasy); 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate static boolean_t abort_charseq_recognize(uchar_t ch); 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate /* The async interrupt entry points */ 169*7c478bd9Sstevel@tonic-gate static void async_txint(struct asycom *asy); 170*7c478bd9Sstevel@tonic-gate static void async_rxint(struct asycom *asy, uchar_t lsr); 171*7c478bd9Sstevel@tonic-gate static void async_msint(struct asycom *asy); 172*7c478bd9Sstevel@tonic-gate static void async_softint(struct asycom *asy); 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate static void async_ioctl(struct asyncline *async, queue_t *q, mblk_t *mp); 175*7c478bd9Sstevel@tonic-gate static void async_reioctl(void *unit); 176*7c478bd9Sstevel@tonic-gate static void async_iocdata(queue_t *q, mblk_t *mp); 177*7c478bd9Sstevel@tonic-gate static void async_restart(void *arg); 178*7c478bd9Sstevel@tonic-gate static void async_start(struct asyncline *async); 179*7c478bd9Sstevel@tonic-gate static void async_nstart(struct asyncline *async, int mode); 180*7c478bd9Sstevel@tonic-gate static void async_resume(struct asyncline *async); 181*7c478bd9Sstevel@tonic-gate static void asy_program(struct asycom *asy, int mode); 182*7c478bd9Sstevel@tonic-gate static void asyinit(struct asycom *asy); 183*7c478bd9Sstevel@tonic-gate static void asy_waiteot(struct asycom *asy); 184*7c478bd9Sstevel@tonic-gate static void asyputchar(struct cons_polledio_arg *, uchar_t c); 185*7c478bd9Sstevel@tonic-gate static int asygetchar(struct cons_polledio_arg *); 186*7c478bd9Sstevel@tonic-gate static boolean_t asyischar(struct cons_polledio_arg *); 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate static int asymctl(struct asycom *, int, int); 189*7c478bd9Sstevel@tonic-gate static int asytodm(int, int); 190*7c478bd9Sstevel@tonic-gate static int dmtoasy(int); 191*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 192*7c478bd9Sstevel@tonic-gate static void asyerror(int level, const char *fmt, ...) __KPRINTFLIKE(2); 193*7c478bd9Sstevel@tonic-gate static void asy_parse_mode(dev_info_t *devi, struct asycom *asy); 194*7c478bd9Sstevel@tonic-gate static void asy_soft_state_free(struct asycom *); 195*7c478bd9Sstevel@tonic-gate static char *asy_hw_name(struct asycom *asy); 196*7c478bd9Sstevel@tonic-gate static void async_hold_utbrk(void *arg); 197*7c478bd9Sstevel@tonic-gate static void async_resume_utbrk(struct asyncline *async); 198*7c478bd9Sstevel@tonic-gate static void async_dtr_free(struct asyncline *async); 199*7c478bd9Sstevel@tonic-gate static int asy_identify_chip(dev_info_t *devi, struct asycom *asy); 200*7c478bd9Sstevel@tonic-gate static void asy_reset_fifo(struct asycom *asy, uchar_t flags); 201*7c478bd9Sstevel@tonic-gate static int asy_getproperty(dev_info_t *devi, struct asycom *asy, 202*7c478bd9Sstevel@tonic-gate const char *property); 203*7c478bd9Sstevel@tonic-gate static boolean_t async_flowcontrol_sw_input(struct asycom *asy, 204*7c478bd9Sstevel@tonic-gate async_flowc_action onoff, int type); 205*7c478bd9Sstevel@tonic-gate static void async_flowcontrol_sw_output(struct asycom *asy, 206*7c478bd9Sstevel@tonic-gate async_flowc_action onoff); 207*7c478bd9Sstevel@tonic-gate static void async_flowcontrol_hw_input(struct asycom *asy, 208*7c478bd9Sstevel@tonic-gate async_flowc_action onoff, int type); 209*7c478bd9Sstevel@tonic-gate static void async_flowcontrol_hw_output(struct asycom *asy, 210*7c478bd9Sstevel@tonic-gate async_flowc_action onoff); 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate #define GET_PROP(devi, pname, pflag, pval, plen) \ 213*7c478bd9Sstevel@tonic-gate (ddi_prop_op(DDI_DEV_T_ANY, (devi), PROP_LEN_AND_VAL_BUF, \ 214*7c478bd9Sstevel@tonic-gate (pflag), (pname), (caddr_t)(pval), (plen))) 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate static ddi_iblock_cookie_t asy_soft_iblock; 217*7c478bd9Sstevel@tonic-gate ddi_softintr_t asy_softintr_id; 218*7c478bd9Sstevel@tonic-gate static int asy_addedsoft = 0; 219*7c478bd9Sstevel@tonic-gate int asysoftpend; /* soft interrupt pending */ 220*7c478bd9Sstevel@tonic-gate kmutex_t asy_soft_lock; /* lock protecting asysoftpend */ 221*7c478bd9Sstevel@tonic-gate kmutex_t asy_glob_lock; /* lock protecting global data manipulation */ 222*7c478bd9Sstevel@tonic-gate void *asy_soft_state; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate /* Standard COM port I/O addresses */ 225*7c478bd9Sstevel@tonic-gate static const int standard_com_ports[] = { 226*7c478bd9Sstevel@tonic-gate COM1_IOADDR, COM2_IOADDR, COM3_IOADDR, COM4_IOADDR 227*7c478bd9Sstevel@tonic-gate }; 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate static int *com_ports; 230*7c478bd9Sstevel@tonic-gate static uint_t num_com_ports; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate /* 233*7c478bd9Sstevel@tonic-gate * Baud rate table. Indexed by #defines found in sys/termios.h 234*7c478bd9Sstevel@tonic-gate */ 235*7c478bd9Sstevel@tonic-gate ushort_t asyspdtab[] = { 236*7c478bd9Sstevel@tonic-gate 0, /* 0 baud rate */ 237*7c478bd9Sstevel@tonic-gate 0x900, /* 50 baud rate */ 238*7c478bd9Sstevel@tonic-gate 0x600, /* 75 baud rate */ 239*7c478bd9Sstevel@tonic-gate 0x417, /* 110 baud rate (%0.026) */ 240*7c478bd9Sstevel@tonic-gate 0x359, /* 134 baud rate (%0.058) */ 241*7c478bd9Sstevel@tonic-gate 0x300, /* 150 baud rate */ 242*7c478bd9Sstevel@tonic-gate 0x240, /* 200 baud rate */ 243*7c478bd9Sstevel@tonic-gate 0x180, /* 300 baud rate */ 244*7c478bd9Sstevel@tonic-gate 0x0c0, /* 600 baud rate */ 245*7c478bd9Sstevel@tonic-gate 0x060, /* 1200 baud rate */ 246*7c478bd9Sstevel@tonic-gate 0x040, /* 1800 baud rate */ 247*7c478bd9Sstevel@tonic-gate 0x030, /* 2400 baud rate */ 248*7c478bd9Sstevel@tonic-gate 0x018, /* 4800 baud rate */ 249*7c478bd9Sstevel@tonic-gate 0x00c, /* 9600 baud rate */ 250*7c478bd9Sstevel@tonic-gate 0x006, /* 19200 baud rate */ 251*7c478bd9Sstevel@tonic-gate 0x003, /* 38400 baud rate */ 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate 0x002, /* 57600 baud rate */ 254*7c478bd9Sstevel@tonic-gate 0x0, /* 76800 baud rate not supported */ 255*7c478bd9Sstevel@tonic-gate 0x001, /* 115200 baud rate */ 256*7c478bd9Sstevel@tonic-gate 0x0, /* 153600 baud rate not supported */ 257*7c478bd9Sstevel@tonic-gate 0x0, /* 0x8002 (SMC chip) 230400 baud rate not supported */ 258*7c478bd9Sstevel@tonic-gate 0x0, /* 307200 baud rate not supported */ 259*7c478bd9Sstevel@tonic-gate 0x0, /* 0x8001 (SMC chip) 460800 baud rate not supported */ 260*7c478bd9Sstevel@tonic-gate 0x0, /* unused */ 261*7c478bd9Sstevel@tonic-gate 0x0, /* unused */ 262*7c478bd9Sstevel@tonic-gate 0x0, /* unused */ 263*7c478bd9Sstevel@tonic-gate 0x0, /* unused */ 264*7c478bd9Sstevel@tonic-gate 0x0, /* unused */ 265*7c478bd9Sstevel@tonic-gate 0x0, /* unused */ 266*7c478bd9Sstevel@tonic-gate 0x0, /* unused */ 267*7c478bd9Sstevel@tonic-gate 0x0, /* unused */ 268*7c478bd9Sstevel@tonic-gate 0x0, /* unused */ 269*7c478bd9Sstevel@tonic-gate }; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate static int asyrsrv(queue_t *q); 272*7c478bd9Sstevel@tonic-gate static int asyopen(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 273*7c478bd9Sstevel@tonic-gate static int asyclose(queue_t *q, int flag, cred_t *credp); 274*7c478bd9Sstevel@tonic-gate static int asywput(queue_t *q, mblk_t *mp); 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate struct module_info asy_info = { 277*7c478bd9Sstevel@tonic-gate 0, 278*7c478bd9Sstevel@tonic-gate "asy", 279*7c478bd9Sstevel@tonic-gate 0, 280*7c478bd9Sstevel@tonic-gate INFPSZ, 281*7c478bd9Sstevel@tonic-gate 4096, 282*7c478bd9Sstevel@tonic-gate 128 283*7c478bd9Sstevel@tonic-gate }; 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate static struct qinit asy_rint = { 286*7c478bd9Sstevel@tonic-gate putq, 287*7c478bd9Sstevel@tonic-gate asyrsrv, 288*7c478bd9Sstevel@tonic-gate asyopen, 289*7c478bd9Sstevel@tonic-gate asyclose, 290*7c478bd9Sstevel@tonic-gate NULL, 291*7c478bd9Sstevel@tonic-gate &asy_info, 292*7c478bd9Sstevel@tonic-gate NULL 293*7c478bd9Sstevel@tonic-gate }; 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate static struct qinit asy_wint = { 296*7c478bd9Sstevel@tonic-gate asywput, 297*7c478bd9Sstevel@tonic-gate NULL, 298*7c478bd9Sstevel@tonic-gate NULL, 299*7c478bd9Sstevel@tonic-gate NULL, 300*7c478bd9Sstevel@tonic-gate NULL, 301*7c478bd9Sstevel@tonic-gate &asy_info, 302*7c478bd9Sstevel@tonic-gate NULL 303*7c478bd9Sstevel@tonic-gate }; 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate struct streamtab asy_str_info = { 306*7c478bd9Sstevel@tonic-gate &asy_rint, 307*7c478bd9Sstevel@tonic-gate &asy_wint, 308*7c478bd9Sstevel@tonic-gate NULL, 309*7c478bd9Sstevel@tonic-gate NULL 310*7c478bd9Sstevel@tonic-gate }; 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate static int asyinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 313*7c478bd9Sstevel@tonic-gate void **result); 314*7c478bd9Sstevel@tonic-gate static int asyprobe(dev_info_t *); 315*7c478bd9Sstevel@tonic-gate static int asyattach(dev_info_t *, ddi_attach_cmd_t); 316*7c478bd9Sstevel@tonic-gate static int asydetach(dev_info_t *, ddi_detach_cmd_t); 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate static struct cb_ops cb_asy_ops = { 319*7c478bd9Sstevel@tonic-gate nodev, /* cb_open */ 320*7c478bd9Sstevel@tonic-gate nodev, /* cb_close */ 321*7c478bd9Sstevel@tonic-gate nodev, /* cb_strategy */ 322*7c478bd9Sstevel@tonic-gate nodev, /* cb_print */ 323*7c478bd9Sstevel@tonic-gate nodev, /* cb_dump */ 324*7c478bd9Sstevel@tonic-gate nodev, /* cb_read */ 325*7c478bd9Sstevel@tonic-gate nodev, /* cb_write */ 326*7c478bd9Sstevel@tonic-gate nodev, /* cb_ioctl */ 327*7c478bd9Sstevel@tonic-gate nodev, /* cb_devmap */ 328*7c478bd9Sstevel@tonic-gate nodev, /* cb_mmap */ 329*7c478bd9Sstevel@tonic-gate nodev, /* cb_segmap */ 330*7c478bd9Sstevel@tonic-gate nochpoll, /* cb_chpoll */ 331*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 332*7c478bd9Sstevel@tonic-gate &asy_str_info, /* cb_stream */ 333*7c478bd9Sstevel@tonic-gate D_MP /* cb_flag */ 334*7c478bd9Sstevel@tonic-gate }; 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate struct dev_ops asy_ops = { 337*7c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 338*7c478bd9Sstevel@tonic-gate 0, /* devo_refcnt */ 339*7c478bd9Sstevel@tonic-gate asyinfo, /* devo_getinfo */ 340*7c478bd9Sstevel@tonic-gate nulldev, /* devo_identify */ 341*7c478bd9Sstevel@tonic-gate asyprobe, /* devo_probe */ 342*7c478bd9Sstevel@tonic-gate asyattach, /* devo_attach */ 343*7c478bd9Sstevel@tonic-gate asydetach, /* devo_detach */ 344*7c478bd9Sstevel@tonic-gate nodev, /* devo_reset */ 345*7c478bd9Sstevel@tonic-gate &cb_asy_ops, /* devo_cb_ops */ 346*7c478bd9Sstevel@tonic-gate }; 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 349*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 350*7c478bd9Sstevel@tonic-gate "ASY driver %I%", 351*7c478bd9Sstevel@tonic-gate &asy_ops, /* driver ops */ 352*7c478bd9Sstevel@tonic-gate }; 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 355*7c478bd9Sstevel@tonic-gate MODREV_1, 356*7c478bd9Sstevel@tonic-gate (void *)&modldrv, 357*7c478bd9Sstevel@tonic-gate NULL 358*7c478bd9Sstevel@tonic-gate }; 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate int 361*7c478bd9Sstevel@tonic-gate _init(void) 362*7c478bd9Sstevel@tonic-gate { 363*7c478bd9Sstevel@tonic-gate int i; 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate i = ddi_soft_state_init(&asy_soft_state, sizeof (struct asycom), 2); 366*7c478bd9Sstevel@tonic-gate if (i == 0) { 367*7c478bd9Sstevel@tonic-gate mutex_init(&asy_glob_lock, NULL, MUTEX_DRIVER, NULL); 368*7c478bd9Sstevel@tonic-gate if ((i = mod_install(&modlinkage)) != 0) { 369*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy_glob_lock); 370*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&asy_soft_state); 371*7c478bd9Sstevel@tonic-gate } else { 372*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_INIT, "%s, debug = %x\n", 373*7c478bd9Sstevel@tonic-gate modldrv.drv_linkinfo, debug); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate return (i); 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate int 380*7c478bd9Sstevel@tonic-gate _fini(void) 381*7c478bd9Sstevel@tonic-gate { 382*7c478bd9Sstevel@tonic-gate int i; 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate if ((i = mod_remove(&modlinkage)) == 0) { 385*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_INIT, "%s unloading\n", 386*7c478bd9Sstevel@tonic-gate modldrv.drv_linkinfo); 387*7c478bd9Sstevel@tonic-gate ASSERT(max_asy_instance == -1); 388*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy_glob_lock); 389*7c478bd9Sstevel@tonic-gate if (asy_addedsoft) 390*7c478bd9Sstevel@tonic-gate ddi_remove_softintr(asy_softintr_id); 391*7c478bd9Sstevel@tonic-gate asy_addedsoft = 0; 392*7c478bd9Sstevel@tonic-gate /* free "motherboard-serial-ports" property if allocated */ 393*7c478bd9Sstevel@tonic-gate if (com_ports != NULL && com_ports != (int *)standard_com_ports) 394*7c478bd9Sstevel@tonic-gate ddi_prop_free(com_ports); 395*7c478bd9Sstevel@tonic-gate com_ports = NULL; 396*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy_soft_lock); 397*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&asy_soft_state); 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate return (i); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate int 403*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 404*7c478bd9Sstevel@tonic-gate { 405*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate static int 409*7c478bd9Sstevel@tonic-gate asydetach(dev_info_t *devi, ddi_detach_cmd_t cmd) 410*7c478bd9Sstevel@tonic-gate { 411*7c478bd9Sstevel@tonic-gate int instance; 412*7c478bd9Sstevel@tonic-gate struct asycom *asy; 413*7c478bd9Sstevel@tonic-gate struct asyncline *async; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 416*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); /* find out which unit */ 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate asy = ddi_get_soft_state(asy_soft_state, instance); 421*7c478bd9Sstevel@tonic-gate if (asy == NULL) 422*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 423*7c478bd9Sstevel@tonic-gate async = asy->asy_priv; 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate DEBUGNOTE2(ASY_DEBUG_INIT, "asy%d: %s shutdown.", 426*7c478bd9Sstevel@tonic-gate instance, asy_hw_name(asy)); 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate /* cancel DTR hold timeout */ 429*7c478bd9Sstevel@tonic-gate if (async->async_dtrtid != 0) { 430*7c478bd9Sstevel@tonic-gate (void) untimeout(async->async_dtrtid); 431*7c478bd9Sstevel@tonic-gate async->async_dtrtid = 0; 432*7c478bd9Sstevel@tonic-gate } 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate /* remove all minor device node(s) for this device */ 435*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl); 438*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl_hi); 439*7c478bd9Sstevel@tonic-gate cv_destroy(&async->async_flags_cv); 440*7c478bd9Sstevel@tonic-gate ddi_remove_intr(devi, 0, asy->asy_iblock); 441*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&asy->asy_iohandle); 442*7c478bd9Sstevel@tonic-gate asy_soft_state_free(asy); 443*7c478bd9Sstevel@tonic-gate DEBUGNOTE1(ASY_DEBUG_INIT, "asy%d: shutdown complete", instance); 444*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* 448*7c478bd9Sstevel@tonic-gate * asyprobe 449*7c478bd9Sstevel@tonic-gate * We don't bother probing for the hardware, as since Solaris 2.6, device 450*7c478bd9Sstevel@tonic-gate * nodes are only created for auto-detected hardware or nodes explicitly 451*7c478bd9Sstevel@tonic-gate * created by the user, e.g. via the DCA. However, we should check the 452*7c478bd9Sstevel@tonic-gate * device node is at least vaguely usable, i.e. we have a block of 8 i/o 453*7c478bd9Sstevel@tonic-gate * ports. This prevents attempting to attach to bogus serial ports which 454*7c478bd9Sstevel@tonic-gate * some BIOSs still partially report when they are disabled in the BIOS. 455*7c478bd9Sstevel@tonic-gate */ 456*7c478bd9Sstevel@tonic-gate static int 457*7c478bd9Sstevel@tonic-gate asyprobe(dev_info_t *devi) 458*7c478bd9Sstevel@tonic-gate { 459*7c478bd9Sstevel@tonic-gate int instance; 460*7c478bd9Sstevel@tonic-gate int ret = DDI_PROBE_FAILURE; 461*7c478bd9Sstevel@tonic-gate int regnum; 462*7c478bd9Sstevel@tonic-gate int reglen, nregs; 463*7c478bd9Sstevel@tonic-gate struct reglist { 464*7c478bd9Sstevel@tonic-gate uint_t bustype; 465*7c478bd9Sstevel@tonic-gate int base; 466*7c478bd9Sstevel@tonic-gate int size; 467*7c478bd9Sstevel@tonic-gate } *reglist = NULL; 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate /* Retrieve "reg" property */ 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 474*7c478bd9Sstevel@tonic-gate "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) { 475*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "asyprobe: \"reg\" property not found " 476*7c478bd9Sstevel@tonic-gate "in devices property list"); 477*7c478bd9Sstevel@tonic-gate goto probedone; 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate /* find I/O bus register property */ 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate nregs = reglen / sizeof (struct reglist); 483*7c478bd9Sstevel@tonic-gate for (regnum = 0; regnum < nregs; regnum++) { 484*7c478bd9Sstevel@tonic-gate if (reglist[regnum].bustype == 1) 485*7c478bd9Sstevel@tonic-gate break; 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate if (regnum >= nregs) { 488*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_INIT, 489*7c478bd9Sstevel@tonic-gate "asy%dprobe: No I/O register property", instance); 490*7c478bd9Sstevel@tonic-gate goto probedone; 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate if (reglist[regnum].size < 8) { /* not enough registers for a UART */ 494*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_INIT, 495*7c478bd9Sstevel@tonic-gate "asy%dprobe: Invalid I/O register property", instance); 496*7c478bd9Sstevel@tonic-gate goto probedone; 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate ret = DDI_PROBE_DONTCARE; /* OK, looks like it might be usable */ 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate probedone: 502*7c478bd9Sstevel@tonic-gate if (reglist != NULL) 503*7c478bd9Sstevel@tonic-gate kmem_free(reglist, reglen); 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_INIT, "asy%dprobe: ret=%s\n", instance, 506*7c478bd9Sstevel@tonic-gate ret == DDI_PROBE_DONTCARE ? "DDI_PROBE_DONTCARE" : 507*7c478bd9Sstevel@tonic-gate "DDI_PROBE_FAILURE"); 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate return (ret); 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate static int 513*7c478bd9Sstevel@tonic-gate asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd) 514*7c478bd9Sstevel@tonic-gate { 515*7c478bd9Sstevel@tonic-gate int instance; 516*7c478bd9Sstevel@tonic-gate int mcr; 517*7c478bd9Sstevel@tonic-gate int ret; 518*7c478bd9Sstevel@tonic-gate int regnum = 0; 519*7c478bd9Sstevel@tonic-gate int i; 520*7c478bd9Sstevel@tonic-gate struct asycom *asy; 521*7c478bd9Sstevel@tonic-gate char name[40]; 522*7c478bd9Sstevel@tonic-gate int status; 523*7c478bd9Sstevel@tonic-gate static ddi_device_acc_attr_t ioattr = { 524*7c478bd9Sstevel@tonic-gate DDI_DEVICE_ATTR_V0, 525*7c478bd9Sstevel@tonic-gate DDI_NEVERSWAP_ACC, 526*7c478bd9Sstevel@tonic-gate DDI_STRICTORDER_ACC, 527*7c478bd9Sstevel@tonic-gate }; 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 530*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); /* find out which unit */ 533*7c478bd9Sstevel@tonic-gate ret = ddi_soft_state_zalloc(asy_soft_state, instance); 534*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 535*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 536*7c478bd9Sstevel@tonic-gate asy = ddi_get_soft_state(asy_soft_state, instance); 537*7c478bd9Sstevel@tonic-gate ASSERT(asy != NULL); /* can't fail - we only just allocated it */ 538*7c478bd9Sstevel@tonic-gate asy->asy_unit = instance; 539*7c478bd9Sstevel@tonic-gate mutex_enter(&asy_glob_lock); 540*7c478bd9Sstevel@tonic-gate if (instance > max_asy_instance) 541*7c478bd9Sstevel@tonic-gate max_asy_instance = instance; 542*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_glob_lock); 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate /*CSTYLED*/ 545*7c478bd9Sstevel@tonic-gate { 546*7c478bd9Sstevel@tonic-gate int reglen, nregs; 547*7c478bd9Sstevel@tonic-gate int i; 548*7c478bd9Sstevel@tonic-gate struct { 549*7c478bd9Sstevel@tonic-gate uint_t bustype; 550*7c478bd9Sstevel@tonic-gate int base; 551*7c478bd9Sstevel@tonic-gate int size; 552*7c478bd9Sstevel@tonic-gate } *reglist; 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate /* new probe */ 555*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 556*7c478bd9Sstevel@tonic-gate "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) { 557*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "asyattach: reg property not found " 558*7c478bd9Sstevel@tonic-gate "in devices property list"); 559*7c478bd9Sstevel@tonic-gate asy_soft_state_free(asy); 560*7c478bd9Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate regnum = -1; 563*7c478bd9Sstevel@tonic-gate nregs = reglen / sizeof (*reglist); 564*7c478bd9Sstevel@tonic-gate for (i = 0; i < nregs; i++) { 565*7c478bd9Sstevel@tonic-gate switch (reglist[i].bustype) { 566*7c478bd9Sstevel@tonic-gate case 1: /* I/O bus reg property */ 567*7c478bd9Sstevel@tonic-gate if (regnum == -1) /* only use the first one */ 568*7c478bd9Sstevel@tonic-gate regnum = i; 569*7c478bd9Sstevel@tonic-gate break; 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate case pnpMTS0219: /* Multitech MT5634ZTX modem */ 572*7c478bd9Sstevel@tonic-gate /* Venus chipset can't do loopback test */ 573*7c478bd9Sstevel@tonic-gate asy->asy_flags2 |= ASY2_NO_LOOPBACK; 574*7c478bd9Sstevel@tonic-gate break; 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate default: 577*7c478bd9Sstevel@tonic-gate break; 578*7c478bd9Sstevel@tonic-gate } 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate kmem_free(reglist, reglen); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate if (regnum < 0 || 584*7c478bd9Sstevel@tonic-gate ddi_regs_map_setup(devi, regnum, (caddr_t *)&asy->asy_ioaddr, 585*7c478bd9Sstevel@tonic-gate (offset_t)0, (offset_t)0, &ioattr, &asy->asy_iohandle) 586*7c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 587*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "asy%d: could not map UART registers @ %p", 588*7c478bd9Sstevel@tonic-gate instance, (void *)asy->asy_ioaddr); 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate asy_soft_state_free(asy); 591*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_INIT, "asy%dattach: UART @ %p\n", 595*7c478bd9Sstevel@tonic-gate instance, (void *)asy->asy_ioaddr); 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate mutex_enter(&asy_glob_lock); 598*7c478bd9Sstevel@tonic-gate if (com_ports == NULL) { /* need to initialize com_ports */ 599*7c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, devi, 0, 600*7c478bd9Sstevel@tonic-gate "motherboard-serial-ports", &com_ports, &num_com_ports) != 601*7c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) { 602*7c478bd9Sstevel@tonic-gate /* Use our built-in COM[1234] values */ 603*7c478bd9Sstevel@tonic-gate com_ports = (int *)standard_com_ports; 604*7c478bd9Sstevel@tonic-gate num_com_ports = sizeof (standard_com_ports) / 605*7c478bd9Sstevel@tonic-gate sizeof (standard_com_ports[0]); 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate if (num_com_ports > 10) { 608*7c478bd9Sstevel@tonic-gate /* We run out of single digits for device properties */ 609*7c478bd9Sstevel@tonic-gate num_com_ports = 10; 610*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 611*7c478bd9Sstevel@tonic-gate "More than %d motherboard-serial-ports", 612*7c478bd9Sstevel@tonic-gate num_com_ports); 613*7c478bd9Sstevel@tonic-gate } 614*7c478bd9Sstevel@tonic-gate } 615*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_glob_lock); 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate /* 618*7c478bd9Sstevel@tonic-gate * Lookup the i/o address to see if this is a standard COM port 619*7c478bd9Sstevel@tonic-gate * in which case we assign it the correct tty[a-d] to match the 620*7c478bd9Sstevel@tonic-gate * COM port number, or some other i/o address in which case it 621*7c478bd9Sstevel@tonic-gate * will be assigned /dev/term/[0123...] in some rather arbitrary 622*7c478bd9Sstevel@tonic-gate * fashion. 623*7c478bd9Sstevel@tonic-gate */ 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate for (i = 0; i < num_com_ports; i++) { 626*7c478bd9Sstevel@tonic-gate if (asy->asy_ioaddr == (uint8_t *)(uintptr_t)com_ports[i]) { 627*7c478bd9Sstevel@tonic-gate asy->asy_com_port = i + 1; 628*7c478bd9Sstevel@tonic-gate break; 629*7c478bd9Sstevel@tonic-gate } 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* 633*7c478bd9Sstevel@tonic-gate * It appears that there was async hardware that on reset 634*7c478bd9Sstevel@tonic-gate * did not clear ICR. Hence when we get to 635*7c478bd9Sstevel@tonic-gate * ddi_get_iblock_cookie below, this hardware would cause 636*7c478bd9Sstevel@tonic-gate * the system to hang if there was input available. 637*7c478bd9Sstevel@tonic-gate */ 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, 0x00); 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate /* establish default usage */ 642*7c478bd9Sstevel@tonic-gate asy->asy_mcr |= RTS|DTR; /* do use RTS/DTR after open */ 643*7c478bd9Sstevel@tonic-gate asy->asy_lcr = STOP1|BITS8; /* default to 1 stop 8 bits */ 644*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B9600; /* default to 9600 */ 645*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 646*7c478bd9Sstevel@tonic-gate asy->asy_msint_cnt = 0; /* # of times in async_msint */ 647*7c478bd9Sstevel@tonic-gate #endif 648*7c478bd9Sstevel@tonic-gate mcr = 0; /* don't enable until open */ 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate if (asy->asy_com_port != 0) { 651*7c478bd9Sstevel@tonic-gate /* 652*7c478bd9Sstevel@tonic-gate * For motherboard ports, emulate tty eeprom properties. 653*7c478bd9Sstevel@tonic-gate * Actually, we can't tell if a port is motherboard or not, 654*7c478bd9Sstevel@tonic-gate * so for "motherboard ports", read standard DOS COM ports. 655*7c478bd9Sstevel@tonic-gate */ 656*7c478bd9Sstevel@tonic-gate switch (asy_getproperty(devi, asy, "ignore-cd")) { 657*7c478bd9Sstevel@tonic-gate case 0: /* *-ignore-cd=False */ 658*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 659*7c478bd9Sstevel@tonic-gate "asy%dattach: clear ASY_IGNORE_CD\n", instance); 660*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~ASY_IGNORE_CD; /* wait for cd */ 661*7c478bd9Sstevel@tonic-gate break; 662*7c478bd9Sstevel@tonic-gate case 1: /* *-ignore-cd=True */ 663*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 664*7c478bd9Sstevel@tonic-gate default: /* *-ignore-cd not defined */ 665*7c478bd9Sstevel@tonic-gate /* 666*7c478bd9Sstevel@tonic-gate * We set rather silly defaults of soft carrier on 667*7c478bd9Sstevel@tonic-gate * and DTR/RTS raised here because it might be that 668*7c478bd9Sstevel@tonic-gate * one of the motherboard ports is the system console. 669*7c478bd9Sstevel@tonic-gate */ 670*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 671*7c478bd9Sstevel@tonic-gate "asy%dattach: set ASY_IGNORE_CD, set RTS & DTR\n", 672*7c478bd9Sstevel@tonic-gate instance); 673*7c478bd9Sstevel@tonic-gate mcr = asy->asy_mcr; /* rts/dtr on */ 674*7c478bd9Sstevel@tonic-gate asy->asy_flags |= ASY_IGNORE_CD; /* ignore cd */ 675*7c478bd9Sstevel@tonic-gate break; 676*7c478bd9Sstevel@tonic-gate } 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate /* Property for not raising DTR/RTS */ 679*7c478bd9Sstevel@tonic-gate switch (asy_getproperty(devi, asy, "rts-dtr-off")) { 680*7c478bd9Sstevel@tonic-gate case 0: /* *-rts-dtr-off=False */ 681*7c478bd9Sstevel@tonic-gate asy->asy_flags |= ASY_RTS_DTR_OFF; /* OFF */ 682*7c478bd9Sstevel@tonic-gate mcr = asy->asy_mcr; /* rts/dtr on */ 683*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, "asy%dattach: " 684*7c478bd9Sstevel@tonic-gate "ASY_RTS_DTR_OFF set and DTR & RTS set\n", 685*7c478bd9Sstevel@tonic-gate instance); 686*7c478bd9Sstevel@tonic-gate break; 687*7c478bd9Sstevel@tonic-gate case 1: /* *-rts-dtr-off=True */ 688*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 689*7c478bd9Sstevel@tonic-gate default: /* *-rts-dtr-off undefined */ 690*7c478bd9Sstevel@tonic-gate break; 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /* Parse property for tty modes */ 694*7c478bd9Sstevel@tonic-gate asy_parse_mode(devi, asy); 695*7c478bd9Sstevel@tonic-gate } else { 696*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 697*7c478bd9Sstevel@tonic-gate "asy%dattach: clear ASY_IGNORE_CD, clear RTS & DTR\n", 698*7c478bd9Sstevel@tonic-gate instance); 699*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~ASY_IGNORE_CD; /* wait for cd */ 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate /* 703*7c478bd9Sstevel@tonic-gate * Initialize the port with default settings. 704*7c478bd9Sstevel@tonic-gate */ 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate asy->asy_fifo_buf = 1; 707*7c478bd9Sstevel@tonic-gate asy->asy_use_fifo = FIFO_OFF; 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate /* 710*7c478bd9Sstevel@tonic-gate * Get icookie for mutexes initialization 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate if ((ddi_get_iblock_cookie(devi, 0, &asy->asy_iblock) != 713*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) || 714*7c478bd9Sstevel@tonic-gate (ddi_get_soft_iblock_cookie(devi, DDI_SOFTINT_MED, 715*7c478bd9Sstevel@tonic-gate &asy_soft_iblock) != DDI_SUCCESS)) { 716*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&asy->asy_iohandle); 717*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 718*7c478bd9Sstevel@tonic-gate "asy%d: could not hook interrupt for UART @ %p\n", 719*7c478bd9Sstevel@tonic-gate instance, (void *)asy->asy_ioaddr); 720*7c478bd9Sstevel@tonic-gate asy_soft_state_free(asy); 721*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 722*7c478bd9Sstevel@tonic-gate } 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate /* 725*7c478bd9Sstevel@tonic-gate * Initialize mutexes before accessing the hardware 726*7c478bd9Sstevel@tonic-gate */ 727*7c478bd9Sstevel@tonic-gate mutex_init(&asy->asy_excl, NULL, MUTEX_DRIVER, asy_soft_iblock); 728*7c478bd9Sstevel@tonic-gate mutex_init(&asy->asy_excl_hi, NULL, MUTEX_DRIVER, 729*7c478bd9Sstevel@tonic-gate (void *)asy->asy_iblock); 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 732*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate if (asy_identify_chip(devi, asy) != DDI_SUCCESS) { 735*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 736*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 737*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl); 738*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl_hi); 739*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&asy->asy_iohandle); 740*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Cannot identify UART chip at %p\n", 741*7c478bd9Sstevel@tonic-gate (void *)asy->asy_ioaddr); 742*7c478bd9Sstevel@tonic-gate asy_soft_state_free(asy); 743*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 744*7c478bd9Sstevel@tonic-gate } 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate /* disable all interrupts */ 747*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, 0); 748*7c478bd9Sstevel@tonic-gate /* select baud rate generator */ 749*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, DLAB); 750*7c478bd9Sstevel@tonic-gate /* Set the baud rate to 9600 */ 751*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + (DAT+DLL), 752*7c478bd9Sstevel@tonic-gate asyspdtab[asy->asy_bidx] & 0xff); 753*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + (DAT+DLH), 754*7c478bd9Sstevel@tonic-gate (asyspdtab[asy->asy_bidx] >> 8) & 0xff); 755*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 756*7c478bd9Sstevel@tonic-gate asy->asy_lcr); 757*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, mcr); 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 760*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate /* 763*7c478bd9Sstevel@tonic-gate * Set up the other components of the asycom structure for this port. 764*7c478bd9Sstevel@tonic-gate */ 765*7c478bd9Sstevel@tonic-gate asy->asy_dip = devi; 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate mutex_enter(&asy_glob_lock); 768*7c478bd9Sstevel@tonic-gate if (asy_addedsoft == 0) { /* install the soft interrupt handler */ 769*7c478bd9Sstevel@tonic-gate if (ddi_add_softintr(devi, DDI_SOFTINT_MED, 770*7c478bd9Sstevel@tonic-gate &asy_softintr_id, NULL, 0, asysoftintr, 771*7c478bd9Sstevel@tonic-gate (caddr_t)0) != DDI_SUCCESS) { 772*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl); 773*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl_hi); 774*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&asy->asy_iohandle); 775*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_glob_lock); 776*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 777*7c478bd9Sstevel@tonic-gate "Can not set soft interrupt for ASY driver\n"); 778*7c478bd9Sstevel@tonic-gate asy_soft_state_free(asy); 779*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate mutex_init(&asy_soft_lock, NULL, MUTEX_DRIVER, 782*7c478bd9Sstevel@tonic-gate (void *)asy->asy_iblock); 783*7c478bd9Sstevel@tonic-gate asy_addedsoft++; 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_glob_lock); 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 788*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate /* 791*7c478bd9Sstevel@tonic-gate * Install interrupt handler for this device. 792*7c478bd9Sstevel@tonic-gate */ 793*7c478bd9Sstevel@tonic-gate if (ddi_add_intr(devi, 0, NULL, 0, asyintr, 794*7c478bd9Sstevel@tonic-gate (caddr_t)asy) != DDI_SUCCESS) { 795*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 796*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 797*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl); 798*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl_hi); 799*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&asy->asy_iohandle); 800*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 801*7c478bd9Sstevel@tonic-gate "Can not set device interrupt for ASY driver\n"); 802*7c478bd9Sstevel@tonic-gate asy_soft_state_free(asy); 803*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 807*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate asyinit(asy); /* initialize the asyncline structure */ 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate /* create minor device nodes for this device */ 812*7c478bd9Sstevel@tonic-gate if (asy->asy_com_port != 0) { 813*7c478bd9Sstevel@tonic-gate /* 814*7c478bd9Sstevel@tonic-gate * For DOS COM ports, add letter suffix so 815*7c478bd9Sstevel@tonic-gate * devfsadm can create correct link names. 816*7c478bd9Sstevel@tonic-gate */ 817*7c478bd9Sstevel@tonic-gate name[0] = asy->asy_com_port + 'a' - 1; 818*7c478bd9Sstevel@tonic-gate name[1] = '\0'; 819*7c478bd9Sstevel@tonic-gate } else { 820*7c478bd9Sstevel@tonic-gate /* 821*7c478bd9Sstevel@tonic-gate * ISA port which isn't a standard DOS COM 822*7c478bd9Sstevel@tonic-gate * port needs no further qualification. 823*7c478bd9Sstevel@tonic-gate */ 824*7c478bd9Sstevel@tonic-gate name[0] = '\0'; 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate status = ddi_create_minor_node(devi, name, S_IFCHR, instance, 827*7c478bd9Sstevel@tonic-gate asy->asy_com_port != 0 ? DDI_NT_SERIAL_MB : DDI_NT_SERIAL, NULL); 828*7c478bd9Sstevel@tonic-gate if (status == DDI_SUCCESS) { 829*7c478bd9Sstevel@tonic-gate (void) strcat(name, ",cu"); 830*7c478bd9Sstevel@tonic-gate status = ddi_create_minor_node(devi, name, S_IFCHR, 831*7c478bd9Sstevel@tonic-gate OUTLINE | instance, 832*7c478bd9Sstevel@tonic-gate asy->asy_com_port != 0 ? DDI_NT_SERIAL_MB_DO : 833*7c478bd9Sstevel@tonic-gate DDI_NT_SERIAL_DO, NULL); 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate if (status != DDI_SUCCESS) { 837*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 840*7c478bd9Sstevel@tonic-gate ddi_remove_intr(devi, 0, asy->asy_iblock); 841*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl); 842*7c478bd9Sstevel@tonic-gate mutex_destroy(&asy->asy_excl_hi); 843*7c478bd9Sstevel@tonic-gate cv_destroy(&async->async_flags_cv); 844*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&asy->asy_iohandle); 845*7c478bd9Sstevel@tonic-gate asy_soft_state_free(asy); 846*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 847*7c478bd9Sstevel@tonic-gate } 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate /* 850*7c478bd9Sstevel@tonic-gate * Fill in the polled I/O structure. 851*7c478bd9Sstevel@tonic-gate */ 852*7c478bd9Sstevel@tonic-gate asy->polledio.cons_polledio_version = CONSPOLLEDIO_V0; 853*7c478bd9Sstevel@tonic-gate asy->polledio.cons_polledio_argument = (struct cons_polledio_arg *)asy; 854*7c478bd9Sstevel@tonic-gate asy->polledio.cons_polledio_putchar = asyputchar; 855*7c478bd9Sstevel@tonic-gate asy->polledio.cons_polledio_getchar = asygetchar; 856*7c478bd9Sstevel@tonic-gate asy->polledio.cons_polledio_ischar = asyischar; 857*7c478bd9Sstevel@tonic-gate asy->polledio.cons_polledio_enter = NULL; 858*7c478bd9Sstevel@tonic-gate asy->polledio.cons_polledio_exit = NULL; 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 861*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_INIT, "asy%dattach: done\n", instance); 862*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 863*7c478bd9Sstevel@tonic-gate } 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 866*7c478bd9Sstevel@tonic-gate static int 867*7c478bd9Sstevel@tonic-gate asyinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 868*7c478bd9Sstevel@tonic-gate void **result) 869*7c478bd9Sstevel@tonic-gate { 870*7c478bd9Sstevel@tonic-gate dev_t dev = (dev_t)arg; 871*7c478bd9Sstevel@tonic-gate int instance, error; 872*7c478bd9Sstevel@tonic-gate struct asycom *asy; 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate instance = UNIT(dev); 875*7c478bd9Sstevel@tonic-gate asy = ddi_get_soft_state(asy_soft_state, instance); 876*7c478bd9Sstevel@tonic-gate if (asy == NULL) 877*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate switch (infocmd) { 880*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 881*7c478bd9Sstevel@tonic-gate if (asy->asy_dip == NULL) 882*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 883*7c478bd9Sstevel@tonic-gate else { 884*7c478bd9Sstevel@tonic-gate *result = (void *) asy->asy_dip; 885*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 886*7c478bd9Sstevel@tonic-gate } 887*7c478bd9Sstevel@tonic-gate break; 888*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 889*7c478bd9Sstevel@tonic-gate *result = (void *)(intptr_t)instance; 890*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 891*7c478bd9Sstevel@tonic-gate break; 892*7c478bd9Sstevel@tonic-gate default: 893*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate return (error); 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate /* asy_getproperty -- walk through all name variants until we find a match */ 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate static int 901*7c478bd9Sstevel@tonic-gate asy_getproperty(dev_info_t *devi, struct asycom *asy, const char *property) 902*7c478bd9Sstevel@tonic-gate { 903*7c478bd9Sstevel@tonic-gate int len; 904*7c478bd9Sstevel@tonic-gate int ret; 905*7c478bd9Sstevel@tonic-gate char letter = asy->asy_com_port + 'a' - 1; /* for ttya */ 906*7c478bd9Sstevel@tonic-gate char number = asy->asy_com_port + '0'; /* for COM1 */ 907*7c478bd9Sstevel@tonic-gate char val[40]; 908*7c478bd9Sstevel@tonic-gate char name[40]; 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate /* Property for ignoring DCD */ 911*7c478bd9Sstevel@tonic-gate (void) sprintf(name, "tty%c-%s", letter, property); 912*7c478bd9Sstevel@tonic-gate len = sizeof (val); 913*7c478bd9Sstevel@tonic-gate ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len); 914*7c478bd9Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) { 915*7c478bd9Sstevel@tonic-gate (void) sprintf(name, "com%c-%s", number, property); 916*7c478bd9Sstevel@tonic-gate len = sizeof (val); 917*7c478bd9Sstevel@tonic-gate ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, 918*7c478bd9Sstevel@tonic-gate &len); 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) { 921*7c478bd9Sstevel@tonic-gate (void) sprintf(name, "tty0%c-%s", number, property); 922*7c478bd9Sstevel@tonic-gate len = sizeof (val); 923*7c478bd9Sstevel@tonic-gate ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, 924*7c478bd9Sstevel@tonic-gate &len); 925*7c478bd9Sstevel@tonic-gate } 926*7c478bd9Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) { 927*7c478bd9Sstevel@tonic-gate (void) sprintf(name, "port-%c-%s", letter, property); 928*7c478bd9Sstevel@tonic-gate len = sizeof (val); 929*7c478bd9Sstevel@tonic-gate ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, 930*7c478bd9Sstevel@tonic-gate &len); 931*7c478bd9Sstevel@tonic-gate } 932*7c478bd9Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) 933*7c478bd9Sstevel@tonic-gate return (-1); /* property non-existant */ 934*7c478bd9Sstevel@tonic-gate if (val[0] == 'f' || val[0] == 'F' || val[0] == '0') 935*7c478bd9Sstevel@tonic-gate return (0); /* property false/0 */ 936*7c478bd9Sstevel@tonic-gate return (1); /* property true/!0 */ 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate /* asy_soft_state_free - local wrapper for ddi_soft_state_free(9F) */ 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate static void 942*7c478bd9Sstevel@tonic-gate asy_soft_state_free(struct asycom *asy) 943*7c478bd9Sstevel@tonic-gate { 944*7c478bd9Sstevel@tonic-gate mutex_enter(&asy_glob_lock); 945*7c478bd9Sstevel@tonic-gate /* If we were the max_asy_instance, work out new value */ 946*7c478bd9Sstevel@tonic-gate if (asy->asy_unit == max_asy_instance) { 947*7c478bd9Sstevel@tonic-gate while (--max_asy_instance >= 0) { 948*7c478bd9Sstevel@tonic-gate if (ddi_get_soft_state(asy_soft_state, 949*7c478bd9Sstevel@tonic-gate max_asy_instance) != NULL) 950*7c478bd9Sstevel@tonic-gate break; 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate } 953*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_glob_lock); 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate if (asy->asy_priv != NULL) { 956*7c478bd9Sstevel@tonic-gate kmem_free(asy->asy_priv, sizeof (struct asyncline)); 957*7c478bd9Sstevel@tonic-gate asy->asy_priv = NULL; 958*7c478bd9Sstevel@tonic-gate } 959*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(asy_soft_state, asy->asy_unit); 960*7c478bd9Sstevel@tonic-gate } 961*7c478bd9Sstevel@tonic-gate 962*7c478bd9Sstevel@tonic-gate static char * 963*7c478bd9Sstevel@tonic-gate asy_hw_name(struct asycom *asy) 964*7c478bd9Sstevel@tonic-gate { 965*7c478bd9Sstevel@tonic-gate switch (asy->asy_hwtype) { 966*7c478bd9Sstevel@tonic-gate case ASY8250A: 967*7c478bd9Sstevel@tonic-gate return ("8250A/16450"); 968*7c478bd9Sstevel@tonic-gate case ASY16550: 969*7c478bd9Sstevel@tonic-gate return ("16550"); 970*7c478bd9Sstevel@tonic-gate case ASY16550A: 971*7c478bd9Sstevel@tonic-gate return ("16550A"); 972*7c478bd9Sstevel@tonic-gate case ASY16650: 973*7c478bd9Sstevel@tonic-gate return ("16650"); 974*7c478bd9Sstevel@tonic-gate case ASY16750: 975*7c478bd9Sstevel@tonic-gate return ("16750"); 976*7c478bd9Sstevel@tonic-gate default: 977*7c478bd9Sstevel@tonic-gate DEBUGNOTE2(ASY_DEBUG_INIT, 978*7c478bd9Sstevel@tonic-gate "asy%d: asy_hw_name: unknown asy_hwtype: %d", 979*7c478bd9Sstevel@tonic-gate asy->asy_unit, asy->asy_hwtype); 980*7c478bd9Sstevel@tonic-gate return ("?"); 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate } 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate static int 985*7c478bd9Sstevel@tonic-gate asy_identify_chip(dev_info_t *devi, struct asycom *asy) 986*7c478bd9Sstevel@tonic-gate { 987*7c478bd9Sstevel@tonic-gate int ret; 988*7c478bd9Sstevel@tonic-gate int mcr; 989*7c478bd9Sstevel@tonic-gate dev_t dev; 990*7c478bd9Sstevel@tonic-gate uint_t hwtype; 991*7c478bd9Sstevel@tonic-gate 992*7c478bd9Sstevel@tonic-gate if (asy_scr_test) { 993*7c478bd9Sstevel@tonic-gate /* Check scratch register works. */ 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate /* write to scratch register */ 996*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + SCR, SCRTEST); 997*7c478bd9Sstevel@tonic-gate /* make sure that pattern doesn't just linger on the bus */ 998*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + FIFOR, 0x00); 999*7c478bd9Sstevel@tonic-gate /* read data back from scratch register */ 1000*7c478bd9Sstevel@tonic-gate ret = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + SCR); 1001*7c478bd9Sstevel@tonic-gate if (ret != SCRTEST) { 1002*7c478bd9Sstevel@tonic-gate /* 1003*7c478bd9Sstevel@tonic-gate * Scratch register not working. 1004*7c478bd9Sstevel@tonic-gate * Probably not an async chip. 1005*7c478bd9Sstevel@tonic-gate * 8250 and 8250B don't have scratch registers, 1006*7c478bd9Sstevel@tonic-gate * but only worked in ancient PC XT's anyway. 1007*7c478bd9Sstevel@tonic-gate */ 1008*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "asy%d: UART @ %p " 1009*7c478bd9Sstevel@tonic-gate "scratch register: expected 0x5a, got 0x%02x\n", 1010*7c478bd9Sstevel@tonic-gate asy->asy_unit, (void *)asy->asy_ioaddr, ret); 1011*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1012*7c478bd9Sstevel@tonic-gate } 1013*7c478bd9Sstevel@tonic-gate } 1014*7c478bd9Sstevel@tonic-gate /* 1015*7c478bd9Sstevel@tonic-gate * Use 16550 fifo reset sequence specified in NS application 1016*7c478bd9Sstevel@tonic-gate * note. Disable fifos until chip is initialized. 1017*7c478bd9Sstevel@tonic-gate */ 1018*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 1019*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + FIFOR, 0x00); /* clear */ 1020*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 1021*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + FIFOR, FIFO_ON); /* enable */ 1022*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 1023*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + FIFOR, FIFO_ON | FIFORXFLSH); 1024*7c478bd9Sstevel@tonic-gate /* reset */ 1025*7c478bd9Sstevel@tonic-gate if (asymaxchip >= ASY16650 && asy_scr_test) { 1026*7c478bd9Sstevel@tonic-gate /* 1027*7c478bd9Sstevel@tonic-gate * Reset 16650 enhanced regs also, in case we have one of these 1028*7c478bd9Sstevel@tonic-gate */ 1029*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1030*7c478bd9Sstevel@tonic-gate EFRACCESS); 1031*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + EFR, 1032*7c478bd9Sstevel@tonic-gate 0); 1033*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1034*7c478bd9Sstevel@tonic-gate STOP1|BITS8); 1035*7c478bd9Sstevel@tonic-gate } 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate /* 1038*7c478bd9Sstevel@tonic-gate * See what sort of FIFO we have. 1039*7c478bd9Sstevel@tonic-gate * Try enabling it and see what chip makes of this. 1040*7c478bd9Sstevel@tonic-gate */ 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate asy->asy_fifor = 0; 1043*7c478bd9Sstevel@tonic-gate asy->asy_hwtype = asymaxchip; /* just for asy_reset_fifo() */ 1044*7c478bd9Sstevel@tonic-gate if (asymaxchip >= ASY16550A) 1045*7c478bd9Sstevel@tonic-gate asy->asy_fifor |= 1046*7c478bd9Sstevel@tonic-gate FIFO_ON | FIFODMA | (asy_trig_level & 0xff); 1047*7c478bd9Sstevel@tonic-gate if (asymaxchip >= ASY16650) 1048*7c478bd9Sstevel@tonic-gate asy->asy_fifor |= FIFOEXTRA1 | FIFOEXTRA2; 1049*7c478bd9Sstevel@tonic-gate 1050*7c478bd9Sstevel@tonic-gate asy_reset_fifo(asy, FIFOTXFLSH | FIFORXFLSH); 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate mcr = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + MCR); 1053*7c478bd9Sstevel@tonic-gate ret = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + ISR); 1054*7c478bd9Sstevel@tonic-gate DEBUGCONT4(ASY_DEBUG_CHIP, 1055*7c478bd9Sstevel@tonic-gate "asy%d: probe fifo FIFOR=0x%02x ISR=0x%02x MCR=0x%02x\n", 1056*7c478bd9Sstevel@tonic-gate asy->asy_unit, asy->asy_fifor | FIFOTXFLSH | FIFORXFLSH, 1057*7c478bd9Sstevel@tonic-gate ret, mcr); 1058*7c478bd9Sstevel@tonic-gate switch (ret & 0xf0) { 1059*7c478bd9Sstevel@tonic-gate case 0x40: 1060*7c478bd9Sstevel@tonic-gate hwtype = ASY16550; /* 16550 with broken FIFO */ 1061*7c478bd9Sstevel@tonic-gate asy->asy_fifor = 0; 1062*7c478bd9Sstevel@tonic-gate break; 1063*7c478bd9Sstevel@tonic-gate case 0xc0: 1064*7c478bd9Sstevel@tonic-gate hwtype = ASY16550A; 1065*7c478bd9Sstevel@tonic-gate asy->asy_fifo_buf = 16; 1066*7c478bd9Sstevel@tonic-gate asy->asy_use_fifo = FIFO_ON; 1067*7c478bd9Sstevel@tonic-gate asy->asy_fifor &= ~(FIFOEXTRA1 | FIFOEXTRA2); 1068*7c478bd9Sstevel@tonic-gate break; 1069*7c478bd9Sstevel@tonic-gate case 0xe0: 1070*7c478bd9Sstevel@tonic-gate hwtype = ASY16650; 1071*7c478bd9Sstevel@tonic-gate asy->asy_fifo_buf = 32; 1072*7c478bd9Sstevel@tonic-gate asy->asy_use_fifo = FIFO_ON; 1073*7c478bd9Sstevel@tonic-gate asy->asy_fifor &= ~(FIFOEXTRA1); 1074*7c478bd9Sstevel@tonic-gate break; 1075*7c478bd9Sstevel@tonic-gate case 0xf0: 1076*7c478bd9Sstevel@tonic-gate /* 1077*7c478bd9Sstevel@tonic-gate * Note we get 0xff if chip didn't return us anything, 1078*7c478bd9Sstevel@tonic-gate * e.g. if there's no chip there. 1079*7c478bd9Sstevel@tonic-gate */ 1080*7c478bd9Sstevel@tonic-gate if (ret == 0xff) { 1081*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "asy%d: UART @ %p " 1082*7c478bd9Sstevel@tonic-gate "interrupt register: got 0xff\n", 1083*7c478bd9Sstevel@tonic-gate asy->asy_unit, (void *)asy->asy_ioaddr); 1084*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1085*7c478bd9Sstevel@tonic-gate } 1086*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 1087*7c478bd9Sstevel@tonic-gate case 0xd0: 1088*7c478bd9Sstevel@tonic-gate hwtype = ASY16750; 1089*7c478bd9Sstevel@tonic-gate asy->asy_fifo_buf = 64; 1090*7c478bd9Sstevel@tonic-gate asy->asy_use_fifo = FIFO_ON; 1091*7c478bd9Sstevel@tonic-gate break; 1092*7c478bd9Sstevel@tonic-gate default: 1093*7c478bd9Sstevel@tonic-gate hwtype = ASY8250A; /* No FIFO */ 1094*7c478bd9Sstevel@tonic-gate asy->asy_fifor = 0; 1095*7c478bd9Sstevel@tonic-gate } 1096*7c478bd9Sstevel@tonic-gate 1097*7c478bd9Sstevel@tonic-gate if (hwtype > asymaxchip) { 1098*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "asy%d: UART @ %p " 1099*7c478bd9Sstevel@tonic-gate "unexpected probe result: " 1100*7c478bd9Sstevel@tonic-gate "FIFOR=0x%02x ISR=0x%02x MCR=0x%02x\n", 1101*7c478bd9Sstevel@tonic-gate asy->asy_unit, (void *)asy->asy_ioaddr, 1102*7c478bd9Sstevel@tonic-gate asy->asy_fifor | FIFOTXFLSH | FIFORXFLSH, ret, mcr); 1103*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1104*7c478bd9Sstevel@tonic-gate } 1105*7c478bd9Sstevel@tonic-gate 1106*7c478bd9Sstevel@tonic-gate /* 1107*7c478bd9Sstevel@tonic-gate * Now reset the FIFO operation appropriate for the chip type. 1108*7c478bd9Sstevel@tonic-gate * Note we must call asy_reset_fifo() before any possible 1109*7c478bd9Sstevel@tonic-gate * downgrade of the asy->asy_hwtype, or it may not disable 1110*7c478bd9Sstevel@tonic-gate * the more advanced features we specifically want downgraded. 1111*7c478bd9Sstevel@tonic-gate */ 1112*7c478bd9Sstevel@tonic-gate asy_reset_fifo(asy, 0); 1113*7c478bd9Sstevel@tonic-gate asy->asy_hwtype = hwtype; 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * Check for Exar/Startech ST16C650, which will still look like a 1117*7c478bd9Sstevel@tonic-gate * 16550A until we enable its enhanced mode. 1118*7c478bd9Sstevel@tonic-gate */ 1119*7c478bd9Sstevel@tonic-gate if (asy->asy_hwtype == ASY16550A && asymaxchip >= ASY16650 && 1120*7c478bd9Sstevel@tonic-gate asy_scr_test) { 1121*7c478bd9Sstevel@tonic-gate /* Enable enhanced mode register access */ 1122*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1123*7c478bd9Sstevel@tonic-gate EFRACCESS); 1124*7c478bd9Sstevel@tonic-gate /* zero scratch register (not scratch register if enhanced) */ 1125*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + SCR, 0); 1126*7c478bd9Sstevel@tonic-gate /* Disable enhanced mode register access */ 1127*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1128*7c478bd9Sstevel@tonic-gate STOP1|BITS8); 1129*7c478bd9Sstevel@tonic-gate /* read back scratch register */ 1130*7c478bd9Sstevel@tonic-gate ret = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + SCR); 1131*7c478bd9Sstevel@tonic-gate if (ret == SCRTEST) { 1132*7c478bd9Sstevel@tonic-gate /* looks like we have an ST16650 -- enable it */ 1133*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1134*7c478bd9Sstevel@tonic-gate EFRACCESS); 1135*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + EFR, 1136*7c478bd9Sstevel@tonic-gate ENHENABLE); 1137*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1138*7c478bd9Sstevel@tonic-gate STOP1|BITS8); 1139*7c478bd9Sstevel@tonic-gate asy->asy_hwtype = ASY16650; 1140*7c478bd9Sstevel@tonic-gate asy->asy_fifo_buf = 32; 1141*7c478bd9Sstevel@tonic-gate asy->asy_fifor |= 0x10; /* 24 byte txfifo trigger */ 1142*7c478bd9Sstevel@tonic-gate asy_reset_fifo(asy, 0); 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate } 1145*7c478bd9Sstevel@tonic-gate 1146*7c478bd9Sstevel@tonic-gate /* 1147*7c478bd9Sstevel@tonic-gate * If we think we might have a FIFO larger than 16 characters, 1148*7c478bd9Sstevel@tonic-gate * measure FIFO size and check it against expected. 1149*7c478bd9Sstevel@tonic-gate */ 1150*7c478bd9Sstevel@tonic-gate if (asy_fifo_test > 0 && 1151*7c478bd9Sstevel@tonic-gate !(asy->asy_flags2 & ASY2_NO_LOOPBACK) && 1152*7c478bd9Sstevel@tonic-gate (asy->asy_fifo_buf > 16 || 1153*7c478bd9Sstevel@tonic-gate (asy_fifo_test > 1 && asy->asy_use_fifo == FIFO_ON) || 1154*7c478bd9Sstevel@tonic-gate ASY_DEBUG(ASY_DEBUG_CHIP))) { 1155*7c478bd9Sstevel@tonic-gate int i; 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate /* Set baud rate to 57600 (fairly arbitrary choice) */ 1158*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1159*7c478bd9Sstevel@tonic-gate DLAB); 1160*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + DAT, 1161*7c478bd9Sstevel@tonic-gate asyspdtab[B57600] & 0xff); 1162*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, 1163*7c478bd9Sstevel@tonic-gate (asyspdtab[B57600] >> 8) & 0xff); 1164*7c478bd9Sstevel@tonic-gate /* Set 8 bits, 1 stop bit */ 1165*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1166*7c478bd9Sstevel@tonic-gate STOP1|BITS8); 1167*7c478bd9Sstevel@tonic-gate /* Set loopback mode */ 1168*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, 1169*7c478bd9Sstevel@tonic-gate DTR | RTS | ASY_LOOP | OUT1 | OUT2); 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate /* Overfill fifo */ 1172*7c478bd9Sstevel@tonic-gate for (i = 0; i < asy->asy_fifo_buf * 2; i++) { 1173*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 1174*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT, i); 1175*7c478bd9Sstevel@tonic-gate } 1176*7c478bd9Sstevel@tonic-gate /* 1177*7c478bd9Sstevel@tonic-gate * Now there's an interesting question here about which 1178*7c478bd9Sstevel@tonic-gate * FIFO we're testing the size of, RX or TX. We just 1179*7c478bd9Sstevel@tonic-gate * filled the TX FIFO much faster than it can empty, 1180*7c478bd9Sstevel@tonic-gate * although it is possible one or two characters may 1181*7c478bd9Sstevel@tonic-gate * have gone from it to the TX shift register. 1182*7c478bd9Sstevel@tonic-gate * We wait for enough time for all the characters to 1183*7c478bd9Sstevel@tonic-gate * move into the RX FIFO and any excess characters to 1184*7c478bd9Sstevel@tonic-gate * have been lost, and then read all the RX FIFO. So 1185*7c478bd9Sstevel@tonic-gate * the answer we finally get will be the size which is 1186*7c478bd9Sstevel@tonic-gate * the MIN(RX FIFO,(TX FIFO + 1 or 2)). The critical 1187*7c478bd9Sstevel@tonic-gate * one is actually the TX FIFO, because if we overfill 1188*7c478bd9Sstevel@tonic-gate * it in normal operation, the excess characters are 1189*7c478bd9Sstevel@tonic-gate * lost with no warning. 1190*7c478bd9Sstevel@tonic-gate */ 1191*7c478bd9Sstevel@tonic-gate /* 1192*7c478bd9Sstevel@tonic-gate * Wait for characters to move into RX FIFO. 1193*7c478bd9Sstevel@tonic-gate * In theory, 200 * asy->asy_fifo_buf * 2 should be 1194*7c478bd9Sstevel@tonic-gate * enough. However, in practice it isn't always, so we 1195*7c478bd9Sstevel@tonic-gate * increase to 400 so some slow 16550A's finish, and we 1196*7c478bd9Sstevel@tonic-gate * increase to 3 so we spot more characters coming back 1197*7c478bd9Sstevel@tonic-gate * than we sent, in case that should ever happen. 1198*7c478bd9Sstevel@tonic-gate */ 1199*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(400 * asy->asy_fifo_buf * 3)); 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate /* Now see how many characters we can read back */ 1202*7c478bd9Sstevel@tonic-gate for (i = 0; i < asy->asy_fifo_buf * 3; i++) { 1203*7c478bd9Sstevel@tonic-gate ret = ddi_io_get8(asy->asy_iohandle, 1204*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR); 1205*7c478bd9Sstevel@tonic-gate if (!(ret & RCA)) 1206*7c478bd9Sstevel@tonic-gate break; /* FIFO emptied */ 1207*7c478bd9Sstevel@tonic-gate (void) ddi_io_get8(asy->asy_iohandle, 1208*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT); /* lose another */ 1209*7c478bd9Sstevel@tonic-gate } 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate DEBUGCONT3(ASY_DEBUG_CHIP, 1212*7c478bd9Sstevel@tonic-gate "asy%d FIFO size: expected=%d, measured=%d\n", 1213*7c478bd9Sstevel@tonic-gate asy->asy_unit, asy->asy_fifo_buf, i); 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate hwtype = asy->asy_hwtype; 1216*7c478bd9Sstevel@tonic-gate if (i < asy->asy_fifo_buf) { 1217*7c478bd9Sstevel@tonic-gate /* 1218*7c478bd9Sstevel@tonic-gate * FIFO is somewhat smaller than we anticipated. 1219*7c478bd9Sstevel@tonic-gate * If we have 16 characters usable, then this 1220*7c478bd9Sstevel@tonic-gate * UART will probably work well enough in 1221*7c478bd9Sstevel@tonic-gate * 16550A mode. If less than 16 characters, 1222*7c478bd9Sstevel@tonic-gate * then we'd better not use it at all. 1223*7c478bd9Sstevel@tonic-gate * UARTs with busted FIFOs do crop up. 1224*7c478bd9Sstevel@tonic-gate */ 1225*7c478bd9Sstevel@tonic-gate if (i >= 16 && asy->asy_fifo_buf >= 16) { 1226*7c478bd9Sstevel@tonic-gate /* fall back to a 16550A */ 1227*7c478bd9Sstevel@tonic-gate hwtype = ASY16550A; 1228*7c478bd9Sstevel@tonic-gate asy->asy_fifo_buf = 16; 1229*7c478bd9Sstevel@tonic-gate asy->asy_fifor &= ~(FIFOEXTRA1 | FIFOEXTRA2); 1230*7c478bd9Sstevel@tonic-gate } else { 1231*7c478bd9Sstevel@tonic-gate /* fall back to no FIFO at all */ 1232*7c478bd9Sstevel@tonic-gate hwtype = ASY16550; 1233*7c478bd9Sstevel@tonic-gate asy->asy_fifo_buf = 1; 1234*7c478bd9Sstevel@tonic-gate asy->asy_use_fifo = FIFO_OFF; 1235*7c478bd9Sstevel@tonic-gate asy->asy_fifor &= 1236*7c478bd9Sstevel@tonic-gate ~(FIFO_ON | FIFOEXTRA1 | FIFOEXTRA2); 1237*7c478bd9Sstevel@tonic-gate } 1238*7c478bd9Sstevel@tonic-gate } 1239*7c478bd9Sstevel@tonic-gate /* 1240*7c478bd9Sstevel@tonic-gate * We will need to reprogram the FIFO if we changed 1241*7c478bd9Sstevel@tonic-gate * our mind about how to drive it above, and in any 1242*7c478bd9Sstevel@tonic-gate * case, it would be a good idea to flush any garbage 1243*7c478bd9Sstevel@tonic-gate * out incase the loopback test left anything behind. 1244*7c478bd9Sstevel@tonic-gate * Again as earlier above, we must call asy_reset_fifo() 1245*7c478bd9Sstevel@tonic-gate * before any possible downgrade of asy->asy_hwtype. 1246*7c478bd9Sstevel@tonic-gate */ 1247*7c478bd9Sstevel@tonic-gate if (asy->asy_hwtype >= ASY16650 && hwtype < ASY16650) { 1248*7c478bd9Sstevel@tonic-gate /* Disable 16650 enhanced mode */ 1249*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1250*7c478bd9Sstevel@tonic-gate EFRACCESS); 1251*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + EFR, 1252*7c478bd9Sstevel@tonic-gate 0); 1253*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1254*7c478bd9Sstevel@tonic-gate STOP1|BITS8); 1255*7c478bd9Sstevel@tonic-gate } 1256*7c478bd9Sstevel@tonic-gate asy_reset_fifo(asy, FIFOTXFLSH | FIFORXFLSH); 1257*7c478bd9Sstevel@tonic-gate asy->asy_hwtype = hwtype; 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate /* Clear loopback mode and restore DTR/RTS */ 1260*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, mcr); 1261*7c478bd9Sstevel@tonic-gate } 1262*7c478bd9Sstevel@tonic-gate 1263*7c478bd9Sstevel@tonic-gate DEBUGNOTE3(ASY_DEBUG_CHIP, "asy%d %s @ %p", 1264*7c478bd9Sstevel@tonic-gate asy->asy_unit, asy_hw_name(asy), (void *)asy->asy_ioaddr); 1265*7c478bd9Sstevel@tonic-gate 1266*7c478bd9Sstevel@tonic-gate /* Make UART type visible in device tree for prtconf, etc */ 1267*7c478bd9Sstevel@tonic-gate dev = makedevice(DDI_MAJOR_T_UNKNOWN, asy->asy_unit); 1268*7c478bd9Sstevel@tonic-gate (void) ddi_prop_update_string(dev, devi, "uart", asy_hw_name(asy)); 1269*7c478bd9Sstevel@tonic-gate 1270*7c478bd9Sstevel@tonic-gate if (asy->asy_hwtype == ASY16550) /* for broken 16550's, */ 1271*7c478bd9Sstevel@tonic-gate asy->asy_hwtype = ASY8250A; /* drive them as 8250A */ 1272*7c478bd9Sstevel@tonic-gate 1273*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1274*7c478bd9Sstevel@tonic-gate } 1275*7c478bd9Sstevel@tonic-gate 1276*7c478bd9Sstevel@tonic-gate /* 1277*7c478bd9Sstevel@tonic-gate * asyinit() initializes the TTY protocol-private data for this channel 1278*7c478bd9Sstevel@tonic-gate * before enabling the interrupts. 1279*7c478bd9Sstevel@tonic-gate */ 1280*7c478bd9Sstevel@tonic-gate static void 1281*7c478bd9Sstevel@tonic-gate asyinit(struct asycom *asy) 1282*7c478bd9Sstevel@tonic-gate { 1283*7c478bd9Sstevel@tonic-gate struct asyncline *async; 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate asy->asy_priv = kmem_zalloc(sizeof (struct asyncline), KM_SLEEP); 1286*7c478bd9Sstevel@tonic-gate async = asy->asy_priv; 1287*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 1288*7c478bd9Sstevel@tonic-gate async->async_common = asy; 1289*7c478bd9Sstevel@tonic-gate cv_init(&async->async_flags_cv, NULL, CV_DRIVER, NULL); 1290*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1291*7c478bd9Sstevel@tonic-gate } 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate /*ARGSUSED3*/ 1294*7c478bd9Sstevel@tonic-gate static int 1295*7c478bd9Sstevel@tonic-gate asyopen(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 1296*7c478bd9Sstevel@tonic-gate { 1297*7c478bd9Sstevel@tonic-gate struct asycom *asy; 1298*7c478bd9Sstevel@tonic-gate struct asyncline *async; 1299*7c478bd9Sstevel@tonic-gate int mcr; 1300*7c478bd9Sstevel@tonic-gate int unit; 1301*7c478bd9Sstevel@tonic-gate int len; 1302*7c478bd9Sstevel@tonic-gate struct termios *termiosp; 1303*7c478bd9Sstevel@tonic-gate 1304*7c478bd9Sstevel@tonic-gate unit = UNIT(*dev); 1305*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_CLOSE, "asy%dopen\n", unit); 1306*7c478bd9Sstevel@tonic-gate asy = ddi_get_soft_state(asy_soft_state, unit); 1307*7c478bd9Sstevel@tonic-gate if (asy == NULL) 1308*7c478bd9Sstevel@tonic-gate return (ENXIO); /* unit not configured */ 1309*7c478bd9Sstevel@tonic-gate async = asy->asy_priv; 1310*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 1311*7c478bd9Sstevel@tonic-gate 1312*7c478bd9Sstevel@tonic-gate again: 1313*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 1314*7c478bd9Sstevel@tonic-gate 1315*7c478bd9Sstevel@tonic-gate /* 1316*7c478bd9Sstevel@tonic-gate * Block waiting for carrier to come up, unless this is a no-delay open. 1317*7c478bd9Sstevel@tonic-gate */ 1318*7c478bd9Sstevel@tonic-gate if (!(async->async_flags & ASYNC_ISOPEN)) { 1319*7c478bd9Sstevel@tonic-gate /* 1320*7c478bd9Sstevel@tonic-gate * Set the default termios settings (cflag). 1321*7c478bd9Sstevel@tonic-gate * Others are set in ldterm. 1322*7c478bd9Sstevel@tonic-gate */ 1323*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1324*7c478bd9Sstevel@tonic-gate 1325*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 1326*7c478bd9Sstevel@tonic-gate 0, "ttymodes", 1327*7c478bd9Sstevel@tonic-gate (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS && 1328*7c478bd9Sstevel@tonic-gate len == sizeof (struct termios)) { 1329*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag = termiosp->c_cflag; 1330*7c478bd9Sstevel@tonic-gate kmem_free(termiosp, len); 1331*7c478bd9Sstevel@tonic-gate } else 1332*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1333*7c478bd9Sstevel@tonic-gate "asy: couldn't get ttymodes property!"); 1334*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 1335*7c478bd9Sstevel@tonic-gate 1336*7c478bd9Sstevel@tonic-gate /* eeprom mode support - respect properties */ 1337*7c478bd9Sstevel@tonic-gate if (asy->asy_cflag) 1338*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag = asy->asy_cflag; 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_iflag = 0; 1341*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_iocpending = NULL; 1342*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_size.ws_row = 0; 1343*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_size.ws_col = 0; 1344*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_size.ws_xpixel = 0; 1345*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_size.ws_ypixel = 0; 1346*7c478bd9Sstevel@tonic-gate async->async_dev = *dev; 1347*7c478bd9Sstevel@tonic-gate async->async_wbufcid = 0; 1348*7c478bd9Sstevel@tonic-gate 1349*7c478bd9Sstevel@tonic-gate async->async_startc = CSTART; 1350*7c478bd9Sstevel@tonic-gate async->async_stopc = CSTOP; 1351*7c478bd9Sstevel@tonic-gate asy_program(asy, ASY_INIT); 1352*7c478bd9Sstevel@tonic-gate } else if ((async->async_ttycommon.t_flags & TS_XCLUDE) && 1353*7c478bd9Sstevel@tonic-gate secpolicy_excl_open(cr) != 0) { 1354*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1355*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1356*7c478bd9Sstevel@tonic-gate return (EBUSY); 1357*7c478bd9Sstevel@tonic-gate } else if ((*dev & OUTLINE) && !(async->async_flags & ASYNC_OUT)) { 1358*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1359*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1360*7c478bd9Sstevel@tonic-gate return (EBUSY); 1361*7c478bd9Sstevel@tonic-gate } 1362*7c478bd9Sstevel@tonic-gate 1363*7c478bd9Sstevel@tonic-gate if (*dev & OUTLINE) 1364*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_OUT; 1365*7c478bd9Sstevel@tonic-gate 1366*7c478bd9Sstevel@tonic-gate /* Raise DTR on every open, but delay if it was just lowered. */ 1367*7c478bd9Sstevel@tonic-gate while (async->async_flags & ASYNC_DTR_DELAY) { 1368*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 1369*7c478bd9Sstevel@tonic-gate "asy%dopen: waiting for the ASYNC_DTR_DELAY to be clear\n", 1370*7c478bd9Sstevel@tonic-gate unit); 1371*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1372*7c478bd9Sstevel@tonic-gate if (cv_wait_sig(&async->async_flags_cv, 1373*7c478bd9Sstevel@tonic-gate &asy->asy_excl) == 0) { 1374*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 1375*7c478bd9Sstevel@tonic-gate "asy%dopen: interrupted by signal, exiting\n", 1376*7c478bd9Sstevel@tonic-gate unit); 1377*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1378*7c478bd9Sstevel@tonic-gate return (EINTR); 1379*7c478bd9Sstevel@tonic-gate } 1380*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate mcr = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + MCR); 1384*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, 1385*7c478bd9Sstevel@tonic-gate mcr|(asy->asy_mcr&DTR)); 1386*7c478bd9Sstevel@tonic-gate 1387*7c478bd9Sstevel@tonic-gate DEBUGCONT3(ASY_DEBUG_INIT, 1388*7c478bd9Sstevel@tonic-gate "asy%dopen: \"Raise DTR on every open\": make mcr = %x, " 1389*7c478bd9Sstevel@tonic-gate "make TS_SOFTCAR = %s\n", 1390*7c478bd9Sstevel@tonic-gate unit, mcr|(asy->asy_mcr&DTR), 1391*7c478bd9Sstevel@tonic-gate (asy->asy_flags & ASY_IGNORE_CD) ? "ON" : "OFF"); 1392*7c478bd9Sstevel@tonic-gate if (asy->asy_flags & ASY_IGNORE_CD) { 1393*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 1394*7c478bd9Sstevel@tonic-gate "asy%dopen: ASY_IGNORE_CD set, set TS_SOFTCAR\n", 1395*7c478bd9Sstevel@tonic-gate unit); 1396*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_flags |= TS_SOFTCAR; 1397*7c478bd9Sstevel@tonic-gate } 1398*7c478bd9Sstevel@tonic-gate else 1399*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_flags &= ~TS_SOFTCAR; 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate /* 1402*7c478bd9Sstevel@tonic-gate * Check carrier. 1403*7c478bd9Sstevel@tonic-gate */ 1404*7c478bd9Sstevel@tonic-gate asy->asy_msr = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + MSR); 1405*7c478bd9Sstevel@tonic-gate DEBUGCONT3(ASY_DEBUG_INIT, "asy%dopen: TS_SOFTCAR is %s, " 1406*7c478bd9Sstevel@tonic-gate "MSR & DCD is %s\n", 1407*7c478bd9Sstevel@tonic-gate unit, 1408*7c478bd9Sstevel@tonic-gate (async->async_ttycommon.t_flags & TS_SOFTCAR) ? "set" : "clear", 1409*7c478bd9Sstevel@tonic-gate (asy->asy_msr & DCD) ? "set" : "clear"); 1410*7c478bd9Sstevel@tonic-gate if (asy->asy_msr & DCD) 1411*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_CARR_ON; 1412*7c478bd9Sstevel@tonic-gate else 1413*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_CARR_ON; 1414*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1415*7c478bd9Sstevel@tonic-gate 1416*7c478bd9Sstevel@tonic-gate /* 1417*7c478bd9Sstevel@tonic-gate * If FNDELAY and FNONBLOCK are clear, block until carrier up. 1418*7c478bd9Sstevel@tonic-gate * Quit on interrupt. 1419*7c478bd9Sstevel@tonic-gate */ 1420*7c478bd9Sstevel@tonic-gate if (!(flag & (FNDELAY|FNONBLOCK)) && 1421*7c478bd9Sstevel@tonic-gate !(async->async_ttycommon.t_cflag & CLOCAL)) { 1422*7c478bd9Sstevel@tonic-gate if ((!(async->async_flags & (ASYNC_CARR_ON|ASYNC_OUT)) && 1423*7c478bd9Sstevel@tonic-gate !(async->async_ttycommon.t_flags & TS_SOFTCAR)) || 1424*7c478bd9Sstevel@tonic-gate ((async->async_flags & ASYNC_OUT) && 1425*7c478bd9Sstevel@tonic-gate !(*dev & OUTLINE))) { 1426*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_WOPEN; 1427*7c478bd9Sstevel@tonic-gate if (cv_wait_sig(&async->async_flags_cv, 1428*7c478bd9Sstevel@tonic-gate &asy->asy_excl) == B_FALSE) { 1429*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_WOPEN; 1430*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1431*7c478bd9Sstevel@tonic-gate return (EINTR); 1432*7c478bd9Sstevel@tonic-gate } 1433*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_WOPEN; 1434*7c478bd9Sstevel@tonic-gate goto again; 1435*7c478bd9Sstevel@tonic-gate } 1436*7c478bd9Sstevel@tonic-gate } else if ((async->async_flags & ASYNC_OUT) && !(*dev & OUTLINE)) { 1437*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1438*7c478bd9Sstevel@tonic-gate return (EBUSY); 1439*7c478bd9Sstevel@tonic-gate } 1440*7c478bd9Sstevel@tonic-gate 1441*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_readq = rq; 1442*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_writeq = WR(rq); 1443*7c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = (caddr_t)async; 1444*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1445*7c478bd9Sstevel@tonic-gate /* 1446*7c478bd9Sstevel@tonic-gate * Caution here -- qprocson sets the pointers that are used by canput 1447*7c478bd9Sstevel@tonic-gate * called by async_softint. ASYNC_ISOPEN must *not* be set until those 1448*7c478bd9Sstevel@tonic-gate * pointers are valid. 1449*7c478bd9Sstevel@tonic-gate */ 1450*7c478bd9Sstevel@tonic-gate qprocson(rq); 1451*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_ISOPEN; 1452*7c478bd9Sstevel@tonic-gate async->async_polltid = 0; 1453*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_INIT, "asy%dopen: done\n", unit); 1454*7c478bd9Sstevel@tonic-gate return (0); 1455*7c478bd9Sstevel@tonic-gate } 1456*7c478bd9Sstevel@tonic-gate 1457*7c478bd9Sstevel@tonic-gate static void 1458*7c478bd9Sstevel@tonic-gate async_progress_check(void *arg) 1459*7c478bd9Sstevel@tonic-gate { 1460*7c478bd9Sstevel@tonic-gate struct asyncline *async = arg; 1461*7c478bd9Sstevel@tonic-gate struct asycom *asy = async->async_common; 1462*7c478bd9Sstevel@tonic-gate mblk_t *bp; 1463*7c478bd9Sstevel@tonic-gate 1464*7c478bd9Sstevel@tonic-gate /* 1465*7c478bd9Sstevel@tonic-gate * We define "progress" as either waiting on a timed break or delay, or 1466*7c478bd9Sstevel@tonic-gate * having had at least one transmitter interrupt. If none of these are 1467*7c478bd9Sstevel@tonic-gate * true, then just terminate the output and wake up that close thread. 1468*7c478bd9Sstevel@tonic-gate */ 1469*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 1470*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 1471*7c478bd9Sstevel@tonic-gate if (!(async->async_flags & (ASYNC_BREAK|ASYNC_DELAY|ASYNC_PROGRESS))) { 1472*7c478bd9Sstevel@tonic-gate async->async_ocnt = 0; 1473*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_BUSY; 1474*7c478bd9Sstevel@tonic-gate async->async_timer = 0; 1475*7c478bd9Sstevel@tonic-gate bp = async->async_xmitblk; 1476*7c478bd9Sstevel@tonic-gate async->async_xmitblk = NULL; 1477*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1478*7c478bd9Sstevel@tonic-gate if (bp != NULL) 1479*7c478bd9Sstevel@tonic-gate freeb(bp); 1480*7c478bd9Sstevel@tonic-gate /* 1481*7c478bd9Sstevel@tonic-gate * Since this timer is running, we know that we're in exit(2). 1482*7c478bd9Sstevel@tonic-gate * That means that the user can't possibly be waiting on any 1483*7c478bd9Sstevel@tonic-gate * valid ioctl(2) completion anymore, and we should just flush 1484*7c478bd9Sstevel@tonic-gate * everything. 1485*7c478bd9Sstevel@tonic-gate */ 1486*7c478bd9Sstevel@tonic-gate flushq(async->async_ttycommon.t_writeq, FLUSHALL); 1487*7c478bd9Sstevel@tonic-gate cv_broadcast(&async->async_flags_cv); 1488*7c478bd9Sstevel@tonic-gate } else { 1489*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_PROGRESS; 1490*7c478bd9Sstevel@tonic-gate async->async_timer = timeout(async_progress_check, async, 1491*7c478bd9Sstevel@tonic-gate drv_usectohz(asy_drain_check)); 1492*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1493*7c478bd9Sstevel@tonic-gate } 1494*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1495*7c478bd9Sstevel@tonic-gate } 1496*7c478bd9Sstevel@tonic-gate 1497*7c478bd9Sstevel@tonic-gate /* 1498*7c478bd9Sstevel@tonic-gate * Release DTR so that asyopen() can raise it. 1499*7c478bd9Sstevel@tonic-gate */ 1500*7c478bd9Sstevel@tonic-gate static void 1501*7c478bd9Sstevel@tonic-gate async_dtr_free(struct asyncline *async) 1502*7c478bd9Sstevel@tonic-gate { 1503*7c478bd9Sstevel@tonic-gate struct asycom *asy = async->async_common; 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate DEBUGCONT0(ASY_DEBUG_MODEM, 1506*7c478bd9Sstevel@tonic-gate "async_dtr_free, clearing ASYNC_DTR_DELAY\n"); 1507*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 1508*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_DTR_DELAY; 1509*7c478bd9Sstevel@tonic-gate async->async_dtrtid = 0; 1510*7c478bd9Sstevel@tonic-gate cv_broadcast(&async->async_flags_cv); 1511*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1512*7c478bd9Sstevel@tonic-gate } 1513*7c478bd9Sstevel@tonic-gate 1514*7c478bd9Sstevel@tonic-gate /* 1515*7c478bd9Sstevel@tonic-gate * Close routine. 1516*7c478bd9Sstevel@tonic-gate */ 1517*7c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 1518*7c478bd9Sstevel@tonic-gate static int 1519*7c478bd9Sstevel@tonic-gate asyclose(queue_t *q, int flag, cred_t *credp) 1520*7c478bd9Sstevel@tonic-gate { 1521*7c478bd9Sstevel@tonic-gate struct asyncline *async; 1522*7c478bd9Sstevel@tonic-gate struct asycom *asy; 1523*7c478bd9Sstevel@tonic-gate int icr, lcr; 1524*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1525*7c478bd9Sstevel@tonic-gate int instance; 1526*7c478bd9Sstevel@tonic-gate #endif 1527*7c478bd9Sstevel@tonic-gate 1528*7c478bd9Sstevel@tonic-gate async = (struct asyncline *)q->q_ptr; 1529*7c478bd9Sstevel@tonic-gate ASSERT(async != NULL); 1530*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1531*7c478bd9Sstevel@tonic-gate instance = UNIT(async->async_dev); 1532*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_CLOSE, "asy%dclose\n", instance); 1533*7c478bd9Sstevel@tonic-gate #endif 1534*7c478bd9Sstevel@tonic-gate asy = async->async_common; 1535*7c478bd9Sstevel@tonic-gate 1536*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 1537*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_CLOSING; 1538*7c478bd9Sstevel@tonic-gate 1539*7c478bd9Sstevel@tonic-gate /* 1540*7c478bd9Sstevel@tonic-gate * Turn off PPS handling early to avoid events occuring during 1541*7c478bd9Sstevel@tonic-gate * close. Also reset the DCD edge monitoring bit. 1542*7c478bd9Sstevel@tonic-gate */ 1543*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 1544*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~(ASY_PPS | ASY_PPS_EDGE); 1545*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1546*7c478bd9Sstevel@tonic-gate 1547*7c478bd9Sstevel@tonic-gate /* 1548*7c478bd9Sstevel@tonic-gate * There are two flavors of break -- timed (M_BREAK or TCSBRK) and 1549*7c478bd9Sstevel@tonic-gate * untimed (TIOCSBRK). For the timed case, these are enqueued on our 1550*7c478bd9Sstevel@tonic-gate * write queue and there's a timer running, so we don't have to worry 1551*7c478bd9Sstevel@tonic-gate * about them. For the untimed case, though, the user obviously made a 1552*7c478bd9Sstevel@tonic-gate * mistake, because these are handled immediately. We'll terminate the 1553*7c478bd9Sstevel@tonic-gate * break now and honor his implicit request by discarding the rest of 1554*7c478bd9Sstevel@tonic-gate * the data. 1555*7c478bd9Sstevel@tonic-gate */ 1556*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_OUT_SUSPEND) { 1557*7c478bd9Sstevel@tonic-gate if (async->async_utbrktid != 0) { 1558*7c478bd9Sstevel@tonic-gate (void) untimeout(async->async_utbrktid); 1559*7c478bd9Sstevel@tonic-gate async->async_utbrktid = 0; 1560*7c478bd9Sstevel@tonic-gate } 1561*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 1562*7c478bd9Sstevel@tonic-gate lcr = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + LCR); 1563*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 1564*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR, (lcr & ~SETBREAK)); 1565*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1566*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_OUT_SUSPEND; 1567*7c478bd9Sstevel@tonic-gate goto nodrain; 1568*7c478bd9Sstevel@tonic-gate } 1569*7c478bd9Sstevel@tonic-gate 1570*7c478bd9Sstevel@tonic-gate /* 1571*7c478bd9Sstevel@tonic-gate * If the user told us not to delay the close ("non-blocking"), then 1572*7c478bd9Sstevel@tonic-gate * don't bother trying to drain. 1573*7c478bd9Sstevel@tonic-gate * 1574*7c478bd9Sstevel@tonic-gate * If the user did M_STOP (ASYNC_STOPPED), there's no hope of ever 1575*7c478bd9Sstevel@tonic-gate * getting an M_START (since these messages aren't enqueued), and the 1576*7c478bd9Sstevel@tonic-gate * only other way to clear the stop condition is by loss of DCD, which 1577*7c478bd9Sstevel@tonic-gate * would discard the queue data. Thus, we drop the output data if 1578*7c478bd9Sstevel@tonic-gate * ASYNC_STOPPED is set. 1579*7c478bd9Sstevel@tonic-gate */ 1580*7c478bd9Sstevel@tonic-gate if ((flag & (FNDELAY|FNONBLOCK)) || 1581*7c478bd9Sstevel@tonic-gate (async->async_flags & ASYNC_STOPPED)) { 1582*7c478bd9Sstevel@tonic-gate goto nodrain; 1583*7c478bd9Sstevel@tonic-gate } 1584*7c478bd9Sstevel@tonic-gate 1585*7c478bd9Sstevel@tonic-gate /* 1586*7c478bd9Sstevel@tonic-gate * If there's any pending output, then we have to try to drain it. 1587*7c478bd9Sstevel@tonic-gate * There are two main cases to be handled: 1588*7c478bd9Sstevel@tonic-gate * - called by close(2): need to drain until done or until 1589*7c478bd9Sstevel@tonic-gate * a signal is received. No timeout. 1590*7c478bd9Sstevel@tonic-gate * - called by exit(2): need to drain while making progress 1591*7c478bd9Sstevel@tonic-gate * or until a timeout occurs. No signals. 1592*7c478bd9Sstevel@tonic-gate * 1593*7c478bd9Sstevel@tonic-gate * If we can't rely on receiving a signal to get us out of a hung 1594*7c478bd9Sstevel@tonic-gate * session, then we have to use a timer. In this case, we set a timer 1595*7c478bd9Sstevel@tonic-gate * to check for progress in sending the output data -- all that we ask 1596*7c478bd9Sstevel@tonic-gate * (at each interval) is that there's been some progress made. Since 1597*7c478bd9Sstevel@tonic-gate * the interrupt routine grabs buffers from the write queue, we can't 1598*7c478bd9Sstevel@tonic-gate * trust changes in async_ocnt. Instead, we use a progress flag. 1599*7c478bd9Sstevel@tonic-gate * 1600*7c478bd9Sstevel@tonic-gate * Note that loss of carrier will cause the output queue to be flushed, 1601*7c478bd9Sstevel@tonic-gate * and we'll wake up again and finish normally. 1602*7c478bd9Sstevel@tonic-gate */ 1603*7c478bd9Sstevel@tonic-gate if (!ddi_can_receive_sig() && asy_drain_check != 0) { 1604*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_PROGRESS; 1605*7c478bd9Sstevel@tonic-gate async->async_timer = timeout(async_progress_check, async, 1606*7c478bd9Sstevel@tonic-gate drv_usectohz(asy_drain_check)); 1607*7c478bd9Sstevel@tonic-gate } 1608*7c478bd9Sstevel@tonic-gate while (async->async_ocnt > 0 || 1609*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_writeq->q_first != NULL || 1610*7c478bd9Sstevel@tonic-gate (async->async_flags & (ASYNC_BUSY|ASYNC_BREAK|ASYNC_DELAY))) { 1611*7c478bd9Sstevel@tonic-gate if (cv_wait_sig(&async->async_flags_cv, &asy->asy_excl) == 0) 1612*7c478bd9Sstevel@tonic-gate break; 1613*7c478bd9Sstevel@tonic-gate } 1614*7c478bd9Sstevel@tonic-gate if (async->async_timer != 0) { 1615*7c478bd9Sstevel@tonic-gate (void) untimeout(async->async_timer); 1616*7c478bd9Sstevel@tonic-gate async->async_timer = 0; 1617*7c478bd9Sstevel@tonic-gate } 1618*7c478bd9Sstevel@tonic-gate 1619*7c478bd9Sstevel@tonic-gate nodrain: 1620*7c478bd9Sstevel@tonic-gate async->async_ocnt = 0; 1621*7c478bd9Sstevel@tonic-gate if (async->async_xmitblk != NULL) 1622*7c478bd9Sstevel@tonic-gate freeb(async->async_xmitblk); 1623*7c478bd9Sstevel@tonic-gate async->async_xmitblk = NULL; 1624*7c478bd9Sstevel@tonic-gate 1625*7c478bd9Sstevel@tonic-gate /* 1626*7c478bd9Sstevel@tonic-gate * If line has HUPCL set or is incompletely opened fix up the modem 1627*7c478bd9Sstevel@tonic-gate * lines. 1628*7c478bd9Sstevel@tonic-gate */ 1629*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 1630*7c478bd9Sstevel@tonic-gate "asy%dclose: next check HUPCL flag\n", instance); 1631*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 1632*7c478bd9Sstevel@tonic-gate if ((async->async_ttycommon.t_cflag & HUPCL) || 1633*7c478bd9Sstevel@tonic-gate (async->async_flags & ASYNC_WOPEN)) { 1634*7c478bd9Sstevel@tonic-gate DEBUGCONT3(ASY_DEBUG_MODEM, 1635*7c478bd9Sstevel@tonic-gate "asy%dclose: HUPCL flag = %x, ASYNC_WOPEN flag = %x\n", 1636*7c478bd9Sstevel@tonic-gate instance, 1637*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag & HUPCL, 1638*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag & ASYNC_WOPEN); 1639*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_DTR_DELAY; 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate /* turn off DTR, RTS but NOT interrupt to 386 */ 1642*7c478bd9Sstevel@tonic-gate if (asy->asy_flags & (ASY_IGNORE_CD|ASY_RTS_DTR_OFF)) { 1643*7c478bd9Sstevel@tonic-gate DEBUGCONT3(ASY_DEBUG_MODEM, 1644*7c478bd9Sstevel@tonic-gate "asy%dclose: ASY_IGNORE_CD flag = %x, " 1645*7c478bd9Sstevel@tonic-gate "ASY_RTS_DTR_OFF flag = %x\n", 1646*7c478bd9Sstevel@tonic-gate instance, 1647*7c478bd9Sstevel@tonic-gate asy->asy_flags & ASY_IGNORE_CD, 1648*7c478bd9Sstevel@tonic-gate asy->asy_flags & ASY_RTS_DTR_OFF); 1649*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 1650*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + MCR, asy->asy_mcr|OUT2); 1651*7c478bd9Sstevel@tonic-gate } else { 1652*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 1653*7c478bd9Sstevel@tonic-gate "asy%dclose: Dropping DTR and RTS\n", instance); 1654*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 1655*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + MCR, OUT2); 1656*7c478bd9Sstevel@tonic-gate } 1657*7c478bd9Sstevel@tonic-gate async->async_dtrtid = 1658*7c478bd9Sstevel@tonic-gate timeout((void (*)())async_dtr_free, 1659*7c478bd9Sstevel@tonic-gate (caddr_t)async, drv_usectohz(asy_min_dtr_low)); 1660*7c478bd9Sstevel@tonic-gate } 1661*7c478bd9Sstevel@tonic-gate /* 1662*7c478bd9Sstevel@tonic-gate * If nobody's using it now, turn off receiver interrupts. 1663*7c478bd9Sstevel@tonic-gate */ 1664*7c478bd9Sstevel@tonic-gate if ((async->async_flags & (ASYNC_WOPEN|ASYNC_ISOPEN)) == 0) { 1665*7c478bd9Sstevel@tonic-gate icr = ddi_io_get8(asy->asy_iohandle, 1666*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + ICR); 1667*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, 1668*7c478bd9Sstevel@tonic-gate (icr & ~RIEN)); 1669*7c478bd9Sstevel@tonic-gate } 1670*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1671*7c478bd9Sstevel@tonic-gate out: 1672*7c478bd9Sstevel@tonic-gate ttycommon_close(&async->async_ttycommon); 1673*7c478bd9Sstevel@tonic-gate 1674*7c478bd9Sstevel@tonic-gate /* 1675*7c478bd9Sstevel@tonic-gate * Cancel outstanding "bufcall" request. 1676*7c478bd9Sstevel@tonic-gate */ 1677*7c478bd9Sstevel@tonic-gate if (async->async_wbufcid != 0) { 1678*7c478bd9Sstevel@tonic-gate unbufcall(async->async_wbufcid); 1679*7c478bd9Sstevel@tonic-gate async->async_wbufcid = 0; 1680*7c478bd9Sstevel@tonic-gate } 1681*7c478bd9Sstevel@tonic-gate 1682*7c478bd9Sstevel@tonic-gate /* Note that qprocsoff can't be done until after interrupts are off */ 1683*7c478bd9Sstevel@tonic-gate qprocsoff(q); 1684*7c478bd9Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL; 1685*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_readq = NULL; 1686*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_writeq = NULL; 1687*7c478bd9Sstevel@tonic-gate 1688*7c478bd9Sstevel@tonic-gate /* 1689*7c478bd9Sstevel@tonic-gate * Clear out device state, except persistant device property flags. 1690*7c478bd9Sstevel@tonic-gate */ 1691*7c478bd9Sstevel@tonic-gate async->async_flags &= (ASYNC_DTR_DELAY|ASY_RTS_DTR_OFF); 1692*7c478bd9Sstevel@tonic-gate cv_broadcast(&async->async_flags_cv); 1693*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1694*7c478bd9Sstevel@tonic-gate 1695*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_CLOSE, "asy%dclose: done\n", instance); 1696*7c478bd9Sstevel@tonic-gate return (0); 1697*7c478bd9Sstevel@tonic-gate } 1698*7c478bd9Sstevel@tonic-gate 1699*7c478bd9Sstevel@tonic-gate static boolean_t 1700*7c478bd9Sstevel@tonic-gate asy_isbusy(struct asycom *asy) 1701*7c478bd9Sstevel@tonic-gate { 1702*7c478bd9Sstevel@tonic-gate struct asyncline *async; 1703*7c478bd9Sstevel@tonic-gate 1704*7c478bd9Sstevel@tonic-gate DEBUGCONT0(ASY_DEBUG_EOT, "asy_isbusy\n"); 1705*7c478bd9Sstevel@tonic-gate async = asy->asy_priv; 1706*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl)); 1707*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl_hi)); 1708*7c478bd9Sstevel@tonic-gate return ((async->async_ocnt > 0) || 1709*7c478bd9Sstevel@tonic-gate ((ddi_io_get8(asy->asy_iohandle, 1710*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR) & (XSRE|XHRE)) == 0)); 1711*7c478bd9Sstevel@tonic-gate } 1712*7c478bd9Sstevel@tonic-gate 1713*7c478bd9Sstevel@tonic-gate static void 1714*7c478bd9Sstevel@tonic-gate asy_waiteot(struct asycom *asy) 1715*7c478bd9Sstevel@tonic-gate { 1716*7c478bd9Sstevel@tonic-gate /* 1717*7c478bd9Sstevel@tonic-gate * Wait for the current transmission block and the 1718*7c478bd9Sstevel@tonic-gate * current fifo data to transmit. Once this is done 1719*7c478bd9Sstevel@tonic-gate * we may go on. 1720*7c478bd9Sstevel@tonic-gate */ 1721*7c478bd9Sstevel@tonic-gate DEBUGCONT0(ASY_DEBUG_EOT, "asy_waiteot\n"); 1722*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl)); 1723*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl_hi)); 1724*7c478bd9Sstevel@tonic-gate while (asy_isbusy(asy)) { 1725*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 1726*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 1727*7c478bd9Sstevel@tonic-gate drv_usecwait(10000); /* wait .01 */ 1728*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 1729*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 1730*7c478bd9Sstevel@tonic-gate } 1731*7c478bd9Sstevel@tonic-gate } 1732*7c478bd9Sstevel@tonic-gate 1733*7c478bd9Sstevel@tonic-gate /* asy_reset_fifo -- flush fifos and [re]program fifo control register */ 1734*7c478bd9Sstevel@tonic-gate static void 1735*7c478bd9Sstevel@tonic-gate asy_reset_fifo(struct asycom *asy, uchar_t flush) 1736*7c478bd9Sstevel@tonic-gate { 1737*7c478bd9Sstevel@tonic-gate uchar_t lcr; 1738*7c478bd9Sstevel@tonic-gate 1739*7c478bd9Sstevel@tonic-gate /* On a 16750, we have to set DLAB in order to set FIFOEXTRA. */ 1740*7c478bd9Sstevel@tonic-gate 1741*7c478bd9Sstevel@tonic-gate if (asy->asy_hwtype >= ASY16750) { 1742*7c478bd9Sstevel@tonic-gate lcr = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + LCR); 1743*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 1744*7c478bd9Sstevel@tonic-gate lcr | DLAB); 1745*7c478bd9Sstevel@tonic-gate } 1746*7c478bd9Sstevel@tonic-gate 1747*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + FIFOR, 1748*7c478bd9Sstevel@tonic-gate asy->asy_fifor | flush); 1749*7c478bd9Sstevel@tonic-gate 1750*7c478bd9Sstevel@tonic-gate /* Clear DLAB */ 1751*7c478bd9Sstevel@tonic-gate 1752*7c478bd9Sstevel@tonic-gate if (asy->asy_hwtype >= ASY16750) { 1753*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, lcr); 1754*7c478bd9Sstevel@tonic-gate } 1755*7c478bd9Sstevel@tonic-gate } 1756*7c478bd9Sstevel@tonic-gate 1757*7c478bd9Sstevel@tonic-gate /* 1758*7c478bd9Sstevel@tonic-gate * Program the ASY port. Most of the async operation is based on the values 1759*7c478bd9Sstevel@tonic-gate * of 'c_iflag' and 'c_cflag'. 1760*7c478bd9Sstevel@tonic-gate */ 1761*7c478bd9Sstevel@tonic-gate 1762*7c478bd9Sstevel@tonic-gate #define BAUDINDEX(cflg) (((cflg) & CBAUDEXT) ? \ 1763*7c478bd9Sstevel@tonic-gate (((cflg) & CBAUD) + CBAUD + 1) : ((cflg) & CBAUD)) 1764*7c478bd9Sstevel@tonic-gate 1765*7c478bd9Sstevel@tonic-gate static void 1766*7c478bd9Sstevel@tonic-gate asy_program(struct asycom *asy, int mode) 1767*7c478bd9Sstevel@tonic-gate { 1768*7c478bd9Sstevel@tonic-gate struct asyncline *async; 1769*7c478bd9Sstevel@tonic-gate int baudrate, c_flag; 1770*7c478bd9Sstevel@tonic-gate int icr, lcr; 1771*7c478bd9Sstevel@tonic-gate int flush_reg; 1772*7c478bd9Sstevel@tonic-gate int ocflags; 1773*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1774*7c478bd9Sstevel@tonic-gate int instance; 1775*7c478bd9Sstevel@tonic-gate #endif 1776*7c478bd9Sstevel@tonic-gate 1777*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl)); 1778*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl_hi)); 1779*7c478bd9Sstevel@tonic-gate 1780*7c478bd9Sstevel@tonic-gate async = asy->asy_priv; 1781*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1782*7c478bd9Sstevel@tonic-gate instance = UNIT(async->async_dev); 1783*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_PROCS, 1784*7c478bd9Sstevel@tonic-gate "asy%d_program: mode = 0x%08X, enter\n", instance, mode); 1785*7c478bd9Sstevel@tonic-gate #endif 1786*7c478bd9Sstevel@tonic-gate 1787*7c478bd9Sstevel@tonic-gate baudrate = BAUDINDEX(async->async_ttycommon.t_cflag); 1788*7c478bd9Sstevel@tonic-gate 1789*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag &= ~(CIBAUD); 1790*7c478bd9Sstevel@tonic-gate 1791*7c478bd9Sstevel@tonic-gate if (baudrate > CBAUD) { 1792*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag |= CIBAUDEXT; 1793*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag |= 1794*7c478bd9Sstevel@tonic-gate (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD); 1795*7c478bd9Sstevel@tonic-gate } else { 1796*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag &= ~CIBAUDEXT; 1797*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag |= 1798*7c478bd9Sstevel@tonic-gate ((baudrate << IBSHIFT) & CIBAUD); 1799*7c478bd9Sstevel@tonic-gate } 1800*7c478bd9Sstevel@tonic-gate 1801*7c478bd9Sstevel@tonic-gate c_flag = async->async_ttycommon.t_cflag & 1802*7c478bd9Sstevel@tonic-gate (CLOCAL|CREAD|CSTOPB|CSIZE|PARENB|PARODD|CBAUD|CBAUDEXT); 1803*7c478bd9Sstevel@tonic-gate 1804*7c478bd9Sstevel@tonic-gate /* disable interrupts */ 1805*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, 0); 1806*7c478bd9Sstevel@tonic-gate 1807*7c478bd9Sstevel@tonic-gate ocflags = asy->asy_ocflag; 1808*7c478bd9Sstevel@tonic-gate 1809*7c478bd9Sstevel@tonic-gate /* flush/reset the status registers */ 1810*7c478bd9Sstevel@tonic-gate (void) ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + ISR); 1811*7c478bd9Sstevel@tonic-gate (void) ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + LSR); 1812*7c478bd9Sstevel@tonic-gate asy->asy_msr = flush_reg = ddi_io_get8(asy->asy_iohandle, 1813*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + MSR); 1814*7c478bd9Sstevel@tonic-gate /* 1815*7c478bd9Sstevel@tonic-gate * The device is programmed in the open sequence, if we 1816*7c478bd9Sstevel@tonic-gate * have to hardware handshake, then this is a good time 1817*7c478bd9Sstevel@tonic-gate * to check if the device can receive any data. 1818*7c478bd9Sstevel@tonic-gate */ 1819*7c478bd9Sstevel@tonic-gate 1820*7c478bd9Sstevel@tonic-gate if ((CRTSCTS & async->async_ttycommon.t_cflag) && !(flush_reg & CTS)) { 1821*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_output(asy, FLOW_STOP); 1822*7c478bd9Sstevel@tonic-gate } else { 1823*7c478bd9Sstevel@tonic-gate /* 1824*7c478bd9Sstevel@tonic-gate * We can not use async_flowcontrol_hw_output(asy, FLOW_START) 1825*7c478bd9Sstevel@tonic-gate * here, because if CRTSCTS is clear, we need clear 1826*7c478bd9Sstevel@tonic-gate * ASYNC_HW_OUT_FLW bit. 1827*7c478bd9Sstevel@tonic-gate */ 1828*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_HW_OUT_FLW; 1829*7c478bd9Sstevel@tonic-gate } 1830*7c478bd9Sstevel@tonic-gate 1831*7c478bd9Sstevel@tonic-gate /* 1832*7c478bd9Sstevel@tonic-gate * If IXON is not set, clear ASYNC_SW_OUT_FLW; 1833*7c478bd9Sstevel@tonic-gate * If IXON is set, no matter what IXON flag is before this 1834*7c478bd9Sstevel@tonic-gate * function call to asy_program, 1835*7c478bd9Sstevel@tonic-gate * we will use the old ASYNC_SW_OUT_FLW status. 1836*7c478bd9Sstevel@tonic-gate * Because of handling IXON in the driver, we also should re-calculate 1837*7c478bd9Sstevel@tonic-gate * the value of ASYNC_OUT_FLW_RESUME bit, but in fact, 1838*7c478bd9Sstevel@tonic-gate * the TCSET* commands which call asy_program 1839*7c478bd9Sstevel@tonic-gate * are put into the write queue, so there is no output needed to 1840*7c478bd9Sstevel@tonic-gate * be resumed at this point. 1841*7c478bd9Sstevel@tonic-gate */ 1842*7c478bd9Sstevel@tonic-gate if (!(IXON & async->async_ttycommon.t_iflag)) 1843*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_SW_OUT_FLW; 1844*7c478bd9Sstevel@tonic-gate 1845*7c478bd9Sstevel@tonic-gate /* manually flush receive buffer or fifo (workaround for buggy fifos) */ 1846*7c478bd9Sstevel@tonic-gate if (mode == ASY_INIT) 1847*7c478bd9Sstevel@tonic-gate if (asy->asy_use_fifo == FIFO_ON) { 1848*7c478bd9Sstevel@tonic-gate for (flush_reg = asy->asy_fifo_buf; flush_reg-- > 0; ) { 1849*7c478bd9Sstevel@tonic-gate (void) ddi_io_get8(asy->asy_iohandle, 1850*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT); 1851*7c478bd9Sstevel@tonic-gate } 1852*7c478bd9Sstevel@tonic-gate } else { 1853*7c478bd9Sstevel@tonic-gate flush_reg = ddi_io_get8(asy->asy_iohandle, 1854*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT); 1855*7c478bd9Sstevel@tonic-gate } 1856*7c478bd9Sstevel@tonic-gate 1857*7c478bd9Sstevel@tonic-gate if (ocflags != (c_flag & ~CLOCAL) || mode == ASY_INIT) { 1858*7c478bd9Sstevel@tonic-gate /* Set line control */ 1859*7c478bd9Sstevel@tonic-gate lcr = ddi_io_get8(asy->asy_iohandle, 1860*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR); 1861*7c478bd9Sstevel@tonic-gate lcr &= ~(WLS0|WLS1|STB|PEN|EPS); 1862*7c478bd9Sstevel@tonic-gate 1863*7c478bd9Sstevel@tonic-gate if (c_flag & CSTOPB) 1864*7c478bd9Sstevel@tonic-gate lcr |= STB; /* 2 stop bits */ 1865*7c478bd9Sstevel@tonic-gate 1866*7c478bd9Sstevel@tonic-gate if (c_flag & PARENB) 1867*7c478bd9Sstevel@tonic-gate lcr |= PEN; 1868*7c478bd9Sstevel@tonic-gate 1869*7c478bd9Sstevel@tonic-gate if ((c_flag & PARODD) == 0) 1870*7c478bd9Sstevel@tonic-gate lcr |= EPS; 1871*7c478bd9Sstevel@tonic-gate 1872*7c478bd9Sstevel@tonic-gate switch (c_flag & CSIZE) { 1873*7c478bd9Sstevel@tonic-gate case CS5: 1874*7c478bd9Sstevel@tonic-gate lcr |= BITS5; 1875*7c478bd9Sstevel@tonic-gate break; 1876*7c478bd9Sstevel@tonic-gate case CS6: 1877*7c478bd9Sstevel@tonic-gate lcr |= BITS6; 1878*7c478bd9Sstevel@tonic-gate break; 1879*7c478bd9Sstevel@tonic-gate case CS7: 1880*7c478bd9Sstevel@tonic-gate lcr |= BITS7; 1881*7c478bd9Sstevel@tonic-gate break; 1882*7c478bd9Sstevel@tonic-gate case CS8: 1883*7c478bd9Sstevel@tonic-gate lcr |= BITS8; 1884*7c478bd9Sstevel@tonic-gate break; 1885*7c478bd9Sstevel@tonic-gate } 1886*7c478bd9Sstevel@tonic-gate 1887*7c478bd9Sstevel@tonic-gate /* set the baud rate, unless it is "0" */ 1888*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 1889*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR, DLAB); 1890*7c478bd9Sstevel@tonic-gate if (baudrate != 0) { 1891*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + DAT, 1892*7c478bd9Sstevel@tonic-gate asyspdtab[baudrate] & 0xff); 1893*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, 1894*7c478bd9Sstevel@tonic-gate (asyspdtab[baudrate] >> 8) & 0xff); 1895*7c478bd9Sstevel@tonic-gate } 1896*7c478bd9Sstevel@tonic-gate /* set the line control modes */ 1897*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, lcr); 1898*7c478bd9Sstevel@tonic-gate 1899*7c478bd9Sstevel@tonic-gate /* 1900*7c478bd9Sstevel@tonic-gate * If we have a FIFO buffer, enable/flush 1901*7c478bd9Sstevel@tonic-gate * at intialize time, flush if transitioning from 1902*7c478bd9Sstevel@tonic-gate * CREAD off to CREAD on. 1903*7c478bd9Sstevel@tonic-gate */ 1904*7c478bd9Sstevel@tonic-gate if ((ocflags & CREAD) == 0 && (c_flag & CREAD) || 1905*7c478bd9Sstevel@tonic-gate mode == ASY_INIT) 1906*7c478bd9Sstevel@tonic-gate if (asy->asy_use_fifo == FIFO_ON) 1907*7c478bd9Sstevel@tonic-gate asy_reset_fifo(asy, FIFORXFLSH); 1908*7c478bd9Sstevel@tonic-gate 1909*7c478bd9Sstevel@tonic-gate /* remember the new cflags */ 1910*7c478bd9Sstevel@tonic-gate asy->asy_ocflag = c_flag & ~CLOCAL; 1911*7c478bd9Sstevel@tonic-gate } 1912*7c478bd9Sstevel@tonic-gate 1913*7c478bd9Sstevel@tonic-gate if (baudrate == 0) 1914*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, 1915*7c478bd9Sstevel@tonic-gate (asy->asy_mcr & RTS) | OUT2); 1916*7c478bd9Sstevel@tonic-gate else 1917*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, 1918*7c478bd9Sstevel@tonic-gate asy->asy_mcr | OUT2); 1919*7c478bd9Sstevel@tonic-gate 1920*7c478bd9Sstevel@tonic-gate /* 1921*7c478bd9Sstevel@tonic-gate * Call the modem status interrupt handler to check for the carrier 1922*7c478bd9Sstevel@tonic-gate * in case CLOCAL was turned off after the carrier came on. 1923*7c478bd9Sstevel@tonic-gate * (Note: Modem status interrupt is not enabled if CLOCAL is ON.) 1924*7c478bd9Sstevel@tonic-gate */ 1925*7c478bd9Sstevel@tonic-gate async_msint(asy); 1926*7c478bd9Sstevel@tonic-gate 1927*7c478bd9Sstevel@tonic-gate /* Set interrupt control */ 1928*7c478bd9Sstevel@tonic-gate DEBUGCONT3(ASY_DEBUG_MODM2, 1929*7c478bd9Sstevel@tonic-gate "asy%d_program: c_flag & CLOCAL = %x t_cflag & CRTSCTS = %x\n", 1930*7c478bd9Sstevel@tonic-gate instance, 1931*7c478bd9Sstevel@tonic-gate c_flag & CLOCAL, 1932*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag & CRTSCTS); 1933*7c478bd9Sstevel@tonic-gate if ((c_flag & CLOCAL) && !(async->async_ttycommon.t_cflag & CRTSCTS)) 1934*7c478bd9Sstevel@tonic-gate /* 1935*7c478bd9Sstevel@tonic-gate * direct-wired line ignores DCD, so we don't enable modem 1936*7c478bd9Sstevel@tonic-gate * status interrupts. 1937*7c478bd9Sstevel@tonic-gate */ 1938*7c478bd9Sstevel@tonic-gate icr = (TIEN | SIEN); 1939*7c478bd9Sstevel@tonic-gate else 1940*7c478bd9Sstevel@tonic-gate icr = (TIEN | SIEN | MIEN); 1941*7c478bd9Sstevel@tonic-gate 1942*7c478bd9Sstevel@tonic-gate if (c_flag & CREAD) 1943*7c478bd9Sstevel@tonic-gate icr |= RIEN; 1944*7c478bd9Sstevel@tonic-gate 1945*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, icr); 1946*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_PROCS, "asy%d_program: done\n", instance); 1947*7c478bd9Sstevel@tonic-gate } 1948*7c478bd9Sstevel@tonic-gate 1949*7c478bd9Sstevel@tonic-gate static boolean_t 1950*7c478bd9Sstevel@tonic-gate asy_baudok(struct asycom *asy) 1951*7c478bd9Sstevel@tonic-gate { 1952*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 1953*7c478bd9Sstevel@tonic-gate int baudrate; 1954*7c478bd9Sstevel@tonic-gate 1955*7c478bd9Sstevel@tonic-gate 1956*7c478bd9Sstevel@tonic-gate baudrate = BAUDINDEX(async->async_ttycommon.t_cflag); 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate if (baudrate >= sizeof (asyspdtab)/sizeof (*asyspdtab)) 1959*7c478bd9Sstevel@tonic-gate return (0); 1960*7c478bd9Sstevel@tonic-gate 1961*7c478bd9Sstevel@tonic-gate return (baudrate == 0 || asyspdtab[baudrate]); 1962*7c478bd9Sstevel@tonic-gate } 1963*7c478bd9Sstevel@tonic-gate 1964*7c478bd9Sstevel@tonic-gate /* 1965*7c478bd9Sstevel@tonic-gate * asyintr() is the High Level Interrupt Handler. 1966*7c478bd9Sstevel@tonic-gate * 1967*7c478bd9Sstevel@tonic-gate * There are four different interrupt types indexed by ISR register values: 1968*7c478bd9Sstevel@tonic-gate * 0: modem 1969*7c478bd9Sstevel@tonic-gate * 1: Tx holding register is empty, ready for next char 1970*7c478bd9Sstevel@tonic-gate * 2: Rx register now holds a char to be picked up 1971*7c478bd9Sstevel@tonic-gate * 3: error or break on line 1972*7c478bd9Sstevel@tonic-gate * This routine checks the Bit 0 (interrupt-not-pending) to determine if 1973*7c478bd9Sstevel@tonic-gate * the interrupt is from this port. 1974*7c478bd9Sstevel@tonic-gate */ 1975*7c478bd9Sstevel@tonic-gate uint_t 1976*7c478bd9Sstevel@tonic-gate asyintr(caddr_t argasy) 1977*7c478bd9Sstevel@tonic-gate { 1978*7c478bd9Sstevel@tonic-gate struct asycom *asy = (struct asycom *)argasy; 1979*7c478bd9Sstevel@tonic-gate struct asyncline *async; 1980*7c478bd9Sstevel@tonic-gate int ret_status = DDI_INTR_UNCLAIMED; 1981*7c478bd9Sstevel@tonic-gate uchar_t interrupt_id, lsr; 1982*7c478bd9Sstevel@tonic-gate 1983*7c478bd9Sstevel@tonic-gate interrupt_id = ddi_io_get8(asy->asy_iohandle, 1984*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + ISR) & 0x0F; 1985*7c478bd9Sstevel@tonic-gate async = asy->asy_priv; 1986*7c478bd9Sstevel@tonic-gate if ((async == NULL) || asy_addedsoft == 0 || 1987*7c478bd9Sstevel@tonic-gate !(async->async_flags & (ASYNC_ISOPEN|ASYNC_WOPEN))) { 1988*7c478bd9Sstevel@tonic-gate if (interrupt_id & NOINTERRUPT) 1989*7c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 1990*7c478bd9Sstevel@tonic-gate else { 1991*7c478bd9Sstevel@tonic-gate /* 1992*7c478bd9Sstevel@tonic-gate * reset the device by: 1993*7c478bd9Sstevel@tonic-gate * reading line status 1994*7c478bd9Sstevel@tonic-gate * reading any data from data status register 1995*7c478bd9Sstevel@tonic-gate * reading modem status 1996*7c478bd9Sstevel@tonic-gate */ 1997*7c478bd9Sstevel@tonic-gate (void) ddi_io_get8(asy->asy_iohandle, 1998*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR); 1999*7c478bd9Sstevel@tonic-gate (void) ddi_io_get8(asy->asy_iohandle, 2000*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT); 2001*7c478bd9Sstevel@tonic-gate asy->asy_msr = ddi_io_get8(asy->asy_iohandle, 2002*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + MSR); 2003*7c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 2004*7c478bd9Sstevel@tonic-gate } 2005*7c478bd9Sstevel@tonic-gate } 2006*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2007*7c478bd9Sstevel@tonic-gate /* 2008*7c478bd9Sstevel@tonic-gate * We will loop until the interrupt line is pulled low. asy 2009*7c478bd9Sstevel@tonic-gate * interrupt is edge triggered. 2010*7c478bd9Sstevel@tonic-gate */ 2011*7c478bd9Sstevel@tonic-gate /* CSTYLED */ 2012*7c478bd9Sstevel@tonic-gate for (;; interrupt_id = (ddi_io_get8(asy->asy_iohandle, 2013*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + ISR) & 0x0F)) { 2014*7c478bd9Sstevel@tonic-gate if (interrupt_id & NOINTERRUPT) 2015*7c478bd9Sstevel@tonic-gate break; 2016*7c478bd9Sstevel@tonic-gate ret_status = DDI_INTR_CLAIMED; 2017*7c478bd9Sstevel@tonic-gate 2018*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_INTR, 2019*7c478bd9Sstevel@tonic-gate "asyintr: interrupt_id = 0x%d\n", interrupt_id); 2020*7c478bd9Sstevel@tonic-gate lsr = ddi_io_get8(asy->asy_iohandle, 2021*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR); 2022*7c478bd9Sstevel@tonic-gate switch (interrupt_id) { 2023*7c478bd9Sstevel@tonic-gate case RxRDY: 2024*7c478bd9Sstevel@tonic-gate case RSTATUS: 2025*7c478bd9Sstevel@tonic-gate case FFTMOUT: 2026*7c478bd9Sstevel@tonic-gate /* receiver interrupt or receiver errors */ 2027*7c478bd9Sstevel@tonic-gate async_rxint(asy, lsr); 2028*7c478bd9Sstevel@tonic-gate break; 2029*7c478bd9Sstevel@tonic-gate case TxRDY: 2030*7c478bd9Sstevel@tonic-gate /* transmit interrupt */ 2031*7c478bd9Sstevel@tonic-gate async_txint(asy); 2032*7c478bd9Sstevel@tonic-gate continue; 2033*7c478bd9Sstevel@tonic-gate case MSTATUS: 2034*7c478bd9Sstevel@tonic-gate /* modem status interrupt */ 2035*7c478bd9Sstevel@tonic-gate async_msint(asy); 2036*7c478bd9Sstevel@tonic-gate break; 2037*7c478bd9Sstevel@tonic-gate } 2038*7c478bd9Sstevel@tonic-gate if ((lsr & XHRE) && (async->async_flags & ASYNC_BUSY) && 2039*7c478bd9Sstevel@tonic-gate (async->async_ocnt > 0)) 2040*7c478bd9Sstevel@tonic-gate async_txint(asy); 2041*7c478bd9Sstevel@tonic-gate } 2042*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2043*7c478bd9Sstevel@tonic-gate return (ret_status); 2044*7c478bd9Sstevel@tonic-gate } 2045*7c478bd9Sstevel@tonic-gate 2046*7c478bd9Sstevel@tonic-gate /* 2047*7c478bd9Sstevel@tonic-gate * Transmitter interrupt service routine. 2048*7c478bd9Sstevel@tonic-gate * If there is more data to transmit in the current pseudo-DMA block, 2049*7c478bd9Sstevel@tonic-gate * send the next character if output is not stopped or draining. 2050*7c478bd9Sstevel@tonic-gate * Otherwise, queue up a soft interrupt. 2051*7c478bd9Sstevel@tonic-gate * 2052*7c478bd9Sstevel@tonic-gate * XXX - Needs review for HW FIFOs. 2053*7c478bd9Sstevel@tonic-gate */ 2054*7c478bd9Sstevel@tonic-gate static void 2055*7c478bd9Sstevel@tonic-gate async_txint(struct asycom *asy) 2056*7c478bd9Sstevel@tonic-gate { 2057*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 2058*7c478bd9Sstevel@tonic-gate int fifo_len; 2059*7c478bd9Sstevel@tonic-gate 2060*7c478bd9Sstevel@tonic-gate /* 2061*7c478bd9Sstevel@tonic-gate * If ASYNC_BREAK or ASYNC_OUT_SUSPEND has been set, return to 2062*7c478bd9Sstevel@tonic-gate * asyintr()'s context to claim the interrupt without performing 2063*7c478bd9Sstevel@tonic-gate * any action. No character will be loaded into FIFO/THR until 2064*7c478bd9Sstevel@tonic-gate * timed or untimed break is removed 2065*7c478bd9Sstevel@tonic-gate */ 2066*7c478bd9Sstevel@tonic-gate if (async->async_flags & (ASYNC_BREAK|ASYNC_OUT_SUSPEND)) 2067*7c478bd9Sstevel@tonic-gate return; 2068*7c478bd9Sstevel@tonic-gate 2069*7c478bd9Sstevel@tonic-gate fifo_len = asy->asy_fifo_buf; /* with FIFO buffers */ 2070*7c478bd9Sstevel@tonic-gate if (fifo_len > asy_max_tx_fifo) 2071*7c478bd9Sstevel@tonic-gate fifo_len = asy_max_tx_fifo; 2072*7c478bd9Sstevel@tonic-gate 2073*7c478bd9Sstevel@tonic-gate if (async_flowcontrol_sw_input(asy, FLOW_CHECK, IN_FLOW_NULL)) 2074*7c478bd9Sstevel@tonic-gate fifo_len--; 2075*7c478bd9Sstevel@tonic-gate 2076*7c478bd9Sstevel@tonic-gate if (async->async_ocnt > 0 && fifo_len > 0 && 2077*7c478bd9Sstevel@tonic-gate !(async->async_flags & 2078*7c478bd9Sstevel@tonic-gate (ASYNC_HW_OUT_FLW|ASYNC_SW_OUT_FLW|ASYNC_STOPPED))) { 2079*7c478bd9Sstevel@tonic-gate while (fifo_len-- > 0 && async->async_ocnt-- > 0) { 2080*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 2081*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT, *async->async_optr++); 2082*7c478bd9Sstevel@tonic-gate } 2083*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_PROGRESS; 2084*7c478bd9Sstevel@tonic-gate } 2085*7c478bd9Sstevel@tonic-gate 2086*7c478bd9Sstevel@tonic-gate if (fifo_len <= 0) 2087*7c478bd9Sstevel@tonic-gate return; 2088*7c478bd9Sstevel@tonic-gate 2089*7c478bd9Sstevel@tonic-gate ASYSETSOFT(asy); 2090*7c478bd9Sstevel@tonic-gate } 2091*7c478bd9Sstevel@tonic-gate 2092*7c478bd9Sstevel@tonic-gate /* 2093*7c478bd9Sstevel@tonic-gate * Interrupt on port: handle PPS event. This function is only called 2094*7c478bd9Sstevel@tonic-gate * for a port on which PPS event handling has been enabled. 2095*7c478bd9Sstevel@tonic-gate */ 2096*7c478bd9Sstevel@tonic-gate static void 2097*7c478bd9Sstevel@tonic-gate asy_ppsevent(struct asycom *asy, int msr) 2098*7c478bd9Sstevel@tonic-gate { 2099*7c478bd9Sstevel@tonic-gate if (asy->asy_flags & ASY_PPS_EDGE) { 2100*7c478bd9Sstevel@tonic-gate /* Have seen leading edge, now look for and record drop */ 2101*7c478bd9Sstevel@tonic-gate if ((msr & DCD) == 0) 2102*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~ASY_PPS_EDGE; 2103*7c478bd9Sstevel@tonic-gate /* 2104*7c478bd9Sstevel@tonic-gate * Waiting for leading edge, look for rise; stamp event and 2105*7c478bd9Sstevel@tonic-gate * calibrate kernel clock. 2106*7c478bd9Sstevel@tonic-gate */ 2107*7c478bd9Sstevel@tonic-gate } else if (msr & DCD) { 2108*7c478bd9Sstevel@tonic-gate /* 2109*7c478bd9Sstevel@tonic-gate * This code captures a timestamp at the designated 2110*7c478bd9Sstevel@tonic-gate * transition of the PPS signal (DCD asserted). The 2111*7c478bd9Sstevel@tonic-gate * code provides a pointer to the timestamp, as well 2112*7c478bd9Sstevel@tonic-gate * as the hardware counter value at the capture. 2113*7c478bd9Sstevel@tonic-gate * 2114*7c478bd9Sstevel@tonic-gate * Note: the kernel has nano based time values while 2115*7c478bd9Sstevel@tonic-gate * NTP requires micro based, an in-line fast algorithm 2116*7c478bd9Sstevel@tonic-gate * to convert nsec to usec is used here -- see hrt2ts() 2117*7c478bd9Sstevel@tonic-gate * in common/os/timers.c for a full description. 2118*7c478bd9Sstevel@tonic-gate */ 2119*7c478bd9Sstevel@tonic-gate struct timeval *tvp = &asy_ppsev.tv; 2120*7c478bd9Sstevel@tonic-gate timestruc_t ts; 2121*7c478bd9Sstevel@tonic-gate long nsec, usec; 2122*7c478bd9Sstevel@tonic-gate 2123*7c478bd9Sstevel@tonic-gate asy->asy_flags |= ASY_PPS_EDGE; 2124*7c478bd9Sstevel@tonic-gate LED_OFF; 2125*7c478bd9Sstevel@tonic-gate gethrestime(&ts); 2126*7c478bd9Sstevel@tonic-gate LED_ON; 2127*7c478bd9Sstevel@tonic-gate nsec = ts.tv_nsec; 2128*7c478bd9Sstevel@tonic-gate usec = nsec + (nsec >> 2); 2129*7c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 1); 2130*7c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 2); 2131*7c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 4); 2132*7c478bd9Sstevel@tonic-gate usec = nsec - (usec >> 3); 2133*7c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 2); 2134*7c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 3); 2135*7c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 4); 2136*7c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 1); 2137*7c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 6); 2138*7c478bd9Sstevel@tonic-gate tvp->tv_usec = usec >> 10; 2139*7c478bd9Sstevel@tonic-gate tvp->tv_sec = ts.tv_sec; 2140*7c478bd9Sstevel@tonic-gate 2141*7c478bd9Sstevel@tonic-gate ++asy_ppsev.serial; 2142*7c478bd9Sstevel@tonic-gate 2143*7c478bd9Sstevel@tonic-gate /* 2144*7c478bd9Sstevel@tonic-gate * Because the kernel keeps a high-resolution time, 2145*7c478bd9Sstevel@tonic-gate * pass the current highres timestamp in tvp and zero 2146*7c478bd9Sstevel@tonic-gate * in usec. 2147*7c478bd9Sstevel@tonic-gate */ 2148*7c478bd9Sstevel@tonic-gate ddi_hardpps(tvp, 0); 2149*7c478bd9Sstevel@tonic-gate } 2150*7c478bd9Sstevel@tonic-gate } 2151*7c478bd9Sstevel@tonic-gate 2152*7c478bd9Sstevel@tonic-gate /* 2153*7c478bd9Sstevel@tonic-gate * Receiver interrupt: RxRDY interrupt, FIFO timeout interrupt or receive 2154*7c478bd9Sstevel@tonic-gate * error interrupt. 2155*7c478bd9Sstevel@tonic-gate * Try to put the character into the circular buffer for this line; if it 2156*7c478bd9Sstevel@tonic-gate * overflows, indicate a circular buffer overrun. If this port is always 2157*7c478bd9Sstevel@tonic-gate * to be serviced immediately, or the character is a STOP character, or 2158*7c478bd9Sstevel@tonic-gate * more than 15 characters have arrived, queue up a soft interrupt to 2159*7c478bd9Sstevel@tonic-gate * drain the circular buffer. 2160*7c478bd9Sstevel@tonic-gate * XXX - needs review for hw FIFOs support. 2161*7c478bd9Sstevel@tonic-gate */ 2162*7c478bd9Sstevel@tonic-gate 2163*7c478bd9Sstevel@tonic-gate static void 2164*7c478bd9Sstevel@tonic-gate async_rxint(struct asycom *asy, uchar_t lsr) 2165*7c478bd9Sstevel@tonic-gate { 2166*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 2167*7c478bd9Sstevel@tonic-gate uchar_t c; 2168*7c478bd9Sstevel@tonic-gate uint_t s, needsoft = 0; 2169*7c478bd9Sstevel@tonic-gate tty_common_t *tp; 2170*7c478bd9Sstevel@tonic-gate int looplim = asy->asy_fifo_buf * 2; 2171*7c478bd9Sstevel@tonic-gate 2172*7c478bd9Sstevel@tonic-gate tp = &async->async_ttycommon; 2173*7c478bd9Sstevel@tonic-gate if (!(tp->t_cflag & CREAD)) { 2174*7c478bd9Sstevel@tonic-gate while (lsr & (RCA|PARERR|FRMERR|BRKDET|OVRRUN)) { 2175*7c478bd9Sstevel@tonic-gate (void) (ddi_io_get8(asy->asy_iohandle, 2176*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT) & 0xff); 2177*7c478bd9Sstevel@tonic-gate lsr = ddi_io_get8(asy->asy_iohandle, 2178*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR); 2179*7c478bd9Sstevel@tonic-gate if (looplim-- < 0) /* limit loop */ 2180*7c478bd9Sstevel@tonic-gate break; 2181*7c478bd9Sstevel@tonic-gate } 2182*7c478bd9Sstevel@tonic-gate return; /* line is not open for read? */ 2183*7c478bd9Sstevel@tonic-gate } 2184*7c478bd9Sstevel@tonic-gate 2185*7c478bd9Sstevel@tonic-gate while (lsr & (RCA|PARERR|FRMERR|BRKDET|OVRRUN)) { 2186*7c478bd9Sstevel@tonic-gate c = 0; 2187*7c478bd9Sstevel@tonic-gate s = 0; /* reset error status */ 2188*7c478bd9Sstevel@tonic-gate if (lsr & RCA) { 2189*7c478bd9Sstevel@tonic-gate c = ddi_io_get8(asy->asy_iohandle, 2190*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT) & 0xff; 2191*7c478bd9Sstevel@tonic-gate 2192*7c478bd9Sstevel@tonic-gate /* 2193*7c478bd9Sstevel@tonic-gate * We handle XON/XOFF char if IXON is set, 2194*7c478bd9Sstevel@tonic-gate * but if received char is _POSIX_VDISABLE, 2195*7c478bd9Sstevel@tonic-gate * we left it to the up level module. 2196*7c478bd9Sstevel@tonic-gate */ 2197*7c478bd9Sstevel@tonic-gate if (tp->t_iflag & IXON) { 2198*7c478bd9Sstevel@tonic-gate if ((c == async->async_stopc) && 2199*7c478bd9Sstevel@tonic-gate (c != _POSIX_VDISABLE)) { 2200*7c478bd9Sstevel@tonic-gate async_flowcontrol_sw_output(asy, 2201*7c478bd9Sstevel@tonic-gate FLOW_STOP); 2202*7c478bd9Sstevel@tonic-gate goto check_looplim; 2203*7c478bd9Sstevel@tonic-gate } else if ((c == async->async_startc) && 2204*7c478bd9Sstevel@tonic-gate (c != _POSIX_VDISABLE)) { 2205*7c478bd9Sstevel@tonic-gate async_flowcontrol_sw_output(asy, 2206*7c478bd9Sstevel@tonic-gate FLOW_START); 2207*7c478bd9Sstevel@tonic-gate needsoft = 1; 2208*7c478bd9Sstevel@tonic-gate goto check_looplim; 2209*7c478bd9Sstevel@tonic-gate } 2210*7c478bd9Sstevel@tonic-gate if ((tp->t_iflag & IXANY) && 2211*7c478bd9Sstevel@tonic-gate (async->async_flags & ASYNC_SW_OUT_FLW)) { 2212*7c478bd9Sstevel@tonic-gate async_flowcontrol_sw_output(asy, 2213*7c478bd9Sstevel@tonic-gate FLOW_START); 2214*7c478bd9Sstevel@tonic-gate needsoft = 1; 2215*7c478bd9Sstevel@tonic-gate } 2216*7c478bd9Sstevel@tonic-gate } 2217*7c478bd9Sstevel@tonic-gate } 2218*7c478bd9Sstevel@tonic-gate 2219*7c478bd9Sstevel@tonic-gate /* 2220*7c478bd9Sstevel@tonic-gate * Check for character break sequence 2221*7c478bd9Sstevel@tonic-gate */ 2222*7c478bd9Sstevel@tonic-gate if ((abort_enable == KIOCABORTALTERNATE) && 2223*7c478bd9Sstevel@tonic-gate (asy->asy_flags & ASY_CONSOLE)) { 2224*7c478bd9Sstevel@tonic-gate if (abort_charseq_recognize(c)) 2225*7c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 2226*7c478bd9Sstevel@tonic-gate } 2227*7c478bd9Sstevel@tonic-gate 2228*7c478bd9Sstevel@tonic-gate /* Handle framing errors */ 2229*7c478bd9Sstevel@tonic-gate if (lsr & (PARERR|FRMERR|BRKDET|OVRRUN)) { 2230*7c478bd9Sstevel@tonic-gate if (lsr & PARERR) { 2231*7c478bd9Sstevel@tonic-gate if (tp->t_iflag & INPCK) /* parity enabled */ 2232*7c478bd9Sstevel@tonic-gate s |= PERROR; 2233*7c478bd9Sstevel@tonic-gate } 2234*7c478bd9Sstevel@tonic-gate 2235*7c478bd9Sstevel@tonic-gate if (lsr & (FRMERR|BRKDET)) 2236*7c478bd9Sstevel@tonic-gate s |= FRERROR; 2237*7c478bd9Sstevel@tonic-gate if (lsr & OVRRUN) { 2238*7c478bd9Sstevel@tonic-gate async->async_hw_overrun = 1; 2239*7c478bd9Sstevel@tonic-gate s |= OVERRUN; 2240*7c478bd9Sstevel@tonic-gate } 2241*7c478bd9Sstevel@tonic-gate } 2242*7c478bd9Sstevel@tonic-gate 2243*7c478bd9Sstevel@tonic-gate if (s == 0) 2244*7c478bd9Sstevel@tonic-gate if ((tp->t_iflag & PARMRK) && 2245*7c478bd9Sstevel@tonic-gate !(tp->t_iflag & (IGNPAR|ISTRIP)) && 2246*7c478bd9Sstevel@tonic-gate (c == 0377)) 2247*7c478bd9Sstevel@tonic-gate if (RING_POK(async, 2)) { 2248*7c478bd9Sstevel@tonic-gate RING_PUT(async, 0377); 2249*7c478bd9Sstevel@tonic-gate RING_PUT(async, c); 2250*7c478bd9Sstevel@tonic-gate } else 2251*7c478bd9Sstevel@tonic-gate async->async_sw_overrun = 1; 2252*7c478bd9Sstevel@tonic-gate else 2253*7c478bd9Sstevel@tonic-gate if (RING_POK(async, 1)) 2254*7c478bd9Sstevel@tonic-gate RING_PUT(async, c); 2255*7c478bd9Sstevel@tonic-gate else 2256*7c478bd9Sstevel@tonic-gate async->async_sw_overrun = 1; 2257*7c478bd9Sstevel@tonic-gate else 2258*7c478bd9Sstevel@tonic-gate if (s & FRERROR) /* Handle framing errors */ 2259*7c478bd9Sstevel@tonic-gate if (c == 0) 2260*7c478bd9Sstevel@tonic-gate if ((asy->asy_flags & ASY_CONSOLE) && 2261*7c478bd9Sstevel@tonic-gate (abort_enable != 2262*7c478bd9Sstevel@tonic-gate KIOCABORTALTERNATE)) 2263*7c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)0); 2264*7c478bd9Sstevel@tonic-gate else 2265*7c478bd9Sstevel@tonic-gate async->async_break++; 2266*7c478bd9Sstevel@tonic-gate else 2267*7c478bd9Sstevel@tonic-gate if (RING_POK(async, 1)) 2268*7c478bd9Sstevel@tonic-gate RING_MARK(async, c, s); 2269*7c478bd9Sstevel@tonic-gate else 2270*7c478bd9Sstevel@tonic-gate async->async_sw_overrun = 1; 2271*7c478bd9Sstevel@tonic-gate else /* Parity errors are handled by ldterm */ 2272*7c478bd9Sstevel@tonic-gate if (RING_POK(async, 1)) 2273*7c478bd9Sstevel@tonic-gate RING_MARK(async, c, s); 2274*7c478bd9Sstevel@tonic-gate else 2275*7c478bd9Sstevel@tonic-gate async->async_sw_overrun = 1; 2276*7c478bd9Sstevel@tonic-gate check_looplim: 2277*7c478bd9Sstevel@tonic-gate lsr = ddi_io_get8(asy->asy_iohandle, 2278*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR); 2279*7c478bd9Sstevel@tonic-gate if (looplim-- < 0) /* limit loop */ 2280*7c478bd9Sstevel@tonic-gate break; 2281*7c478bd9Sstevel@tonic-gate } 2282*7c478bd9Sstevel@tonic-gate if ((RING_CNT(async) > (RINGSIZE * 3)/4) && 2283*7c478bd9Sstevel@tonic-gate !(async->async_inflow_source & IN_FLOW_RINGBUFF)) { 2284*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_input(asy, FLOW_STOP, IN_FLOW_RINGBUFF); 2285*7c478bd9Sstevel@tonic-gate (void) async_flowcontrol_sw_input(asy, FLOW_STOP, 2286*7c478bd9Sstevel@tonic-gate IN_FLOW_RINGBUFF); 2287*7c478bd9Sstevel@tonic-gate } 2288*7c478bd9Sstevel@tonic-gate 2289*7c478bd9Sstevel@tonic-gate if ((async->async_flags & ASYNC_SERVICEIMM) || needsoft || 2290*7c478bd9Sstevel@tonic-gate (RING_FRAC(async)) || (async->async_polltid == 0)) 2291*7c478bd9Sstevel@tonic-gate ASYSETSOFT(asy); /* need a soft interrupt */ 2292*7c478bd9Sstevel@tonic-gate } 2293*7c478bd9Sstevel@tonic-gate 2294*7c478bd9Sstevel@tonic-gate /* 2295*7c478bd9Sstevel@tonic-gate * Modem status interrupt. 2296*7c478bd9Sstevel@tonic-gate * 2297*7c478bd9Sstevel@tonic-gate * (Note: It is assumed that the MSR hasn't been read by asyintr().) 2298*7c478bd9Sstevel@tonic-gate */ 2299*7c478bd9Sstevel@tonic-gate 2300*7c478bd9Sstevel@tonic-gate static void 2301*7c478bd9Sstevel@tonic-gate async_msint(struct asycom *asy) 2302*7c478bd9Sstevel@tonic-gate { 2303*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 2304*7c478bd9Sstevel@tonic-gate int msr, t_cflag = async->async_ttycommon.t_cflag; 2305*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2306*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 2307*7c478bd9Sstevel@tonic-gate #endif 2308*7c478bd9Sstevel@tonic-gate 2309*7c478bd9Sstevel@tonic-gate async_msint_retry: 2310*7c478bd9Sstevel@tonic-gate /* this resets the interrupt */ 2311*7c478bd9Sstevel@tonic-gate msr = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + MSR); 2312*7c478bd9Sstevel@tonic-gate DEBUGCONT10(ASY_DEBUG_STATE, 2313*7c478bd9Sstevel@tonic-gate "async%d_msint call #%d:\n" 2314*7c478bd9Sstevel@tonic-gate " transition: %3s %3s %3s %3s\n" 2315*7c478bd9Sstevel@tonic-gate "current state: %3s %3s %3s %3s\n", 2316*7c478bd9Sstevel@tonic-gate instance, 2317*7c478bd9Sstevel@tonic-gate ++(asy->asy_msint_cnt), 2318*7c478bd9Sstevel@tonic-gate (msr & DCTS) ? "DCTS" : " ", 2319*7c478bd9Sstevel@tonic-gate (msr & DDSR) ? "DDSR" : " ", 2320*7c478bd9Sstevel@tonic-gate (msr & DRI) ? "DRI " : " ", 2321*7c478bd9Sstevel@tonic-gate (msr & DDCD) ? "DDCD" : " ", 2322*7c478bd9Sstevel@tonic-gate (msr & CTS) ? "CTS " : " ", 2323*7c478bd9Sstevel@tonic-gate (msr & DSR) ? "DSR " : " ", 2324*7c478bd9Sstevel@tonic-gate (msr & RI) ? "RI " : " ", 2325*7c478bd9Sstevel@tonic-gate (msr & DCD) ? "DCD " : " "); 2326*7c478bd9Sstevel@tonic-gate 2327*7c478bd9Sstevel@tonic-gate /* If CTS status is changed, do H/W output flow control */ 2328*7c478bd9Sstevel@tonic-gate if ((t_cflag & CRTSCTS) && (((asy->asy_msr ^ msr) & CTS) != 0)) 2329*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_output(asy, 2330*7c478bd9Sstevel@tonic-gate msr & CTS ? FLOW_START : FLOW_STOP); 2331*7c478bd9Sstevel@tonic-gate /* 2332*7c478bd9Sstevel@tonic-gate * Reading MSR resets the interrupt, we save the 2333*7c478bd9Sstevel@tonic-gate * value of msr so that other functions could examine MSR by 2334*7c478bd9Sstevel@tonic-gate * looking at asy_msr. 2335*7c478bd9Sstevel@tonic-gate */ 2336*7c478bd9Sstevel@tonic-gate asy->asy_msr = (uchar_t)msr; 2337*7c478bd9Sstevel@tonic-gate 2338*7c478bd9Sstevel@tonic-gate /* Handle PPS event */ 2339*7c478bd9Sstevel@tonic-gate if (asy->asy_flags & ASY_PPS) 2340*7c478bd9Sstevel@tonic-gate asy_ppsevent(asy, msr); 2341*7c478bd9Sstevel@tonic-gate 2342*7c478bd9Sstevel@tonic-gate async->async_ext++; 2343*7c478bd9Sstevel@tonic-gate ASYSETSOFT(asy); 2344*7c478bd9Sstevel@tonic-gate /* 2345*7c478bd9Sstevel@tonic-gate * We will make sure that the modem status presented to us 2346*7c478bd9Sstevel@tonic-gate * during the previous read has not changed. If the chip samples 2347*7c478bd9Sstevel@tonic-gate * the modem status on the falling edge of the interrupt line, 2348*7c478bd9Sstevel@tonic-gate * and uses this state as the base for detecting change of modem 2349*7c478bd9Sstevel@tonic-gate * status, we would miss a change of modem status event that occured 2350*7c478bd9Sstevel@tonic-gate * after we initiated a read MSR operation. 2351*7c478bd9Sstevel@tonic-gate */ 2352*7c478bd9Sstevel@tonic-gate msr = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + MSR); 2353*7c478bd9Sstevel@tonic-gate if (STATES(msr) != STATES(asy->asy_msr)) 2354*7c478bd9Sstevel@tonic-gate goto async_msint_retry; 2355*7c478bd9Sstevel@tonic-gate } 2356*7c478bd9Sstevel@tonic-gate 2357*7c478bd9Sstevel@tonic-gate /* 2358*7c478bd9Sstevel@tonic-gate * Handle a second-stage interrupt. 2359*7c478bd9Sstevel@tonic-gate */ 2360*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2361*7c478bd9Sstevel@tonic-gate uint_t 2362*7c478bd9Sstevel@tonic-gate asysoftintr(caddr_t intarg) 2363*7c478bd9Sstevel@tonic-gate { 2364*7c478bd9Sstevel@tonic-gate struct asycom *asy; 2365*7c478bd9Sstevel@tonic-gate int rv; 2366*7c478bd9Sstevel@tonic-gate int instance; 2367*7c478bd9Sstevel@tonic-gate 2368*7c478bd9Sstevel@tonic-gate /* 2369*7c478bd9Sstevel@tonic-gate * Test and clear soft interrupt. 2370*7c478bd9Sstevel@tonic-gate */ 2371*7c478bd9Sstevel@tonic-gate mutex_enter(&asy_soft_lock); 2372*7c478bd9Sstevel@tonic-gate DEBUGCONT0(ASY_DEBUG_PROCS, "asysoftintr: enter\n"); 2373*7c478bd9Sstevel@tonic-gate rv = asysoftpend; 2374*7c478bd9Sstevel@tonic-gate if (rv != 0) 2375*7c478bd9Sstevel@tonic-gate asysoftpend = 0; 2376*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_soft_lock); 2377*7c478bd9Sstevel@tonic-gate 2378*7c478bd9Sstevel@tonic-gate if (rv) { 2379*7c478bd9Sstevel@tonic-gate /* 2380*7c478bd9Sstevel@tonic-gate * Note - we can optimize the loop by remembering the last 2381*7c478bd9Sstevel@tonic-gate * device that requested soft interrupt 2382*7c478bd9Sstevel@tonic-gate */ 2383*7c478bd9Sstevel@tonic-gate for (instance = 0; instance <= max_asy_instance; instance++) { 2384*7c478bd9Sstevel@tonic-gate asy = ddi_get_soft_state(asy_soft_state, instance); 2385*7c478bd9Sstevel@tonic-gate if (asy == NULL || asy->asy_priv == NULL) 2386*7c478bd9Sstevel@tonic-gate continue; 2387*7c478bd9Sstevel@tonic-gate mutex_enter(&asy_soft_lock); 2388*7c478bd9Sstevel@tonic-gate if (asy->asy_flags & ASY_NEEDSOFT) { 2389*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~ASY_NEEDSOFT; 2390*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_soft_lock); 2391*7c478bd9Sstevel@tonic-gate async_softint(asy); 2392*7c478bd9Sstevel@tonic-gate } else 2393*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_soft_lock); 2394*7c478bd9Sstevel@tonic-gate } 2395*7c478bd9Sstevel@tonic-gate } 2396*7c478bd9Sstevel@tonic-gate return (rv ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 2397*7c478bd9Sstevel@tonic-gate } 2398*7c478bd9Sstevel@tonic-gate 2399*7c478bd9Sstevel@tonic-gate /* 2400*7c478bd9Sstevel@tonic-gate * Handle a software interrupt. 2401*7c478bd9Sstevel@tonic-gate */ 2402*7c478bd9Sstevel@tonic-gate static void 2403*7c478bd9Sstevel@tonic-gate async_softint(struct asycom *asy) 2404*7c478bd9Sstevel@tonic-gate { 2405*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 2406*7c478bd9Sstevel@tonic-gate short cc; 2407*7c478bd9Sstevel@tonic-gate mblk_t *bp; 2408*7c478bd9Sstevel@tonic-gate queue_t *q; 2409*7c478bd9Sstevel@tonic-gate uchar_t val; 2410*7c478bd9Sstevel@tonic-gate uchar_t c; 2411*7c478bd9Sstevel@tonic-gate tty_common_t *tp; 2412*7c478bd9Sstevel@tonic-gate int nb; 2413*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 2414*7c478bd9Sstevel@tonic-gate 2415*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_PROCS, "async%d_softint\n", instance); 2416*7c478bd9Sstevel@tonic-gate mutex_enter(&asy_soft_lock); 2417*7c478bd9Sstevel@tonic-gate if (asy->asy_flags & ASY_DOINGSOFT) { 2418*7c478bd9Sstevel@tonic-gate asy->asy_flags |= ASY_DOINGSOFT_RETRY; 2419*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_soft_lock); 2420*7c478bd9Sstevel@tonic-gate return; 2421*7c478bd9Sstevel@tonic-gate } 2422*7c478bd9Sstevel@tonic-gate asy->asy_flags |= ASY_DOINGSOFT; 2423*7c478bd9Sstevel@tonic-gate begin: 2424*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~ASY_DOINGSOFT_RETRY; 2425*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_soft_lock); 2426*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2427*7c478bd9Sstevel@tonic-gate tp = &async->async_ttycommon; 2428*7c478bd9Sstevel@tonic-gate q = tp->t_readq; 2429*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_OUT_FLW_RESUME) { 2430*7c478bd9Sstevel@tonic-gate if (async->async_ocnt > 0) { 2431*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2432*7c478bd9Sstevel@tonic-gate async_resume(async); 2433*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2434*7c478bd9Sstevel@tonic-gate } else { 2435*7c478bd9Sstevel@tonic-gate if (async->async_xmitblk) 2436*7c478bd9Sstevel@tonic-gate freeb(async->async_xmitblk); 2437*7c478bd9Sstevel@tonic-gate async->async_xmitblk = NULL; 2438*7c478bd9Sstevel@tonic-gate async_start(async); 2439*7c478bd9Sstevel@tonic-gate } 2440*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_OUT_FLW_RESUME; 2441*7c478bd9Sstevel@tonic-gate } 2442*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2443*7c478bd9Sstevel@tonic-gate if (async->async_ext) { 2444*7c478bd9Sstevel@tonic-gate async->async_ext = 0; 2445*7c478bd9Sstevel@tonic-gate /* check for carrier up */ 2446*7c478bd9Sstevel@tonic-gate DEBUGCONT3(ASY_DEBUG_MODM2, 2447*7c478bd9Sstevel@tonic-gate "async%d_softint: asy_msr & DCD = %x, " 2448*7c478bd9Sstevel@tonic-gate "tp->t_flags & TS_SOFTCAR = %x\n", 2449*7c478bd9Sstevel@tonic-gate instance, 2450*7c478bd9Sstevel@tonic-gate asy->asy_msr & DCD, 2451*7c478bd9Sstevel@tonic-gate tp->t_flags & TS_SOFTCAR); 2452*7c478bd9Sstevel@tonic-gate if (asy->asy_msr & DCD) { 2453*7c478bd9Sstevel@tonic-gate /* carrier present */ 2454*7c478bd9Sstevel@tonic-gate if ((async->async_flags & ASYNC_CARR_ON) == 0) { 2455*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODM2, 2456*7c478bd9Sstevel@tonic-gate "async%d_softint: set ASYNC_CARR_ON\n", 2457*7c478bd9Sstevel@tonic-gate instance); 2458*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_CARR_ON; 2459*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_ISOPEN) { 2460*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2461*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2462*7c478bd9Sstevel@tonic-gate (void) putctl(q, M_UNHANGUP); 2463*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2464*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2465*7c478bd9Sstevel@tonic-gate } 2466*7c478bd9Sstevel@tonic-gate cv_broadcast(&async->async_flags_cv); 2467*7c478bd9Sstevel@tonic-gate } 2468*7c478bd9Sstevel@tonic-gate } else { 2469*7c478bd9Sstevel@tonic-gate if ((async->async_flags & ASYNC_CARR_ON) && 2470*7c478bd9Sstevel@tonic-gate !(tp->t_cflag & CLOCAL) && 2471*7c478bd9Sstevel@tonic-gate !(tp->t_flags & TS_SOFTCAR)) { 2472*7c478bd9Sstevel@tonic-gate int flushflag; 2473*7c478bd9Sstevel@tonic-gate 2474*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 2475*7c478bd9Sstevel@tonic-gate "async%d_softint: carrier dropped, " 2476*7c478bd9Sstevel@tonic-gate "so drop DTR\n", 2477*7c478bd9Sstevel@tonic-gate instance); 2478*7c478bd9Sstevel@tonic-gate /* 2479*7c478bd9Sstevel@tonic-gate * Carrier went away. 2480*7c478bd9Sstevel@tonic-gate * Drop DTR, abort any output in 2481*7c478bd9Sstevel@tonic-gate * progress, indicate that output is 2482*7c478bd9Sstevel@tonic-gate * not stopped, and send a hangup 2483*7c478bd9Sstevel@tonic-gate * notification upstream. 2484*7c478bd9Sstevel@tonic-gate */ 2485*7c478bd9Sstevel@tonic-gate val = ddi_io_get8(asy->asy_iohandle, 2486*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + MCR); 2487*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 2488*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + MCR, (val & ~DTR)); 2489*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_BUSY) { 2490*7c478bd9Sstevel@tonic-gate DEBUGCONT0(ASY_DEBUG_BUSY, 2491*7c478bd9Sstevel@tonic-gate "async_softint: " 2492*7c478bd9Sstevel@tonic-gate "Carrier dropped. " 2493*7c478bd9Sstevel@tonic-gate "Clearing async_ocnt\n"); 2494*7c478bd9Sstevel@tonic-gate async->async_ocnt = 0; 2495*7c478bd9Sstevel@tonic-gate } /* if */ 2496*7c478bd9Sstevel@tonic-gate 2497*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_STOPPED; 2498*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_ISOPEN) { 2499*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2500*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2501*7c478bd9Sstevel@tonic-gate (void) putctl(q, M_HANGUP); 2502*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2503*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, 2504*7c478bd9Sstevel@tonic-gate "async%d_softint: " 2505*7c478bd9Sstevel@tonic-gate "putctl(q, M_HANGUP)\n", 2506*7c478bd9Sstevel@tonic-gate instance); 2507*7c478bd9Sstevel@tonic-gate /* 2508*7c478bd9Sstevel@tonic-gate * Flush FIFO buffers 2509*7c478bd9Sstevel@tonic-gate * Any data left in there is invalid now 2510*7c478bd9Sstevel@tonic-gate */ 2511*7c478bd9Sstevel@tonic-gate if (asy->asy_use_fifo == FIFO_ON) 2512*7c478bd9Sstevel@tonic-gate asy_reset_fifo(asy, FIFOTXFLSH); 2513*7c478bd9Sstevel@tonic-gate /* 2514*7c478bd9Sstevel@tonic-gate * Flush our write queue if we have one. 2515*7c478bd9Sstevel@tonic-gate * 2516*7c478bd9Sstevel@tonic-gate * If we're in the midst of close, then flush 2517*7c478bd9Sstevel@tonic-gate * everything. Don't leave stale ioctls lying 2518*7c478bd9Sstevel@tonic-gate * about. 2519*7c478bd9Sstevel@tonic-gate */ 2520*7c478bd9Sstevel@tonic-gate flushflag = (async->async_flags & 2521*7c478bd9Sstevel@tonic-gate ASYNC_CLOSING) ? FLUSHALL : FLUSHDATA; 2522*7c478bd9Sstevel@tonic-gate flushq(tp->t_writeq, flushflag); 2523*7c478bd9Sstevel@tonic-gate 2524*7c478bd9Sstevel@tonic-gate bp = async->async_xmitblk; /* active msg */ 2525*7c478bd9Sstevel@tonic-gate if (bp != NULL) { 2526*7c478bd9Sstevel@tonic-gate freeb(bp); 2527*7c478bd9Sstevel@tonic-gate async->async_xmitblk = NULL; 2528*7c478bd9Sstevel@tonic-gate } 2529*7c478bd9Sstevel@tonic-gate 2530*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2531*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_BUSY; 2532*7c478bd9Sstevel@tonic-gate /* 2533*7c478bd9Sstevel@tonic-gate * This message warns of Carrier loss 2534*7c478bd9Sstevel@tonic-gate * with data left to transmit can hang the 2535*7c478bd9Sstevel@tonic-gate * system. 2536*7c478bd9Sstevel@tonic-gate */ 2537*7c478bd9Sstevel@tonic-gate DEBUGCONT0(ASY_DEBUG_MODEM, 2538*7c478bd9Sstevel@tonic-gate "async_softint: Flushing to " 2539*7c478bd9Sstevel@tonic-gate "prevent HUPCL hanging\n"); 2540*7c478bd9Sstevel@tonic-gate } /* if (ASYNC_ISOPEN) */ 2541*7c478bd9Sstevel@tonic-gate } /* if (ASYNC_CARR_ON && CLOCAL) */ 2542*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_CARR_ON; 2543*7c478bd9Sstevel@tonic-gate cv_broadcast(&async->async_flags_cv); 2544*7c478bd9Sstevel@tonic-gate } /* else */ 2545*7c478bd9Sstevel@tonic-gate } /* if (async->async_ext) */ 2546*7c478bd9Sstevel@tonic-gate 2547*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2548*7c478bd9Sstevel@tonic-gate 2549*7c478bd9Sstevel@tonic-gate /* 2550*7c478bd9Sstevel@tonic-gate * If data has been added to the circular buffer, remove 2551*7c478bd9Sstevel@tonic-gate * it from the buffer, and send it up the stream if there's 2552*7c478bd9Sstevel@tonic-gate * somebody listening. Try to do it 16 bytes at a time. If we 2553*7c478bd9Sstevel@tonic-gate * have more than 16 bytes to move, move 16 byte chunks and 2554*7c478bd9Sstevel@tonic-gate * leave the rest for next time around (maybe it will grow). 2555*7c478bd9Sstevel@tonic-gate */ 2556*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2557*7c478bd9Sstevel@tonic-gate if (!(async->async_flags & ASYNC_ISOPEN)) { 2558*7c478bd9Sstevel@tonic-gate RING_INIT(async); 2559*7c478bd9Sstevel@tonic-gate goto rv; 2560*7c478bd9Sstevel@tonic-gate } 2561*7c478bd9Sstevel@tonic-gate if ((cc = RING_CNT(async)) <= 0) 2562*7c478bd9Sstevel@tonic-gate goto rv; 2563*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2564*7c478bd9Sstevel@tonic-gate 2565*7c478bd9Sstevel@tonic-gate if (!canput(q)) { 2566*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2567*7c478bd9Sstevel@tonic-gate if (!(async->async_inflow_source & IN_FLOW_STREAMS)) { 2568*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_input(asy, FLOW_STOP, 2569*7c478bd9Sstevel@tonic-gate IN_FLOW_STREAMS); 2570*7c478bd9Sstevel@tonic-gate (void) async_flowcontrol_sw_input(asy, FLOW_STOP, 2571*7c478bd9Sstevel@tonic-gate IN_FLOW_STREAMS); 2572*7c478bd9Sstevel@tonic-gate } 2573*7c478bd9Sstevel@tonic-gate goto rv; 2574*7c478bd9Sstevel@tonic-gate } 2575*7c478bd9Sstevel@tonic-gate if (async->async_inflow_source & IN_FLOW_STREAMS) { 2576*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2577*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_input(asy, FLOW_START, 2578*7c478bd9Sstevel@tonic-gate IN_FLOW_STREAMS); 2579*7c478bd9Sstevel@tonic-gate (void) async_flowcontrol_sw_input(asy, FLOW_START, 2580*7c478bd9Sstevel@tonic-gate IN_FLOW_STREAMS); 2581*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2582*7c478bd9Sstevel@tonic-gate } 2583*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_INPUT, 2584*7c478bd9Sstevel@tonic-gate "async%d_softint: %d char(s) in queue.\n", instance, cc); 2585*7c478bd9Sstevel@tonic-gate if (!(bp = allocb(cc, BPRI_MED))) { 2586*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2587*7c478bd9Sstevel@tonic-gate ttycommon_qfull(&async->async_ttycommon, q); 2588*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2589*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2590*7c478bd9Sstevel@tonic-gate goto rv; 2591*7c478bd9Sstevel@tonic-gate } 2592*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2593*7c478bd9Sstevel@tonic-gate do { 2594*7c478bd9Sstevel@tonic-gate if (RING_ERR(async, S_ERRORS)) { 2595*7c478bd9Sstevel@tonic-gate RING_UNMARK(async); 2596*7c478bd9Sstevel@tonic-gate c = RING_GET(async); 2597*7c478bd9Sstevel@tonic-gate break; 2598*7c478bd9Sstevel@tonic-gate } else 2599*7c478bd9Sstevel@tonic-gate *bp->b_wptr++ = RING_GET(async); 2600*7c478bd9Sstevel@tonic-gate } while (--cc); 2601*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2602*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2603*7c478bd9Sstevel@tonic-gate if (bp->b_wptr > bp->b_rptr) { 2604*7c478bd9Sstevel@tonic-gate if (!canput(q)) { 2605*7c478bd9Sstevel@tonic-gate asyerror(CE_NOTE, "asy%d: local queue full", 2606*7c478bd9Sstevel@tonic-gate instance); 2607*7c478bd9Sstevel@tonic-gate freemsg(bp); 2608*7c478bd9Sstevel@tonic-gate } else 2609*7c478bd9Sstevel@tonic-gate (void) putq(q, bp); 2610*7c478bd9Sstevel@tonic-gate } else 2611*7c478bd9Sstevel@tonic-gate freemsg(bp); 2612*7c478bd9Sstevel@tonic-gate /* 2613*7c478bd9Sstevel@tonic-gate * If we have a parity error, then send 2614*7c478bd9Sstevel@tonic-gate * up an M_BREAK with the "bad" 2615*7c478bd9Sstevel@tonic-gate * character as an argument. Let ldterm 2616*7c478bd9Sstevel@tonic-gate * figure out what to do with the error. 2617*7c478bd9Sstevel@tonic-gate */ 2618*7c478bd9Sstevel@tonic-gate if (cc) { 2619*7c478bd9Sstevel@tonic-gate (void) putctl1(q, M_BREAK, c); 2620*7c478bd9Sstevel@tonic-gate ASYSETSOFT(async->async_common); /* finish cc chars */ 2621*7c478bd9Sstevel@tonic-gate } 2622*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2623*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2624*7c478bd9Sstevel@tonic-gate rv: 2625*7c478bd9Sstevel@tonic-gate if ((RING_CNT(async) < (RINGSIZE/4)) && 2626*7c478bd9Sstevel@tonic-gate (async->async_inflow_source & IN_FLOW_RINGBUFF)) { 2627*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_input(asy, FLOW_START, IN_FLOW_RINGBUFF); 2628*7c478bd9Sstevel@tonic-gate (void) async_flowcontrol_sw_input(asy, FLOW_START, 2629*7c478bd9Sstevel@tonic-gate IN_FLOW_RINGBUFF); 2630*7c478bd9Sstevel@tonic-gate } 2631*7c478bd9Sstevel@tonic-gate 2632*7c478bd9Sstevel@tonic-gate /* 2633*7c478bd9Sstevel@tonic-gate * If a transmission has finished, indicate that it's finished, 2634*7c478bd9Sstevel@tonic-gate * and start that line up again. 2635*7c478bd9Sstevel@tonic-gate */ 2636*7c478bd9Sstevel@tonic-gate if (async->async_break > 0) { 2637*7c478bd9Sstevel@tonic-gate nb = async->async_break; 2638*7c478bd9Sstevel@tonic-gate async->async_break = 0; 2639*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_ISOPEN) { 2640*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2641*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2642*7c478bd9Sstevel@tonic-gate for (; nb > 0; nb--) 2643*7c478bd9Sstevel@tonic-gate (void) putctl(q, M_BREAK); 2644*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2645*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2646*7c478bd9Sstevel@tonic-gate } 2647*7c478bd9Sstevel@tonic-gate } 2648*7c478bd9Sstevel@tonic-gate if (async->async_ocnt <= 0 && (async->async_flags & ASYNC_BUSY)) { 2649*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_BUSY, 2650*7c478bd9Sstevel@tonic-gate "async%d_softint: Clearing ASYNC_BUSY. async_ocnt=%d\n", 2651*7c478bd9Sstevel@tonic-gate instance, 2652*7c478bd9Sstevel@tonic-gate async->async_ocnt); 2653*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_BUSY; 2654*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2655*7c478bd9Sstevel@tonic-gate if (async->async_xmitblk) 2656*7c478bd9Sstevel@tonic-gate freeb(async->async_xmitblk); 2657*7c478bd9Sstevel@tonic-gate async->async_xmitblk = NULL; 2658*7c478bd9Sstevel@tonic-gate async_start(async); 2659*7c478bd9Sstevel@tonic-gate /* 2660*7c478bd9Sstevel@tonic-gate * If the flag isn't set after doing the async_start above, we 2661*7c478bd9Sstevel@tonic-gate * may have finished all the queued output. Signal any thread 2662*7c478bd9Sstevel@tonic-gate * stuck in close. 2663*7c478bd9Sstevel@tonic-gate */ 2664*7c478bd9Sstevel@tonic-gate if (!(async->async_flags & ASYNC_BUSY)) 2665*7c478bd9Sstevel@tonic-gate cv_broadcast(&async->async_flags_cv); 2666*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2667*7c478bd9Sstevel@tonic-gate } 2668*7c478bd9Sstevel@tonic-gate /* 2669*7c478bd9Sstevel@tonic-gate * A note about these overrun bits: all they do is *tell* someone 2670*7c478bd9Sstevel@tonic-gate * about an error- They do not track multiple errors. In fact, 2671*7c478bd9Sstevel@tonic-gate * you could consider them latched register bits if you like. 2672*7c478bd9Sstevel@tonic-gate * We are only interested in printing the error message once for 2673*7c478bd9Sstevel@tonic-gate * any cluster of overrun errrors. 2674*7c478bd9Sstevel@tonic-gate */ 2675*7c478bd9Sstevel@tonic-gate if (async->async_hw_overrun) { 2676*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_ISOPEN) { 2677*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2678*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2679*7c478bd9Sstevel@tonic-gate asyerror(CE_NOTE, "asy%d: silo overflow", instance); 2680*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2681*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2682*7c478bd9Sstevel@tonic-gate } 2683*7c478bd9Sstevel@tonic-gate async->async_hw_overrun = 0; 2684*7c478bd9Sstevel@tonic-gate } 2685*7c478bd9Sstevel@tonic-gate if (async->async_sw_overrun) { 2686*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_ISOPEN) { 2687*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2688*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2689*7c478bd9Sstevel@tonic-gate asyerror(CE_NOTE, "asy%d: ring buffer overflow", 2690*7c478bd9Sstevel@tonic-gate instance); 2691*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2692*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2693*7c478bd9Sstevel@tonic-gate } 2694*7c478bd9Sstevel@tonic-gate async->async_sw_overrun = 0; 2695*7c478bd9Sstevel@tonic-gate } 2696*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2697*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2698*7c478bd9Sstevel@tonic-gate mutex_enter(&asy_soft_lock); 2699*7c478bd9Sstevel@tonic-gate if (asy->asy_flags & ASY_DOINGSOFT_RETRY) { 2700*7c478bd9Sstevel@tonic-gate goto begin; 2701*7c478bd9Sstevel@tonic-gate } 2702*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~ASY_DOINGSOFT; 2703*7c478bd9Sstevel@tonic-gate mutex_exit(&asy_soft_lock); 2704*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_PROCS, "async%d_softint: done\n", instance); 2705*7c478bd9Sstevel@tonic-gate } 2706*7c478bd9Sstevel@tonic-gate 2707*7c478bd9Sstevel@tonic-gate /* 2708*7c478bd9Sstevel@tonic-gate * Restart output on a line after a delay or break timer expired. 2709*7c478bd9Sstevel@tonic-gate */ 2710*7c478bd9Sstevel@tonic-gate static void 2711*7c478bd9Sstevel@tonic-gate async_restart(void *arg) 2712*7c478bd9Sstevel@tonic-gate { 2713*7c478bd9Sstevel@tonic-gate struct asyncline *async = (struct asyncline *)arg; 2714*7c478bd9Sstevel@tonic-gate struct asycom *asy = async->async_common; 2715*7c478bd9Sstevel@tonic-gate uchar_t lcr; 2716*7c478bd9Sstevel@tonic-gate 2717*7c478bd9Sstevel@tonic-gate /* 2718*7c478bd9Sstevel@tonic-gate * If break timer expired, turn off the break bit. 2719*7c478bd9Sstevel@tonic-gate */ 2720*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2721*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 2722*7c478bd9Sstevel@tonic-gate 2723*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_PROCS, "async%d_restart\n", instance); 2724*7c478bd9Sstevel@tonic-gate #endif 2725*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2726*7c478bd9Sstevel@tonic-gate /* 2727*7c478bd9Sstevel@tonic-gate * If ASYNC_OUT_SUSPEND is also set, we don't really 2728*7c478bd9Sstevel@tonic-gate * clean the HW break, TIOCCBRK is responsible for this. 2729*7c478bd9Sstevel@tonic-gate */ 2730*7c478bd9Sstevel@tonic-gate if ((async->async_flags & ASYNC_BREAK) && 2731*7c478bd9Sstevel@tonic-gate !(async->async_flags & ASYNC_OUT_SUSPEND)) { 2732*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2733*7c478bd9Sstevel@tonic-gate lcr = ddi_io_get8(asy->asy_iohandle, 2734*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR); 2735*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 2736*7c478bd9Sstevel@tonic-gate (lcr & ~SETBREAK)); 2737*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2738*7c478bd9Sstevel@tonic-gate } 2739*7c478bd9Sstevel@tonic-gate async->async_flags &= ~(ASYNC_DELAY|ASYNC_BREAK); 2740*7c478bd9Sstevel@tonic-gate cv_broadcast(&async->async_flags_cv); 2741*7c478bd9Sstevel@tonic-gate async_start(async); 2742*7c478bd9Sstevel@tonic-gate 2743*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2744*7c478bd9Sstevel@tonic-gate } 2745*7c478bd9Sstevel@tonic-gate 2746*7c478bd9Sstevel@tonic-gate static void 2747*7c478bd9Sstevel@tonic-gate async_start(struct asyncline *async) 2748*7c478bd9Sstevel@tonic-gate { 2749*7c478bd9Sstevel@tonic-gate async_nstart(async, 0); 2750*7c478bd9Sstevel@tonic-gate } 2751*7c478bd9Sstevel@tonic-gate 2752*7c478bd9Sstevel@tonic-gate /* 2753*7c478bd9Sstevel@tonic-gate * Start output on a line, unless it's busy, frozen, or otherwise. 2754*7c478bd9Sstevel@tonic-gate */ 2755*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2756*7c478bd9Sstevel@tonic-gate static void 2757*7c478bd9Sstevel@tonic-gate async_nstart(struct asyncline *async, int mode) 2758*7c478bd9Sstevel@tonic-gate { 2759*7c478bd9Sstevel@tonic-gate struct asycom *asy = async->async_common; 2760*7c478bd9Sstevel@tonic-gate int cc; 2761*7c478bd9Sstevel@tonic-gate queue_t *q; 2762*7c478bd9Sstevel@tonic-gate mblk_t *bp; 2763*7c478bd9Sstevel@tonic-gate uchar_t *xmit_addr; 2764*7c478bd9Sstevel@tonic-gate uchar_t val; 2765*7c478bd9Sstevel@tonic-gate int fifo_len = 1; 2766*7c478bd9Sstevel@tonic-gate boolean_t didsome; 2767*7c478bd9Sstevel@tonic-gate mblk_t *nbp; 2768*7c478bd9Sstevel@tonic-gate 2769*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2770*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 2771*7c478bd9Sstevel@tonic-gate 2772*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_PROCS, "async%d_nstart\n", instance); 2773*7c478bd9Sstevel@tonic-gate #endif 2774*7c478bd9Sstevel@tonic-gate if (asy->asy_use_fifo == FIFO_ON) { 2775*7c478bd9Sstevel@tonic-gate fifo_len = asy->asy_fifo_buf; /* with FIFO buffers */ 2776*7c478bd9Sstevel@tonic-gate if (fifo_len > asy_max_tx_fifo) 2777*7c478bd9Sstevel@tonic-gate fifo_len = asy_max_tx_fifo; 2778*7c478bd9Sstevel@tonic-gate } 2779*7c478bd9Sstevel@tonic-gate 2780*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl)); 2781*7c478bd9Sstevel@tonic-gate 2782*7c478bd9Sstevel@tonic-gate /* 2783*7c478bd9Sstevel@tonic-gate * If the chip is busy (i.e., we're waiting for a break timeout 2784*7c478bd9Sstevel@tonic-gate * to expire, or for the current transmission to finish, or for 2785*7c478bd9Sstevel@tonic-gate * output to finish draining from chip), don't grab anything new. 2786*7c478bd9Sstevel@tonic-gate */ 2787*7c478bd9Sstevel@tonic-gate if (async->async_flags & (ASYNC_BREAK|ASYNC_BUSY)) { 2788*7c478bd9Sstevel@tonic-gate DEBUGCONT2((mode? ASY_DEBUG_OUT : 0), 2789*7c478bd9Sstevel@tonic-gate "async%d_nstart: start %s.\n", 2790*7c478bd9Sstevel@tonic-gate instance, 2791*7c478bd9Sstevel@tonic-gate async->async_flags & ASYNC_BREAK ? "break" : "busy"); 2792*7c478bd9Sstevel@tonic-gate return; 2793*7c478bd9Sstevel@tonic-gate } 2794*7c478bd9Sstevel@tonic-gate 2795*7c478bd9Sstevel@tonic-gate /* 2796*7c478bd9Sstevel@tonic-gate * Check only pended sw input flow control. 2797*7c478bd9Sstevel@tonic-gate */ 2798*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2799*7c478bd9Sstevel@tonic-gate if (async_flowcontrol_sw_input(asy, FLOW_CHECK, IN_FLOW_NULL)) 2800*7c478bd9Sstevel@tonic-gate fifo_len--; 2801*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2802*7c478bd9Sstevel@tonic-gate 2803*7c478bd9Sstevel@tonic-gate /* 2804*7c478bd9Sstevel@tonic-gate * If we're waiting for a delay timeout to expire, don't grab 2805*7c478bd9Sstevel@tonic-gate * anything new. 2806*7c478bd9Sstevel@tonic-gate */ 2807*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_DELAY) { 2808*7c478bd9Sstevel@tonic-gate DEBUGCONT1((mode? ASY_DEBUG_OUT : 0), 2809*7c478bd9Sstevel@tonic-gate "async%d_nstart: start ASYNC_DELAY.\n", instance); 2810*7c478bd9Sstevel@tonic-gate return; 2811*7c478bd9Sstevel@tonic-gate } 2812*7c478bd9Sstevel@tonic-gate 2813*7c478bd9Sstevel@tonic-gate if ((q = async->async_ttycommon.t_writeq) == NULL) { 2814*7c478bd9Sstevel@tonic-gate DEBUGCONT1((mode? ASY_DEBUG_OUT : 0), 2815*7c478bd9Sstevel@tonic-gate "async%d_nstart: start writeq is null.\n", instance); 2816*7c478bd9Sstevel@tonic-gate return; /* not attached to a stream */ 2817*7c478bd9Sstevel@tonic-gate } 2818*7c478bd9Sstevel@tonic-gate 2819*7c478bd9Sstevel@tonic-gate for (;;) { 2820*7c478bd9Sstevel@tonic-gate if ((bp = getq(q)) == NULL) 2821*7c478bd9Sstevel@tonic-gate return; /* no data to transmit */ 2822*7c478bd9Sstevel@tonic-gate 2823*7c478bd9Sstevel@tonic-gate /* 2824*7c478bd9Sstevel@tonic-gate * We have a message block to work on. 2825*7c478bd9Sstevel@tonic-gate * Check whether it's a break, a delay, or an ioctl (the latter 2826*7c478bd9Sstevel@tonic-gate * occurs if the ioctl in question was waiting for the output 2827*7c478bd9Sstevel@tonic-gate * to drain). If it's one of those, process it immediately. 2828*7c478bd9Sstevel@tonic-gate */ 2829*7c478bd9Sstevel@tonic-gate switch (bp->b_datap->db_type) { 2830*7c478bd9Sstevel@tonic-gate 2831*7c478bd9Sstevel@tonic-gate case M_BREAK: 2832*7c478bd9Sstevel@tonic-gate /* 2833*7c478bd9Sstevel@tonic-gate * Set the break bit, and arrange for "async_restart" 2834*7c478bd9Sstevel@tonic-gate * to be called in 1/4 second; it will turn the 2835*7c478bd9Sstevel@tonic-gate * break bit off, and call "async_start" to grab 2836*7c478bd9Sstevel@tonic-gate * the next message. 2837*7c478bd9Sstevel@tonic-gate */ 2838*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2839*7c478bd9Sstevel@tonic-gate val = ddi_io_get8(asy->asy_iohandle, 2840*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR); 2841*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 2842*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR, (val | SETBREAK)); 2843*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2844*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_BREAK; 2845*7c478bd9Sstevel@tonic-gate (void) timeout(async_restart, (caddr_t)async, 2846*7c478bd9Sstevel@tonic-gate drv_usectohz(1000000)/4); 2847*7c478bd9Sstevel@tonic-gate freemsg(bp); 2848*7c478bd9Sstevel@tonic-gate return; /* wait for this to finish */ 2849*7c478bd9Sstevel@tonic-gate 2850*7c478bd9Sstevel@tonic-gate case M_DELAY: 2851*7c478bd9Sstevel@tonic-gate /* 2852*7c478bd9Sstevel@tonic-gate * Arrange for "async_restart" to be called when the 2853*7c478bd9Sstevel@tonic-gate * delay expires; it will turn ASYNC_DELAY off, 2854*7c478bd9Sstevel@tonic-gate * and call "async_start" to grab the next message. 2855*7c478bd9Sstevel@tonic-gate */ 2856*7c478bd9Sstevel@tonic-gate (void) timeout(async_restart, (caddr_t)async, 2857*7c478bd9Sstevel@tonic-gate (int)(*(unsigned char *)bp->b_rptr + 6)); 2858*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_DELAY; 2859*7c478bd9Sstevel@tonic-gate freemsg(bp); 2860*7c478bd9Sstevel@tonic-gate return; /* wait for this to finish */ 2861*7c478bd9Sstevel@tonic-gate 2862*7c478bd9Sstevel@tonic-gate case M_IOCTL: 2863*7c478bd9Sstevel@tonic-gate /* 2864*7c478bd9Sstevel@tonic-gate * This ioctl was waiting for the output ahead of 2865*7c478bd9Sstevel@tonic-gate * it to drain; obviously, it has. Do it, and 2866*7c478bd9Sstevel@tonic-gate * then grab the next message after it. 2867*7c478bd9Sstevel@tonic-gate */ 2868*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2869*7c478bd9Sstevel@tonic-gate async_ioctl(async, q, bp); 2870*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2871*7c478bd9Sstevel@tonic-gate continue; 2872*7c478bd9Sstevel@tonic-gate } 2873*7c478bd9Sstevel@tonic-gate 2874*7c478bd9Sstevel@tonic-gate while (bp != NULL && (cc = bp->b_wptr - bp->b_rptr) == 0) { 2875*7c478bd9Sstevel@tonic-gate nbp = bp->b_cont; 2876*7c478bd9Sstevel@tonic-gate freeb(bp); 2877*7c478bd9Sstevel@tonic-gate bp = nbp; 2878*7c478bd9Sstevel@tonic-gate } 2879*7c478bd9Sstevel@tonic-gate if (bp != NULL) 2880*7c478bd9Sstevel@tonic-gate break; 2881*7c478bd9Sstevel@tonic-gate } 2882*7c478bd9Sstevel@tonic-gate 2883*7c478bd9Sstevel@tonic-gate /* 2884*7c478bd9Sstevel@tonic-gate * We have data to transmit. If output is stopped, put 2885*7c478bd9Sstevel@tonic-gate * it back and try again later. 2886*7c478bd9Sstevel@tonic-gate */ 2887*7c478bd9Sstevel@tonic-gate if (async->async_flags & (ASYNC_HW_OUT_FLW | ASYNC_SW_OUT_FLW | 2888*7c478bd9Sstevel@tonic-gate ASYNC_STOPPED | ASYNC_OUT_SUSPEND)) { 2889*7c478bd9Sstevel@tonic-gate (void) putbq(q, bp); 2890*7c478bd9Sstevel@tonic-gate return; 2891*7c478bd9Sstevel@tonic-gate } 2892*7c478bd9Sstevel@tonic-gate 2893*7c478bd9Sstevel@tonic-gate async->async_xmitblk = bp; 2894*7c478bd9Sstevel@tonic-gate xmit_addr = bp->b_rptr; 2895*7c478bd9Sstevel@tonic-gate bp = bp->b_cont; 2896*7c478bd9Sstevel@tonic-gate if (bp != NULL) 2897*7c478bd9Sstevel@tonic-gate (void) putbq(q, bp); /* not done with this message yet */ 2898*7c478bd9Sstevel@tonic-gate 2899*7c478bd9Sstevel@tonic-gate /* 2900*7c478bd9Sstevel@tonic-gate * In 5-bit mode, the high order bits are used 2901*7c478bd9Sstevel@tonic-gate * to indicate character sizes less than five, 2902*7c478bd9Sstevel@tonic-gate * so we need to explicitly mask before transmitting 2903*7c478bd9Sstevel@tonic-gate */ 2904*7c478bd9Sstevel@tonic-gate if ((async->async_ttycommon.t_cflag & CSIZE) == CS5) { 2905*7c478bd9Sstevel@tonic-gate unsigned char *p = xmit_addr; 2906*7c478bd9Sstevel@tonic-gate int cnt = cc; 2907*7c478bd9Sstevel@tonic-gate 2908*7c478bd9Sstevel@tonic-gate while (cnt--) 2909*7c478bd9Sstevel@tonic-gate *p++ &= (unsigned char) 0x1f; 2910*7c478bd9Sstevel@tonic-gate } 2911*7c478bd9Sstevel@tonic-gate 2912*7c478bd9Sstevel@tonic-gate /* 2913*7c478bd9Sstevel@tonic-gate * Set up this block for pseudo-DMA. 2914*7c478bd9Sstevel@tonic-gate */ 2915*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 2916*7c478bd9Sstevel@tonic-gate /* 2917*7c478bd9Sstevel@tonic-gate * If the transmitter is ready, shove the first 2918*7c478bd9Sstevel@tonic-gate * character out. 2919*7c478bd9Sstevel@tonic-gate */ 2920*7c478bd9Sstevel@tonic-gate didsome = B_FALSE; 2921*7c478bd9Sstevel@tonic-gate while (--fifo_len >= 0 && cc > 0) { 2922*7c478bd9Sstevel@tonic-gate if (!(ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + LSR) & 2923*7c478bd9Sstevel@tonic-gate XHRE)) 2924*7c478bd9Sstevel@tonic-gate break; 2925*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + DAT, 2926*7c478bd9Sstevel@tonic-gate *xmit_addr++); 2927*7c478bd9Sstevel@tonic-gate cc--; 2928*7c478bd9Sstevel@tonic-gate didsome = B_TRUE; 2929*7c478bd9Sstevel@tonic-gate } 2930*7c478bd9Sstevel@tonic-gate async->async_optr = xmit_addr; 2931*7c478bd9Sstevel@tonic-gate async->async_ocnt = cc; 2932*7c478bd9Sstevel@tonic-gate if (didsome) 2933*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_PROGRESS; 2934*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_BUSY, 2935*7c478bd9Sstevel@tonic-gate "async%d_nstart: Set ASYNC_BUSY. async_ocnt=%d\n", 2936*7c478bd9Sstevel@tonic-gate instance, 2937*7c478bd9Sstevel@tonic-gate async->async_ocnt); 2938*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_BUSY; 2939*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 2940*7c478bd9Sstevel@tonic-gate } 2941*7c478bd9Sstevel@tonic-gate 2942*7c478bd9Sstevel@tonic-gate /* 2943*7c478bd9Sstevel@tonic-gate * Resume output by poking the transmitter. 2944*7c478bd9Sstevel@tonic-gate */ 2945*7c478bd9Sstevel@tonic-gate static void 2946*7c478bd9Sstevel@tonic-gate async_resume(struct asyncline *async) 2947*7c478bd9Sstevel@tonic-gate { 2948*7c478bd9Sstevel@tonic-gate struct asycom *asy = async->async_common; 2949*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2950*7c478bd9Sstevel@tonic-gate int instance; 2951*7c478bd9Sstevel@tonic-gate #endif 2952*7c478bd9Sstevel@tonic-gate 2953*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl_hi)); 2954*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2955*7c478bd9Sstevel@tonic-gate instance = UNIT(async->async_dev); 2956*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_PROCS, "async%d_resume\n", instance); 2957*7c478bd9Sstevel@tonic-gate #endif 2958*7c478bd9Sstevel@tonic-gate 2959*7c478bd9Sstevel@tonic-gate if (ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + LSR) & XHRE) { 2960*7c478bd9Sstevel@tonic-gate if (async_flowcontrol_sw_input(asy, FLOW_CHECK, IN_FLOW_NULL)) 2961*7c478bd9Sstevel@tonic-gate return; 2962*7c478bd9Sstevel@tonic-gate if (async->async_ocnt > 0 && 2963*7c478bd9Sstevel@tonic-gate !(async->async_flags & 2964*7c478bd9Sstevel@tonic-gate (ASYNC_HW_OUT_FLW|ASYNC_SW_OUT_FLW|ASYNC_OUT_SUSPEND))) { 2965*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 2966*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT, *async->async_optr++); 2967*7c478bd9Sstevel@tonic-gate async->async_ocnt--; 2968*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_PROGRESS; 2969*7c478bd9Sstevel@tonic-gate } 2970*7c478bd9Sstevel@tonic-gate } 2971*7c478bd9Sstevel@tonic-gate } 2972*7c478bd9Sstevel@tonic-gate 2973*7c478bd9Sstevel@tonic-gate /* 2974*7c478bd9Sstevel@tonic-gate * Hold the untimed break to last the minimum time. 2975*7c478bd9Sstevel@tonic-gate */ 2976*7c478bd9Sstevel@tonic-gate static void 2977*7c478bd9Sstevel@tonic-gate async_hold_utbrk(void *arg) 2978*7c478bd9Sstevel@tonic-gate { 2979*7c478bd9Sstevel@tonic-gate struct asyncline *async = arg; 2980*7c478bd9Sstevel@tonic-gate struct asycom *asy = async->async_common; 2981*7c478bd9Sstevel@tonic-gate 2982*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 2983*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_HOLD_UTBRK; 2984*7c478bd9Sstevel@tonic-gate cv_broadcast(&async->async_flags_cv); 2985*7c478bd9Sstevel@tonic-gate async->async_utbrktid = 0; 2986*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 2987*7c478bd9Sstevel@tonic-gate } 2988*7c478bd9Sstevel@tonic-gate 2989*7c478bd9Sstevel@tonic-gate /* 2990*7c478bd9Sstevel@tonic-gate * Resume the untimed break. 2991*7c478bd9Sstevel@tonic-gate */ 2992*7c478bd9Sstevel@tonic-gate static void 2993*7c478bd9Sstevel@tonic-gate async_resume_utbrk(struct asyncline *async) 2994*7c478bd9Sstevel@tonic-gate { 2995*7c478bd9Sstevel@tonic-gate uchar_t val; 2996*7c478bd9Sstevel@tonic-gate struct asycom *asy = async->async_common; 2997*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl)); 2998*7c478bd9Sstevel@tonic-gate 2999*7c478bd9Sstevel@tonic-gate /* 3000*7c478bd9Sstevel@tonic-gate * Because the wait time is very short, 3001*7c478bd9Sstevel@tonic-gate * so we use uninterruptably wait. 3002*7c478bd9Sstevel@tonic-gate */ 3003*7c478bd9Sstevel@tonic-gate while (async->async_flags & ASYNC_HOLD_UTBRK) { 3004*7c478bd9Sstevel@tonic-gate cv_wait(&async->async_flags_cv, &asy->asy_excl); 3005*7c478bd9Sstevel@tonic-gate } 3006*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3007*7c478bd9Sstevel@tonic-gate /* 3008*7c478bd9Sstevel@tonic-gate * Timed break and untimed break can exist simultaneously, 3009*7c478bd9Sstevel@tonic-gate * if ASYNC_BREAK is also set at here, we don't 3010*7c478bd9Sstevel@tonic-gate * really clean the HW break. 3011*7c478bd9Sstevel@tonic-gate */ 3012*7c478bd9Sstevel@tonic-gate if (!(async->async_flags & ASYNC_BREAK)) { 3013*7c478bd9Sstevel@tonic-gate val = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + LCR); 3014*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, 3015*7c478bd9Sstevel@tonic-gate (val & ~SETBREAK)); 3016*7c478bd9Sstevel@tonic-gate } 3017*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_OUT_SUSPEND; 3018*7c478bd9Sstevel@tonic-gate cv_broadcast(&async->async_flags_cv); 3019*7c478bd9Sstevel@tonic-gate if (async->async_ocnt > 0) { 3020*7c478bd9Sstevel@tonic-gate async_resume(async); 3021*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3022*7c478bd9Sstevel@tonic-gate } else { 3023*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_BUSY; 3024*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3025*7c478bd9Sstevel@tonic-gate if (async->async_xmitblk != NULL) { 3026*7c478bd9Sstevel@tonic-gate freeb(async->async_xmitblk); 3027*7c478bd9Sstevel@tonic-gate async->async_xmitblk = NULL; 3028*7c478bd9Sstevel@tonic-gate } 3029*7c478bd9Sstevel@tonic-gate async_start(async); 3030*7c478bd9Sstevel@tonic-gate } 3031*7c478bd9Sstevel@tonic-gate } 3032*7c478bd9Sstevel@tonic-gate 3033*7c478bd9Sstevel@tonic-gate /* 3034*7c478bd9Sstevel@tonic-gate * Process an "ioctl" message sent down to us. 3035*7c478bd9Sstevel@tonic-gate * Note that we don't need to get any locks until we are ready to access 3036*7c478bd9Sstevel@tonic-gate * the hardware. Nothing we access until then is going to be altered 3037*7c478bd9Sstevel@tonic-gate * outside of the STREAMS framework, so we should be safe. 3038*7c478bd9Sstevel@tonic-gate */ 3039*7c478bd9Sstevel@tonic-gate int asydelay = 10000; 3040*7c478bd9Sstevel@tonic-gate static void 3041*7c478bd9Sstevel@tonic-gate async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp) 3042*7c478bd9Sstevel@tonic-gate { 3043*7c478bd9Sstevel@tonic-gate struct asycom *asy = async->async_common; 3044*7c478bd9Sstevel@tonic-gate tty_common_t *tp = &async->async_ttycommon; 3045*7c478bd9Sstevel@tonic-gate struct iocblk *iocp; 3046*7c478bd9Sstevel@tonic-gate unsigned datasize; 3047*7c478bd9Sstevel@tonic-gate int error = 0; 3048*7c478bd9Sstevel@tonic-gate uchar_t val; 3049*7c478bd9Sstevel@tonic-gate mblk_t *datamp; 3050*7c478bd9Sstevel@tonic-gate unsigned int index; 3051*7c478bd9Sstevel@tonic-gate 3052*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3053*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 3054*7c478bd9Sstevel@tonic-gate 3055*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_PROCS, "async%d_ioctl\n", instance); 3056*7c478bd9Sstevel@tonic-gate #endif 3057*7c478bd9Sstevel@tonic-gate 3058*7c478bd9Sstevel@tonic-gate if (tp->t_iocpending != NULL) { 3059*7c478bd9Sstevel@tonic-gate /* 3060*7c478bd9Sstevel@tonic-gate * We were holding an "ioctl" response pending the 3061*7c478bd9Sstevel@tonic-gate * availability of an "mblk" to hold data to be passed up; 3062*7c478bd9Sstevel@tonic-gate * another "ioctl" came through, which means that "ioctl" 3063*7c478bd9Sstevel@tonic-gate * must have timed out or been aborted. 3064*7c478bd9Sstevel@tonic-gate */ 3065*7c478bd9Sstevel@tonic-gate freemsg(async->async_ttycommon.t_iocpending); 3066*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_iocpending = NULL; 3067*7c478bd9Sstevel@tonic-gate } 3068*7c478bd9Sstevel@tonic-gate 3069*7c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 3070*7c478bd9Sstevel@tonic-gate 3071*7c478bd9Sstevel@tonic-gate /* 3072*7c478bd9Sstevel@tonic-gate * For TIOCMGET and the PPS ioctls, do NOT call ttycommon_ioctl() 3073*7c478bd9Sstevel@tonic-gate * because this function frees up the message block (mp->b_cont) that 3074*7c478bd9Sstevel@tonic-gate * contains the user location where we pass back the results. 3075*7c478bd9Sstevel@tonic-gate * 3076*7c478bd9Sstevel@tonic-gate * Similarly, CONSOPENPOLLEDIO needs ioc_count, which ttycommon_ioctl 3077*7c478bd9Sstevel@tonic-gate * zaps. We know that ttycommon_ioctl doesn't know any CONS* 3078*7c478bd9Sstevel@tonic-gate * ioctls, so keep the others safe too. 3079*7c478bd9Sstevel@tonic-gate */ 3080*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_IOCTL, "async%d_ioctl: %s\n", 3081*7c478bd9Sstevel@tonic-gate instance, 3082*7c478bd9Sstevel@tonic-gate iocp->ioc_cmd == TIOCMGET ? "TIOCMGET" : 3083*7c478bd9Sstevel@tonic-gate iocp->ioc_cmd == TIOCMSET ? "TIOCMSET" : 3084*7c478bd9Sstevel@tonic-gate iocp->ioc_cmd == TIOCMBIS ? "TIOCMBIS" : 3085*7c478bd9Sstevel@tonic-gate iocp->ioc_cmd == TIOCMBIC ? "TIOCMBIC" : 3086*7c478bd9Sstevel@tonic-gate "other"); 3087*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 3088*7c478bd9Sstevel@tonic-gate case TIOCMGET: 3089*7c478bd9Sstevel@tonic-gate case TIOCGPPS: 3090*7c478bd9Sstevel@tonic-gate case TIOCSPPS: 3091*7c478bd9Sstevel@tonic-gate case TIOCGPPSEV: 3092*7c478bd9Sstevel@tonic-gate case CONSOPENPOLLEDIO: 3093*7c478bd9Sstevel@tonic-gate case CONSCLOSEPOLLEDIO: 3094*7c478bd9Sstevel@tonic-gate case CONSSETABORTENABLE: 3095*7c478bd9Sstevel@tonic-gate case CONSGETABORTENABLE: 3096*7c478bd9Sstevel@tonic-gate error = -1; /* Do Nothing */ 3097*7c478bd9Sstevel@tonic-gate break; 3098*7c478bd9Sstevel@tonic-gate default: 3099*7c478bd9Sstevel@tonic-gate 3100*7c478bd9Sstevel@tonic-gate /* 3101*7c478bd9Sstevel@tonic-gate * The only way in which "ttycommon_ioctl" can fail is if the 3102*7c478bd9Sstevel@tonic-gate * "ioctl" requires a response containing data to be returned 3103*7c478bd9Sstevel@tonic-gate * to the user, and no mblk could be allocated for the data. 3104*7c478bd9Sstevel@tonic-gate * No such "ioctl" alters our state. Thus, we always go ahead 3105*7c478bd9Sstevel@tonic-gate * and do any state-changes the "ioctl" calls for. If we 3106*7c478bd9Sstevel@tonic-gate * couldn't allocate the data, "ttycommon_ioctl" has stashed 3107*7c478bd9Sstevel@tonic-gate * the "ioctl" away safely, so we just call "bufcall" to 3108*7c478bd9Sstevel@tonic-gate * request that we be called back when we stand a better 3109*7c478bd9Sstevel@tonic-gate * chance of allocating the data. 3110*7c478bd9Sstevel@tonic-gate */ 3111*7c478bd9Sstevel@tonic-gate if ((datasize = ttycommon_ioctl(tp, wq, mp, &error)) != 0) { 3112*7c478bd9Sstevel@tonic-gate if (async->async_wbufcid) 3113*7c478bd9Sstevel@tonic-gate unbufcall(async->async_wbufcid); 3114*7c478bd9Sstevel@tonic-gate async->async_wbufcid = bufcall(datasize, BPRI_HI, 3115*7c478bd9Sstevel@tonic-gate (void (*)(void *)) async_reioctl, 3116*7c478bd9Sstevel@tonic-gate (void *)(intptr_t)async->async_common->asy_unit); 3117*7c478bd9Sstevel@tonic-gate return; 3118*7c478bd9Sstevel@tonic-gate } 3119*7c478bd9Sstevel@tonic-gate } 3120*7c478bd9Sstevel@tonic-gate 3121*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3122*7c478bd9Sstevel@tonic-gate 3123*7c478bd9Sstevel@tonic-gate if (error == 0) { 3124*7c478bd9Sstevel@tonic-gate /* 3125*7c478bd9Sstevel@tonic-gate * "ttycommon_ioctl" did most of the work; we just use the 3126*7c478bd9Sstevel@tonic-gate * data it set up. 3127*7c478bd9Sstevel@tonic-gate */ 3128*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 3129*7c478bd9Sstevel@tonic-gate 3130*7c478bd9Sstevel@tonic-gate case TCSETS: 3131*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3132*7c478bd9Sstevel@tonic-gate if (asy_baudok(asy)) 3133*7c478bd9Sstevel@tonic-gate asy_program(asy, ASY_NOINIT); 3134*7c478bd9Sstevel@tonic-gate else 3135*7c478bd9Sstevel@tonic-gate error = EINVAL; 3136*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3137*7c478bd9Sstevel@tonic-gate break; 3138*7c478bd9Sstevel@tonic-gate case TCSETSF: 3139*7c478bd9Sstevel@tonic-gate case TCSETSW: 3140*7c478bd9Sstevel@tonic-gate case TCSETA: 3141*7c478bd9Sstevel@tonic-gate case TCSETAW: 3142*7c478bd9Sstevel@tonic-gate case TCSETAF: 3143*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3144*7c478bd9Sstevel@tonic-gate if (!asy_baudok(asy)) 3145*7c478bd9Sstevel@tonic-gate error = EINVAL; 3146*7c478bd9Sstevel@tonic-gate else { 3147*7c478bd9Sstevel@tonic-gate if (asy_isbusy(asy)) 3148*7c478bd9Sstevel@tonic-gate asy_waiteot(asy); 3149*7c478bd9Sstevel@tonic-gate asy_program(asy, ASY_NOINIT); 3150*7c478bd9Sstevel@tonic-gate } 3151*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3152*7c478bd9Sstevel@tonic-gate break; 3153*7c478bd9Sstevel@tonic-gate } 3154*7c478bd9Sstevel@tonic-gate } else if (error < 0) { 3155*7c478bd9Sstevel@tonic-gate /* 3156*7c478bd9Sstevel@tonic-gate * "ttycommon_ioctl" didn't do anything; we process it here. 3157*7c478bd9Sstevel@tonic-gate */ 3158*7c478bd9Sstevel@tonic-gate error = 0; 3159*7c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 3160*7c478bd9Sstevel@tonic-gate 3161*7c478bd9Sstevel@tonic-gate case TIOCGPPS: 3162*7c478bd9Sstevel@tonic-gate /* 3163*7c478bd9Sstevel@tonic-gate * Get PPS on/off. 3164*7c478bd9Sstevel@tonic-gate */ 3165*7c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) 3166*7c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 3167*7c478bd9Sstevel@tonic-gate 3168*7c478bd9Sstevel@tonic-gate mp->b_cont = allocb(sizeof (int), BPRI_HI); 3169*7c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) { 3170*7c478bd9Sstevel@tonic-gate error = ENOMEM; 3171*7c478bd9Sstevel@tonic-gate break; 3172*7c478bd9Sstevel@tonic-gate } 3173*7c478bd9Sstevel@tonic-gate if (asy->asy_flags & ASY_PPS) 3174*7c478bd9Sstevel@tonic-gate *(int *)mp->b_cont->b_wptr = 1; 3175*7c478bd9Sstevel@tonic-gate else 3176*7c478bd9Sstevel@tonic-gate *(int *)mp->b_cont->b_wptr = 0; 3177*7c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (int); 3178*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 3179*7c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (int); 3180*7c478bd9Sstevel@tonic-gate break; 3181*7c478bd9Sstevel@tonic-gate 3182*7c478bd9Sstevel@tonic-gate case TIOCSPPS: 3183*7c478bd9Sstevel@tonic-gate /* 3184*7c478bd9Sstevel@tonic-gate * Set PPS on/off. 3185*7c478bd9Sstevel@tonic-gate */ 3186*7c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 3187*7c478bd9Sstevel@tonic-gate if (error != 0) 3188*7c478bd9Sstevel@tonic-gate break; 3189*7c478bd9Sstevel@tonic-gate 3190*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3191*7c478bd9Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr) 3192*7c478bd9Sstevel@tonic-gate asy->asy_flags |= ASY_PPS; 3193*7c478bd9Sstevel@tonic-gate else 3194*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~ASY_PPS; 3195*7c478bd9Sstevel@tonic-gate /* Reset edge sense */ 3196*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~ASY_PPS_EDGE; 3197*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3198*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 3199*7c478bd9Sstevel@tonic-gate break; 3200*7c478bd9Sstevel@tonic-gate 3201*7c478bd9Sstevel@tonic-gate case TIOCGPPSEV: 3202*7c478bd9Sstevel@tonic-gate { 3203*7c478bd9Sstevel@tonic-gate /* 3204*7c478bd9Sstevel@tonic-gate * Get PPS event data. 3205*7c478bd9Sstevel@tonic-gate */ 3206*7c478bd9Sstevel@tonic-gate mblk_t *bp; 3207*7c478bd9Sstevel@tonic-gate void *buf; 3208*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 3209*7c478bd9Sstevel@tonic-gate struct ppsclockev32 p32; 3210*7c478bd9Sstevel@tonic-gate #endif 3211*7c478bd9Sstevel@tonic-gate struct ppsclockev ppsclockev; 3212*7c478bd9Sstevel@tonic-gate 3213*7c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) { 3214*7c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 3215*7c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 3216*7c478bd9Sstevel@tonic-gate } 3217*7c478bd9Sstevel@tonic-gate 3218*7c478bd9Sstevel@tonic-gate if ((asy->asy_flags & ASY_PPS) == 0) { 3219*7c478bd9Sstevel@tonic-gate error = ENXIO; 3220*7c478bd9Sstevel@tonic-gate break; 3221*7c478bd9Sstevel@tonic-gate } 3222*7c478bd9Sstevel@tonic-gate 3223*7c478bd9Sstevel@tonic-gate /* Protect from incomplete asy_ppsev */ 3224*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3225*7c478bd9Sstevel@tonic-gate ppsclockev = asy_ppsev; 3226*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3227*7c478bd9Sstevel@tonic-gate 3228*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 3229*7c478bd9Sstevel@tonic-gate if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) { 3230*7c478bd9Sstevel@tonic-gate TIMEVAL_TO_TIMEVAL32(&p32.tv, &ppsclockev.tv); 3231*7c478bd9Sstevel@tonic-gate p32.serial = ppsclockev.serial; 3232*7c478bd9Sstevel@tonic-gate buf = &p32; 3233*7c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ppsclockev32); 3234*7c478bd9Sstevel@tonic-gate } else 3235*7c478bd9Sstevel@tonic-gate #endif 3236*7c478bd9Sstevel@tonic-gate { 3237*7c478bd9Sstevel@tonic-gate buf = &ppsclockev; 3238*7c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ppsclockev); 3239*7c478bd9Sstevel@tonic-gate } 3240*7c478bd9Sstevel@tonic-gate 3241*7c478bd9Sstevel@tonic-gate if ((bp = allocb(iocp->ioc_count, BPRI_HI)) == NULL) { 3242*7c478bd9Sstevel@tonic-gate error = ENOMEM; 3243*7c478bd9Sstevel@tonic-gate break; 3244*7c478bd9Sstevel@tonic-gate } 3245*7c478bd9Sstevel@tonic-gate mp->b_cont = bp; 3246*7c478bd9Sstevel@tonic-gate 3247*7c478bd9Sstevel@tonic-gate bcopy(buf, bp->b_wptr, iocp->ioc_count); 3248*7c478bd9Sstevel@tonic-gate bp->b_wptr += iocp->ioc_count; 3249*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 3250*7c478bd9Sstevel@tonic-gate break; 3251*7c478bd9Sstevel@tonic-gate } 3252*7c478bd9Sstevel@tonic-gate 3253*7c478bd9Sstevel@tonic-gate case TCSBRK: 3254*7c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 3255*7c478bd9Sstevel@tonic-gate if (error != 0) 3256*7c478bd9Sstevel@tonic-gate break; 3257*7c478bd9Sstevel@tonic-gate 3258*7c478bd9Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr == 0) { 3259*7c478bd9Sstevel@tonic-gate 3260*7c478bd9Sstevel@tonic-gate /* 3261*7c478bd9Sstevel@tonic-gate * XXX Arrangements to ensure that a break 3262*7c478bd9Sstevel@tonic-gate * isn't in progress should be sufficient. 3263*7c478bd9Sstevel@tonic-gate * This ugly delay() is the only thing 3264*7c478bd9Sstevel@tonic-gate * that seems to work on the NCR Worldmark. 3265*7c478bd9Sstevel@tonic-gate * It should be replaced. Note that an 3266*7c478bd9Sstevel@tonic-gate * asy_waiteot() also does not work. 3267*7c478bd9Sstevel@tonic-gate */ 3268*7c478bd9Sstevel@tonic-gate if (asydelay) 3269*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(asydelay)); 3270*7c478bd9Sstevel@tonic-gate 3271*7c478bd9Sstevel@tonic-gate while (async->async_flags & ASYNC_BREAK) { 3272*7c478bd9Sstevel@tonic-gate cv_wait(&async->async_flags_cv, 3273*7c478bd9Sstevel@tonic-gate &asy->asy_excl); 3274*7c478bd9Sstevel@tonic-gate } 3275*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3276*7c478bd9Sstevel@tonic-gate /* 3277*7c478bd9Sstevel@tonic-gate * We loop until the TSR is empty and then 3278*7c478bd9Sstevel@tonic-gate * set the break. ASYNC_BREAK has been set 3279*7c478bd9Sstevel@tonic-gate * to ensure that no characters are 3280*7c478bd9Sstevel@tonic-gate * transmitted while the TSR is being 3281*7c478bd9Sstevel@tonic-gate * flushed and SOUT is being used for the 3282*7c478bd9Sstevel@tonic-gate * break signal. 3283*7c478bd9Sstevel@tonic-gate * 3284*7c478bd9Sstevel@tonic-gate * The wait period is equal to 3285*7c478bd9Sstevel@tonic-gate * clock / (baud * 16) * 16 * 2. 3286*7c478bd9Sstevel@tonic-gate */ 3287*7c478bd9Sstevel@tonic-gate index = BAUDINDEX( 3288*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag); 3289*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_BREAK; 3290*7c478bd9Sstevel@tonic-gate while ((ddi_io_get8(asy->asy_iohandle, 3291*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR) & XSRE) == 0) { 3292*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3293*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3294*7c478bd9Sstevel@tonic-gate drv_usecwait( 3295*7c478bd9Sstevel@tonic-gate 32*asyspdtab[index] & 0xfff); 3296*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3297*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3298*7c478bd9Sstevel@tonic-gate } 3299*7c478bd9Sstevel@tonic-gate /* 3300*7c478bd9Sstevel@tonic-gate * Arrange for "async_restart" 3301*7c478bd9Sstevel@tonic-gate * to be called in 1/4 second; 3302*7c478bd9Sstevel@tonic-gate * it will turn the break bit off, and call 3303*7c478bd9Sstevel@tonic-gate * "async_start" to grab the next message. 3304*7c478bd9Sstevel@tonic-gate */ 3305*7c478bd9Sstevel@tonic-gate val = ddi_io_get8(asy->asy_iohandle, 3306*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR); 3307*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 3308*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR, 3309*7c478bd9Sstevel@tonic-gate (val | SETBREAK)); 3310*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3311*7c478bd9Sstevel@tonic-gate (void) timeout(async_restart, (caddr_t)async, 3312*7c478bd9Sstevel@tonic-gate drv_usectohz(1000000)/4); 3313*7c478bd9Sstevel@tonic-gate } else { 3314*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_OUT, 3315*7c478bd9Sstevel@tonic-gate "async%d_ioctl: wait for flush.\n", 3316*7c478bd9Sstevel@tonic-gate instance); 3317*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3318*7c478bd9Sstevel@tonic-gate asy_waiteot(asy); 3319*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3320*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_OUT, 3321*7c478bd9Sstevel@tonic-gate "async%d_ioctl: ldterm satisfied.\n", 3322*7c478bd9Sstevel@tonic-gate instance); 3323*7c478bd9Sstevel@tonic-gate } 3324*7c478bd9Sstevel@tonic-gate break; 3325*7c478bd9Sstevel@tonic-gate 3326*7c478bd9Sstevel@tonic-gate case TIOCSBRK: 3327*7c478bd9Sstevel@tonic-gate if (!(async->async_flags & ASYNC_OUT_SUSPEND)) { 3328*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3329*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_OUT_SUSPEND; 3330*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_HOLD_UTBRK; 3331*7c478bd9Sstevel@tonic-gate index = BAUDINDEX( 3332*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_cflag); 3333*7c478bd9Sstevel@tonic-gate while ((ddi_io_get8(asy->asy_iohandle, 3334*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR) & XSRE) == 0) { 3335*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3336*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3337*7c478bd9Sstevel@tonic-gate drv_usecwait( 3338*7c478bd9Sstevel@tonic-gate 32*asyspdtab[index] & 0xfff); 3339*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3340*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3341*7c478bd9Sstevel@tonic-gate } 3342*7c478bd9Sstevel@tonic-gate val = ddi_io_get8(asy->asy_iohandle, 3343*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR); 3344*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 3345*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LCR, (val | SETBREAK)); 3346*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3347*7c478bd9Sstevel@tonic-gate /* wait for 100ms to hold BREAK */ 3348*7c478bd9Sstevel@tonic-gate async->async_utbrktid = 3349*7c478bd9Sstevel@tonic-gate timeout((void (*)())async_hold_utbrk, 3350*7c478bd9Sstevel@tonic-gate (caddr_t)async, 3351*7c478bd9Sstevel@tonic-gate drv_usectohz(asy_min_utbrk)); 3352*7c478bd9Sstevel@tonic-gate } 3353*7c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 3354*7c478bd9Sstevel@tonic-gate break; 3355*7c478bd9Sstevel@tonic-gate 3356*7c478bd9Sstevel@tonic-gate case TIOCCBRK: 3357*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_OUT_SUSPEND) 3358*7c478bd9Sstevel@tonic-gate async_resume_utbrk(async); 3359*7c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 3360*7c478bd9Sstevel@tonic-gate break; 3361*7c478bd9Sstevel@tonic-gate 3362*7c478bd9Sstevel@tonic-gate case TIOCMSET: 3363*7c478bd9Sstevel@tonic-gate case TIOCMBIS: 3364*7c478bd9Sstevel@tonic-gate case TIOCMBIC: 3365*7c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 3366*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_IOCTL, "async%d_ioctl: " 3367*7c478bd9Sstevel@tonic-gate "non-transparent\n", instance); 3368*7c478bd9Sstevel@tonic-gate 3369*7c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 3370*7c478bd9Sstevel@tonic-gate if (error != 0) 3371*7c478bd9Sstevel@tonic-gate break; 3372*7c478bd9Sstevel@tonic-gate 3373*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3374*7c478bd9Sstevel@tonic-gate (void) asymctl(asy, 3375*7c478bd9Sstevel@tonic-gate dmtoasy(*(int *)mp->b_cont->b_rptr), 3376*7c478bd9Sstevel@tonic-gate iocp->ioc_cmd); 3377*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3378*7c478bd9Sstevel@tonic-gate iocp->ioc_error = 0; 3379*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 3380*7c478bd9Sstevel@tonic-gate } else { 3381*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_IOCTL, "async%d_ioctl: " 3382*7c478bd9Sstevel@tonic-gate "transparent\n", instance); 3383*7c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL); 3384*7c478bd9Sstevel@tonic-gate } 3385*7c478bd9Sstevel@tonic-gate break; 3386*7c478bd9Sstevel@tonic-gate 3387*7c478bd9Sstevel@tonic-gate case TIOCMGET: 3388*7c478bd9Sstevel@tonic-gate datamp = allocb(sizeof (int), BPRI_MED); 3389*7c478bd9Sstevel@tonic-gate if (datamp == NULL) { 3390*7c478bd9Sstevel@tonic-gate error = EAGAIN; 3391*7c478bd9Sstevel@tonic-gate break; 3392*7c478bd9Sstevel@tonic-gate } 3393*7c478bd9Sstevel@tonic-gate 3394*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3395*7c478bd9Sstevel@tonic-gate *(int *)datamp->b_rptr = asymctl(asy, 0, TIOCMGET); 3396*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3397*7c478bd9Sstevel@tonic-gate 3398*7c478bd9Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) { 3399*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_IOCTL, "async%d_ioctl: " 3400*7c478bd9Sstevel@tonic-gate "transparent\n", instance); 3401*7c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, 3402*7c478bd9Sstevel@tonic-gate datamp); 3403*7c478bd9Sstevel@tonic-gate } else { 3404*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_IOCTL, "async%d_ioctl: " 3405*7c478bd9Sstevel@tonic-gate "non-transparent\n", instance); 3406*7c478bd9Sstevel@tonic-gate mioc2ack(mp, datamp, sizeof (int), 0); 3407*7c478bd9Sstevel@tonic-gate } 3408*7c478bd9Sstevel@tonic-gate break; 3409*7c478bd9Sstevel@tonic-gate 3410*7c478bd9Sstevel@tonic-gate case CONSOPENPOLLEDIO: 3411*7c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct cons_polledio *)); 3412*7c478bd9Sstevel@tonic-gate if (error != 0) 3413*7c478bd9Sstevel@tonic-gate break; 3414*7c478bd9Sstevel@tonic-gate 3415*7c478bd9Sstevel@tonic-gate *(struct cons_polledio **)mp->b_cont->b_rptr = 3416*7c478bd9Sstevel@tonic-gate &asy->polledio; 3417*7c478bd9Sstevel@tonic-gate 3418*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 3419*7c478bd9Sstevel@tonic-gate break; 3420*7c478bd9Sstevel@tonic-gate 3421*7c478bd9Sstevel@tonic-gate case CONSCLOSEPOLLEDIO: 3422*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 3423*7c478bd9Sstevel@tonic-gate iocp->ioc_error = 0; 3424*7c478bd9Sstevel@tonic-gate iocp->ioc_rval = 0; 3425*7c478bd9Sstevel@tonic-gate break; 3426*7c478bd9Sstevel@tonic-gate 3427*7c478bd9Sstevel@tonic-gate case CONSSETABORTENABLE: 3428*7c478bd9Sstevel@tonic-gate error = secpolicy_console(iocp->ioc_cr); 3429*7c478bd9Sstevel@tonic-gate if (error != 0) 3430*7c478bd9Sstevel@tonic-gate break; 3431*7c478bd9Sstevel@tonic-gate 3432*7c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) { 3433*7c478bd9Sstevel@tonic-gate error = EINVAL; 3434*7c478bd9Sstevel@tonic-gate break; 3435*7c478bd9Sstevel@tonic-gate } 3436*7c478bd9Sstevel@tonic-gate 3437*7c478bd9Sstevel@tonic-gate if (*(intptr_t *)mp->b_cont->b_rptr) 3438*7c478bd9Sstevel@tonic-gate asy->asy_flags |= ASY_CONSOLE; 3439*7c478bd9Sstevel@tonic-gate else 3440*7c478bd9Sstevel@tonic-gate asy->asy_flags &= ~ASY_CONSOLE; 3441*7c478bd9Sstevel@tonic-gate 3442*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 3443*7c478bd9Sstevel@tonic-gate iocp->ioc_error = 0; 3444*7c478bd9Sstevel@tonic-gate iocp->ioc_rval = 0; 3445*7c478bd9Sstevel@tonic-gate break; 3446*7c478bd9Sstevel@tonic-gate 3447*7c478bd9Sstevel@tonic-gate case CONSGETABORTENABLE: 3448*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 3449*7c478bd9Sstevel@tonic-gate ASSERT(sizeof (boolean_t) <= sizeof (boolean_t *)); 3450*7c478bd9Sstevel@tonic-gate /* 3451*7c478bd9Sstevel@tonic-gate * Store the return value right in the payload 3452*7c478bd9Sstevel@tonic-gate * we were passed. Crude. 3453*7c478bd9Sstevel@tonic-gate */ 3454*7c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (boolean_t), NULL, NULL); 3455*7c478bd9Sstevel@tonic-gate *(boolean_t *)mp->b_cont->b_rptr = 3456*7c478bd9Sstevel@tonic-gate (asy->asy_flags & ASY_CONSOLE) != 0; 3457*7c478bd9Sstevel@tonic-gate break; 3458*7c478bd9Sstevel@tonic-gate 3459*7c478bd9Sstevel@tonic-gate default: 3460*7c478bd9Sstevel@tonic-gate /* 3461*7c478bd9Sstevel@tonic-gate * If we don't understand it, it's an error. NAK it. 3462*7c478bd9Sstevel@tonic-gate */ 3463*7c478bd9Sstevel@tonic-gate error = EINVAL; 3464*7c478bd9Sstevel@tonic-gate break; 3465*7c478bd9Sstevel@tonic-gate } 3466*7c478bd9Sstevel@tonic-gate } 3467*7c478bd9Sstevel@tonic-gate if (error != 0) { 3468*7c478bd9Sstevel@tonic-gate iocp->ioc_error = error; 3469*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 3470*7c478bd9Sstevel@tonic-gate } 3471*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3472*7c478bd9Sstevel@tonic-gate qreply(wq, mp); 3473*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_PROCS, "async%d_ioctl: done\n", instance); 3474*7c478bd9Sstevel@tonic-gate } 3475*7c478bd9Sstevel@tonic-gate 3476*7c478bd9Sstevel@tonic-gate static int 3477*7c478bd9Sstevel@tonic-gate asyrsrv(queue_t *q) 3478*7c478bd9Sstevel@tonic-gate { 3479*7c478bd9Sstevel@tonic-gate mblk_t *bp; 3480*7c478bd9Sstevel@tonic-gate struct asyncline *async; 3481*7c478bd9Sstevel@tonic-gate 3482*7c478bd9Sstevel@tonic-gate async = (struct asyncline *)q->q_ptr; 3483*7c478bd9Sstevel@tonic-gate 3484*7c478bd9Sstevel@tonic-gate while (canputnext(q) && (bp = getq(q))) 3485*7c478bd9Sstevel@tonic-gate putnext(q, bp); 3486*7c478bd9Sstevel@tonic-gate ASYSETSOFT(async->async_common); 3487*7c478bd9Sstevel@tonic-gate async->async_polltid = 0; 3488*7c478bd9Sstevel@tonic-gate return (0); 3489*7c478bd9Sstevel@tonic-gate } 3490*7c478bd9Sstevel@tonic-gate 3491*7c478bd9Sstevel@tonic-gate /* 3492*7c478bd9Sstevel@tonic-gate * Put procedure for write queue. 3493*7c478bd9Sstevel@tonic-gate * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here; 3494*7c478bd9Sstevel@tonic-gate * set the flow control character for M_STOPI and M_STARTI messages; 3495*7c478bd9Sstevel@tonic-gate * queue up M_BREAK, M_DELAY, and M_DATA messages for processing 3496*7c478bd9Sstevel@tonic-gate * by the start routine, and then call the start routine; discard 3497*7c478bd9Sstevel@tonic-gate * everything else. Note that this driver does not incorporate any 3498*7c478bd9Sstevel@tonic-gate * mechanism to negotiate to handle the canonicalization process. 3499*7c478bd9Sstevel@tonic-gate * It expects that these functions are handled in upper module(s), 3500*7c478bd9Sstevel@tonic-gate * as we do in ldterm. 3501*7c478bd9Sstevel@tonic-gate */ 3502*7c478bd9Sstevel@tonic-gate static int 3503*7c478bd9Sstevel@tonic-gate asywput(queue_t *q, mblk_t *mp) 3504*7c478bd9Sstevel@tonic-gate { 3505*7c478bd9Sstevel@tonic-gate struct asyncline *async; 3506*7c478bd9Sstevel@tonic-gate struct asycom *asy; 3507*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3508*7c478bd9Sstevel@tonic-gate int instance; 3509*7c478bd9Sstevel@tonic-gate #endif 3510*7c478bd9Sstevel@tonic-gate int error; 3511*7c478bd9Sstevel@tonic-gate 3512*7c478bd9Sstevel@tonic-gate async = (struct asyncline *)q->q_ptr; 3513*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3514*7c478bd9Sstevel@tonic-gate instance = UNIT(async->async_dev); 3515*7c478bd9Sstevel@tonic-gate #endif 3516*7c478bd9Sstevel@tonic-gate asy = async->async_common; 3517*7c478bd9Sstevel@tonic-gate 3518*7c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 3519*7c478bd9Sstevel@tonic-gate 3520*7c478bd9Sstevel@tonic-gate case M_STOP: 3521*7c478bd9Sstevel@tonic-gate /* 3522*7c478bd9Sstevel@tonic-gate * Since we don't do real DMA, we can just let the 3523*7c478bd9Sstevel@tonic-gate * chip coast to a stop after applying the brakes. 3524*7c478bd9Sstevel@tonic-gate */ 3525*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3526*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_STOPPED; 3527*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3528*7c478bd9Sstevel@tonic-gate freemsg(mp); 3529*7c478bd9Sstevel@tonic-gate break; 3530*7c478bd9Sstevel@tonic-gate 3531*7c478bd9Sstevel@tonic-gate case M_START: 3532*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3533*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_STOPPED) { 3534*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_STOPPED; 3535*7c478bd9Sstevel@tonic-gate /* 3536*7c478bd9Sstevel@tonic-gate * If an output operation is in progress, 3537*7c478bd9Sstevel@tonic-gate * resume it. Otherwise, prod the start 3538*7c478bd9Sstevel@tonic-gate * routine. 3539*7c478bd9Sstevel@tonic-gate */ 3540*7c478bd9Sstevel@tonic-gate if (async->async_ocnt > 0) { 3541*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3542*7c478bd9Sstevel@tonic-gate async_resume(async); 3543*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3544*7c478bd9Sstevel@tonic-gate } else { 3545*7c478bd9Sstevel@tonic-gate async_start(async); 3546*7c478bd9Sstevel@tonic-gate } 3547*7c478bd9Sstevel@tonic-gate } 3548*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3549*7c478bd9Sstevel@tonic-gate freemsg(mp); 3550*7c478bd9Sstevel@tonic-gate break; 3551*7c478bd9Sstevel@tonic-gate 3552*7c478bd9Sstevel@tonic-gate case M_IOCTL: 3553*7c478bd9Sstevel@tonic-gate switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 3554*7c478bd9Sstevel@tonic-gate 3555*7c478bd9Sstevel@tonic-gate case TCSBRK: 3556*7c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 3557*7c478bd9Sstevel@tonic-gate if (error != 0) { 3558*7c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error); 3559*7c478bd9Sstevel@tonic-gate return (0); 3560*7c478bd9Sstevel@tonic-gate } 3561*7c478bd9Sstevel@tonic-gate 3562*7c478bd9Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr != 0) { 3563*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_OUT, 3564*7c478bd9Sstevel@tonic-gate "async%d_ioctl: flush request.\n", 3565*7c478bd9Sstevel@tonic-gate instance); 3566*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 3567*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3568*7c478bd9Sstevel@tonic-gate 3569*7c478bd9Sstevel@tonic-gate /* 3570*7c478bd9Sstevel@tonic-gate * If an TIOCSBRK is in progress, 3571*7c478bd9Sstevel@tonic-gate * clean it as TIOCCBRK does, 3572*7c478bd9Sstevel@tonic-gate * then kick off output. 3573*7c478bd9Sstevel@tonic-gate * If TIOCSBRK is not in progress, 3574*7c478bd9Sstevel@tonic-gate * just kick off output. 3575*7c478bd9Sstevel@tonic-gate */ 3576*7c478bd9Sstevel@tonic-gate async_resume_utbrk(async); 3577*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3578*7c478bd9Sstevel@tonic-gate break; 3579*7c478bd9Sstevel@tonic-gate } 3580*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 3581*7c478bd9Sstevel@tonic-gate case TCSETSW: 3582*7c478bd9Sstevel@tonic-gate case TCSETSF: 3583*7c478bd9Sstevel@tonic-gate case TCSETAW: 3584*7c478bd9Sstevel@tonic-gate case TCSETAF: 3585*7c478bd9Sstevel@tonic-gate /* 3586*7c478bd9Sstevel@tonic-gate * The changes do not take effect until all 3587*7c478bd9Sstevel@tonic-gate * output queued before them is drained. 3588*7c478bd9Sstevel@tonic-gate * Put this message on the queue, so that 3589*7c478bd9Sstevel@tonic-gate * "async_start" will see it when it's done 3590*7c478bd9Sstevel@tonic-gate * with the output before it. Poke the 3591*7c478bd9Sstevel@tonic-gate * start routine, just in case. 3592*7c478bd9Sstevel@tonic-gate */ 3593*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 3594*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3595*7c478bd9Sstevel@tonic-gate 3596*7c478bd9Sstevel@tonic-gate /* 3597*7c478bd9Sstevel@tonic-gate * If an TIOCSBRK is in progress, 3598*7c478bd9Sstevel@tonic-gate * clean it as TIOCCBRK does. 3599*7c478bd9Sstevel@tonic-gate * then kick off output. 3600*7c478bd9Sstevel@tonic-gate * If TIOCSBRK is not in progress, 3601*7c478bd9Sstevel@tonic-gate * just kick off output. 3602*7c478bd9Sstevel@tonic-gate */ 3603*7c478bd9Sstevel@tonic-gate async_resume_utbrk(async); 3604*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3605*7c478bd9Sstevel@tonic-gate break; 3606*7c478bd9Sstevel@tonic-gate 3607*7c478bd9Sstevel@tonic-gate default: 3608*7c478bd9Sstevel@tonic-gate /* 3609*7c478bd9Sstevel@tonic-gate * Do it now. 3610*7c478bd9Sstevel@tonic-gate */ 3611*7c478bd9Sstevel@tonic-gate async_ioctl(async, q, mp); 3612*7c478bd9Sstevel@tonic-gate break; 3613*7c478bd9Sstevel@tonic-gate } 3614*7c478bd9Sstevel@tonic-gate break; 3615*7c478bd9Sstevel@tonic-gate 3616*7c478bd9Sstevel@tonic-gate case M_FLUSH: 3617*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 3618*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3619*7c478bd9Sstevel@tonic-gate 3620*7c478bd9Sstevel@tonic-gate /* 3621*7c478bd9Sstevel@tonic-gate * Abort any output in progress. 3622*7c478bd9Sstevel@tonic-gate */ 3623*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3624*7c478bd9Sstevel@tonic-gate if (async->async_flags & ASYNC_BUSY) { 3625*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_BUSY, "asy%dwput: " 3626*7c478bd9Sstevel@tonic-gate "Clearing async_ocnt, " 3627*7c478bd9Sstevel@tonic-gate "leaving ASYNC_BUSY set\n", 3628*7c478bd9Sstevel@tonic-gate instance); 3629*7c478bd9Sstevel@tonic-gate async->async_ocnt = 0; 3630*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_BUSY; 3631*7c478bd9Sstevel@tonic-gate } /* if */ 3632*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3633*7c478bd9Sstevel@tonic-gate 3634*7c478bd9Sstevel@tonic-gate /* Flush FIFO buffers */ 3635*7c478bd9Sstevel@tonic-gate if (asy->asy_use_fifo == FIFO_ON) { 3636*7c478bd9Sstevel@tonic-gate asy_reset_fifo(asy, FIFOTXFLSH); 3637*7c478bd9Sstevel@tonic-gate } 3638*7c478bd9Sstevel@tonic-gate 3639*7c478bd9Sstevel@tonic-gate /* 3640*7c478bd9Sstevel@tonic-gate * Flush our write queue. 3641*7c478bd9Sstevel@tonic-gate */ 3642*7c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */ 3643*7c478bd9Sstevel@tonic-gate if (async->async_xmitblk != NULL) { 3644*7c478bd9Sstevel@tonic-gate freeb(async->async_xmitblk); 3645*7c478bd9Sstevel@tonic-gate async->async_xmitblk = NULL; 3646*7c478bd9Sstevel@tonic-gate } 3647*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3648*7c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; /* it has been flushed */ 3649*7c478bd9Sstevel@tonic-gate } 3650*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 3651*7c478bd9Sstevel@tonic-gate /* Flush FIFO buffers */ 3652*7c478bd9Sstevel@tonic-gate if (asy->asy_use_fifo == FIFO_ON) { 3653*7c478bd9Sstevel@tonic-gate asy_reset_fifo(asy, FIFORXFLSH); 3654*7c478bd9Sstevel@tonic-gate } 3655*7c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 3656*7c478bd9Sstevel@tonic-gate qreply(q, mp); /* give the read queues a crack at it */ 3657*7c478bd9Sstevel@tonic-gate } else { 3658*7c478bd9Sstevel@tonic-gate freemsg(mp); 3659*7c478bd9Sstevel@tonic-gate } 3660*7c478bd9Sstevel@tonic-gate 3661*7c478bd9Sstevel@tonic-gate /* 3662*7c478bd9Sstevel@tonic-gate * We must make sure we process messages that survive the 3663*7c478bd9Sstevel@tonic-gate * write-side flush. 3664*7c478bd9Sstevel@tonic-gate */ 3665*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3666*7c478bd9Sstevel@tonic-gate async_start(async); 3667*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3668*7c478bd9Sstevel@tonic-gate break; 3669*7c478bd9Sstevel@tonic-gate 3670*7c478bd9Sstevel@tonic-gate case M_BREAK: 3671*7c478bd9Sstevel@tonic-gate case M_DELAY: 3672*7c478bd9Sstevel@tonic-gate case M_DATA: 3673*7c478bd9Sstevel@tonic-gate /* 3674*7c478bd9Sstevel@tonic-gate * Queue the message up to be transmitted, 3675*7c478bd9Sstevel@tonic-gate * and poke the start routine. 3676*7c478bd9Sstevel@tonic-gate */ 3677*7c478bd9Sstevel@tonic-gate (void) putq(q, mp); 3678*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3679*7c478bd9Sstevel@tonic-gate async_start(async); 3680*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3681*7c478bd9Sstevel@tonic-gate break; 3682*7c478bd9Sstevel@tonic-gate 3683*7c478bd9Sstevel@tonic-gate case M_STOPI: 3684*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3685*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3686*7c478bd9Sstevel@tonic-gate if (!(async->async_inflow_source & IN_FLOW_USER)) { 3687*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_input(asy, FLOW_STOP, 3688*7c478bd9Sstevel@tonic-gate IN_FLOW_USER); 3689*7c478bd9Sstevel@tonic-gate (void) async_flowcontrol_sw_input(asy, FLOW_STOP, 3690*7c478bd9Sstevel@tonic-gate IN_FLOW_USER); 3691*7c478bd9Sstevel@tonic-gate } 3692*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3693*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3694*7c478bd9Sstevel@tonic-gate freemsg(mp); 3695*7c478bd9Sstevel@tonic-gate break; 3696*7c478bd9Sstevel@tonic-gate 3697*7c478bd9Sstevel@tonic-gate case M_STARTI: 3698*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3699*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3700*7c478bd9Sstevel@tonic-gate if (async->async_inflow_source & IN_FLOW_USER) { 3701*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_input(asy, FLOW_START, 3702*7c478bd9Sstevel@tonic-gate IN_FLOW_USER); 3703*7c478bd9Sstevel@tonic-gate (void) async_flowcontrol_sw_input(asy, FLOW_START, 3704*7c478bd9Sstevel@tonic-gate IN_FLOW_USER); 3705*7c478bd9Sstevel@tonic-gate } 3706*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3707*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3708*7c478bd9Sstevel@tonic-gate freemsg(mp); 3709*7c478bd9Sstevel@tonic-gate break; 3710*7c478bd9Sstevel@tonic-gate 3711*7c478bd9Sstevel@tonic-gate case M_CTL: 3712*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) >= sizeof (struct iocblk) && 3713*7c478bd9Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) { 3714*7c478bd9Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd = MC_HAS_POSIX; 3715*7c478bd9Sstevel@tonic-gate qreply(q, mp); 3716*7c478bd9Sstevel@tonic-gate } else { 3717*7c478bd9Sstevel@tonic-gate /* 3718*7c478bd9Sstevel@tonic-gate * These MC_SERVICE type messages are used by upper 3719*7c478bd9Sstevel@tonic-gate * modules to tell this driver to send input up 3720*7c478bd9Sstevel@tonic-gate * immediately, or that it can wait for normal 3721*7c478bd9Sstevel@tonic-gate * processing that may or may not be done. Sun 3722*7c478bd9Sstevel@tonic-gate * requires these for the mouse module. 3723*7c478bd9Sstevel@tonic-gate * (XXX - for x86?) 3724*7c478bd9Sstevel@tonic-gate */ 3725*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3726*7c478bd9Sstevel@tonic-gate switch (*mp->b_rptr) { 3727*7c478bd9Sstevel@tonic-gate 3728*7c478bd9Sstevel@tonic-gate case MC_SERVICEIMM: 3729*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_SERVICEIMM; 3730*7c478bd9Sstevel@tonic-gate break; 3731*7c478bd9Sstevel@tonic-gate 3732*7c478bd9Sstevel@tonic-gate case MC_SERVICEDEF: 3733*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_SERVICEIMM; 3734*7c478bd9Sstevel@tonic-gate break; 3735*7c478bd9Sstevel@tonic-gate } 3736*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3737*7c478bd9Sstevel@tonic-gate freemsg(mp); 3738*7c478bd9Sstevel@tonic-gate } 3739*7c478bd9Sstevel@tonic-gate break; 3740*7c478bd9Sstevel@tonic-gate 3741*7c478bd9Sstevel@tonic-gate case M_IOCDATA: 3742*7c478bd9Sstevel@tonic-gate async_iocdata(q, mp); 3743*7c478bd9Sstevel@tonic-gate break; 3744*7c478bd9Sstevel@tonic-gate 3745*7c478bd9Sstevel@tonic-gate default: 3746*7c478bd9Sstevel@tonic-gate freemsg(mp); 3747*7c478bd9Sstevel@tonic-gate break; 3748*7c478bd9Sstevel@tonic-gate } 3749*7c478bd9Sstevel@tonic-gate return (0); 3750*7c478bd9Sstevel@tonic-gate } 3751*7c478bd9Sstevel@tonic-gate 3752*7c478bd9Sstevel@tonic-gate /* 3753*7c478bd9Sstevel@tonic-gate * Retry an "ioctl", now that "bufcall" claims we may be able to allocate 3754*7c478bd9Sstevel@tonic-gate * the buffer we need. 3755*7c478bd9Sstevel@tonic-gate */ 3756*7c478bd9Sstevel@tonic-gate static void 3757*7c478bd9Sstevel@tonic-gate async_reioctl(void *unit) 3758*7c478bd9Sstevel@tonic-gate { 3759*7c478bd9Sstevel@tonic-gate int instance = (uintptr_t)unit; 3760*7c478bd9Sstevel@tonic-gate struct asyncline *async; 3761*7c478bd9Sstevel@tonic-gate struct asycom *asy; 3762*7c478bd9Sstevel@tonic-gate queue_t *q; 3763*7c478bd9Sstevel@tonic-gate mblk_t *mp; 3764*7c478bd9Sstevel@tonic-gate 3765*7c478bd9Sstevel@tonic-gate asy = ddi_get_soft_state(asy_soft_state, instance); 3766*7c478bd9Sstevel@tonic-gate ASSERT(asy != NULL); 3767*7c478bd9Sstevel@tonic-gate async = asy->asy_priv; 3768*7c478bd9Sstevel@tonic-gate 3769*7c478bd9Sstevel@tonic-gate /* 3770*7c478bd9Sstevel@tonic-gate * The bufcall is no longer pending. 3771*7c478bd9Sstevel@tonic-gate */ 3772*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3773*7c478bd9Sstevel@tonic-gate async->async_wbufcid = 0; 3774*7c478bd9Sstevel@tonic-gate if ((q = async->async_ttycommon.t_writeq) == NULL) { 3775*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3776*7c478bd9Sstevel@tonic-gate return; 3777*7c478bd9Sstevel@tonic-gate } 3778*7c478bd9Sstevel@tonic-gate if ((mp = async->async_ttycommon.t_iocpending) != NULL) { 3779*7c478bd9Sstevel@tonic-gate /* not pending any more */ 3780*7c478bd9Sstevel@tonic-gate async->async_ttycommon.t_iocpending = NULL; 3781*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3782*7c478bd9Sstevel@tonic-gate async_ioctl(async, q, mp); 3783*7c478bd9Sstevel@tonic-gate } else 3784*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3785*7c478bd9Sstevel@tonic-gate } 3786*7c478bd9Sstevel@tonic-gate 3787*7c478bd9Sstevel@tonic-gate static void 3788*7c478bd9Sstevel@tonic-gate async_iocdata(queue_t *q, mblk_t *mp) 3789*7c478bd9Sstevel@tonic-gate { 3790*7c478bd9Sstevel@tonic-gate struct asyncline *async = (struct asyncline *)q->q_ptr; 3791*7c478bd9Sstevel@tonic-gate struct asycom *asy; 3792*7c478bd9Sstevel@tonic-gate struct iocblk *ip; 3793*7c478bd9Sstevel@tonic-gate struct copyresp *csp; 3794*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3795*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 3796*7c478bd9Sstevel@tonic-gate #endif 3797*7c478bd9Sstevel@tonic-gate 3798*7c478bd9Sstevel@tonic-gate asy = async->async_common; 3799*7c478bd9Sstevel@tonic-gate ip = (struct iocblk *)mp->b_rptr; 3800*7c478bd9Sstevel@tonic-gate csp = (struct copyresp *)mp->b_rptr; 3801*7c478bd9Sstevel@tonic-gate 3802*7c478bd9Sstevel@tonic-gate if (csp->cp_rval != 0) { 3803*7c478bd9Sstevel@tonic-gate if (csp->cp_private) 3804*7c478bd9Sstevel@tonic-gate freemsg(csp->cp_private); 3805*7c478bd9Sstevel@tonic-gate freemsg(mp); 3806*7c478bd9Sstevel@tonic-gate return; 3807*7c478bd9Sstevel@tonic-gate } 3808*7c478bd9Sstevel@tonic-gate 3809*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl); 3810*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_MODEM, "async%d_iocdata: case %s\n", 3811*7c478bd9Sstevel@tonic-gate instance, 3812*7c478bd9Sstevel@tonic-gate csp->cp_cmd == TIOCMGET ? "TIOCMGET" : 3813*7c478bd9Sstevel@tonic-gate csp->cp_cmd == TIOCMSET ? "TIOCMSET" : 3814*7c478bd9Sstevel@tonic-gate csp->cp_cmd == TIOCMBIS ? "TIOCMBIS" : 3815*7c478bd9Sstevel@tonic-gate "TIOCMBIC"); 3816*7c478bd9Sstevel@tonic-gate switch (csp->cp_cmd) { 3817*7c478bd9Sstevel@tonic-gate 3818*7c478bd9Sstevel@tonic-gate case TIOCMGET: 3819*7c478bd9Sstevel@tonic-gate if (mp->b_cont) { 3820*7c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 3821*7c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 3822*7c478bd9Sstevel@tonic-gate } 3823*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 3824*7c478bd9Sstevel@tonic-gate ip->ioc_error = 0; 3825*7c478bd9Sstevel@tonic-gate ip->ioc_count = 0; 3826*7c478bd9Sstevel@tonic-gate ip->ioc_rval = 0; 3827*7c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 3828*7c478bd9Sstevel@tonic-gate break; 3829*7c478bd9Sstevel@tonic-gate 3830*7c478bd9Sstevel@tonic-gate case TIOCMSET: 3831*7c478bd9Sstevel@tonic-gate case TIOCMBIS: 3832*7c478bd9Sstevel@tonic-gate case TIOCMBIC: 3833*7c478bd9Sstevel@tonic-gate mutex_enter(&asy->asy_excl_hi); 3834*7c478bd9Sstevel@tonic-gate (void) asymctl(asy, 3835*7c478bd9Sstevel@tonic-gate dmtoasy(*(int *)mp->b_cont->b_rptr), 3836*7c478bd9Sstevel@tonic-gate csp->cp_cmd); 3837*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl_hi); 3838*7c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 3839*7c478bd9Sstevel@tonic-gate break; 3840*7c478bd9Sstevel@tonic-gate 3841*7c478bd9Sstevel@tonic-gate default: 3842*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 3843*7c478bd9Sstevel@tonic-gate ip->ioc_error = EINVAL; 3844*7c478bd9Sstevel@tonic-gate break; 3845*7c478bd9Sstevel@tonic-gate } 3846*7c478bd9Sstevel@tonic-gate qreply(q, mp); 3847*7c478bd9Sstevel@tonic-gate mutex_exit(&asy->asy_excl); 3848*7c478bd9Sstevel@tonic-gate } 3849*7c478bd9Sstevel@tonic-gate 3850*7c478bd9Sstevel@tonic-gate /* 3851*7c478bd9Sstevel@tonic-gate * debugger/console support routines. 3852*7c478bd9Sstevel@tonic-gate */ 3853*7c478bd9Sstevel@tonic-gate 3854*7c478bd9Sstevel@tonic-gate /* 3855*7c478bd9Sstevel@tonic-gate * put a character out 3856*7c478bd9Sstevel@tonic-gate * Do not use interrupts. If char is LF, put out CR, LF. 3857*7c478bd9Sstevel@tonic-gate */ 3858*7c478bd9Sstevel@tonic-gate static void 3859*7c478bd9Sstevel@tonic-gate asyputchar(struct cons_polledio_arg *arg, uchar_t c) 3860*7c478bd9Sstevel@tonic-gate { 3861*7c478bd9Sstevel@tonic-gate struct asycom *asy = (struct asycom *)arg; 3862*7c478bd9Sstevel@tonic-gate 3863*7c478bd9Sstevel@tonic-gate if (c == '\n') 3864*7c478bd9Sstevel@tonic-gate asyputchar(arg, '\r'); 3865*7c478bd9Sstevel@tonic-gate 3866*7c478bd9Sstevel@tonic-gate while ((ddi_io_get8(asy->asy_iohandle, 3867*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR) & XHRE) == 0) { 3868*7c478bd9Sstevel@tonic-gate /* wait for xmit to finish */ 3869*7c478bd9Sstevel@tonic-gate drv_usecwait(10); 3870*7c478bd9Sstevel@tonic-gate } 3871*7c478bd9Sstevel@tonic-gate 3872*7c478bd9Sstevel@tonic-gate /* put the character out */ 3873*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + DAT, c); 3874*7c478bd9Sstevel@tonic-gate } 3875*7c478bd9Sstevel@tonic-gate 3876*7c478bd9Sstevel@tonic-gate /* 3877*7c478bd9Sstevel@tonic-gate * See if there's a character available. If no character is 3878*7c478bd9Sstevel@tonic-gate * available, return 0. Run in polled mode, no interrupts. 3879*7c478bd9Sstevel@tonic-gate */ 3880*7c478bd9Sstevel@tonic-gate static boolean_t 3881*7c478bd9Sstevel@tonic-gate asyischar(struct cons_polledio_arg *arg) 3882*7c478bd9Sstevel@tonic-gate { 3883*7c478bd9Sstevel@tonic-gate struct asycom *asy = (struct asycom *)arg; 3884*7c478bd9Sstevel@tonic-gate 3885*7c478bd9Sstevel@tonic-gate return ((ddi_io_get8(asy->asy_iohandle, 3886*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + LSR) & RCA) != 0); 3887*7c478bd9Sstevel@tonic-gate } 3888*7c478bd9Sstevel@tonic-gate 3889*7c478bd9Sstevel@tonic-gate /* 3890*7c478bd9Sstevel@tonic-gate * Get a character. Run in polled mode, no interrupts. 3891*7c478bd9Sstevel@tonic-gate */ 3892*7c478bd9Sstevel@tonic-gate static int 3893*7c478bd9Sstevel@tonic-gate asygetchar(struct cons_polledio_arg *arg) 3894*7c478bd9Sstevel@tonic-gate { 3895*7c478bd9Sstevel@tonic-gate struct asycom *asy = (struct asycom *)arg; 3896*7c478bd9Sstevel@tonic-gate 3897*7c478bd9Sstevel@tonic-gate while (!asyischar(arg)) 3898*7c478bd9Sstevel@tonic-gate drv_usecwait(10); 3899*7c478bd9Sstevel@tonic-gate return (ddi_io_get8(asy->asy_iohandle, 3900*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + DAT)); 3901*7c478bd9Sstevel@tonic-gate } 3902*7c478bd9Sstevel@tonic-gate 3903*7c478bd9Sstevel@tonic-gate /* 3904*7c478bd9Sstevel@tonic-gate * Set or get the modem control status. 3905*7c478bd9Sstevel@tonic-gate */ 3906*7c478bd9Sstevel@tonic-gate static int 3907*7c478bd9Sstevel@tonic-gate asymctl(struct asycom *asy, int bits, int how) 3908*7c478bd9Sstevel@tonic-gate { 3909*7c478bd9Sstevel@tonic-gate int mcr_r, msr_r; 3910*7c478bd9Sstevel@tonic-gate int instance = asy->asy_unit; 3911*7c478bd9Sstevel@tonic-gate 3912*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl_hi)); 3913*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl)); 3914*7c478bd9Sstevel@tonic-gate 3915*7c478bd9Sstevel@tonic-gate /* Read Modem Control Registers */ 3916*7c478bd9Sstevel@tonic-gate mcr_r = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + MCR); 3917*7c478bd9Sstevel@tonic-gate 3918*7c478bd9Sstevel@tonic-gate switch (how) { 3919*7c478bd9Sstevel@tonic-gate 3920*7c478bd9Sstevel@tonic-gate case TIOCMSET: 3921*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_MODEM, 3922*7c478bd9Sstevel@tonic-gate "asy%dmctl: TIOCMSET, bits = %x\n", instance, bits); 3923*7c478bd9Sstevel@tonic-gate mcr_r = bits; /* Set bits */ 3924*7c478bd9Sstevel@tonic-gate break; 3925*7c478bd9Sstevel@tonic-gate 3926*7c478bd9Sstevel@tonic-gate case TIOCMBIS: 3927*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_MODEM, "asy%dmctl: TIOCMBIS, bits = %x\n", 3928*7c478bd9Sstevel@tonic-gate instance, bits); 3929*7c478bd9Sstevel@tonic-gate mcr_r |= bits; /* Mask in bits */ 3930*7c478bd9Sstevel@tonic-gate break; 3931*7c478bd9Sstevel@tonic-gate 3932*7c478bd9Sstevel@tonic-gate case TIOCMBIC: 3933*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_MODEM, "asy%dmctl: TIOCMBIC, bits = %x\n", 3934*7c478bd9Sstevel@tonic-gate instance, bits); 3935*7c478bd9Sstevel@tonic-gate mcr_r &= ~bits; /* Mask out bits */ 3936*7c478bd9Sstevel@tonic-gate break; 3937*7c478bd9Sstevel@tonic-gate 3938*7c478bd9Sstevel@tonic-gate case TIOCMGET: 3939*7c478bd9Sstevel@tonic-gate /* Read Modem Status Registers */ 3940*7c478bd9Sstevel@tonic-gate /* 3941*7c478bd9Sstevel@tonic-gate * If modem interrupts are enabled, we return the 3942*7c478bd9Sstevel@tonic-gate * saved value of msr. We read MSR only in async_msint() 3943*7c478bd9Sstevel@tonic-gate */ 3944*7c478bd9Sstevel@tonic-gate if (ddi_io_get8(asy->asy_iohandle, 3945*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + ICR) & MIEN) { 3946*7c478bd9Sstevel@tonic-gate msr_r = asy->asy_msr; 3947*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_MODEM, 3948*7c478bd9Sstevel@tonic-gate "asy%dmctl: TIOCMGET, read msr_r = %x\n", 3949*7c478bd9Sstevel@tonic-gate instance, msr_r); 3950*7c478bd9Sstevel@tonic-gate } else { 3951*7c478bd9Sstevel@tonic-gate msr_r = ddi_io_get8(asy->asy_iohandle, 3952*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + MSR); 3953*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_MODEM, 3954*7c478bd9Sstevel@tonic-gate "asy%dmctl: TIOCMGET, read MSR = %x\n", 3955*7c478bd9Sstevel@tonic-gate instance, msr_r); 3956*7c478bd9Sstevel@tonic-gate } 3957*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_MODEM, "asy%dtodm: modem_lines = %x\n", 3958*7c478bd9Sstevel@tonic-gate instance, asytodm(mcr_r, msr_r)); 3959*7c478bd9Sstevel@tonic-gate return (asytodm(mcr_r, msr_r)); 3960*7c478bd9Sstevel@tonic-gate } 3961*7c478bd9Sstevel@tonic-gate 3962*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, mcr_r); 3963*7c478bd9Sstevel@tonic-gate 3964*7c478bd9Sstevel@tonic-gate return (mcr_r); 3965*7c478bd9Sstevel@tonic-gate } 3966*7c478bd9Sstevel@tonic-gate 3967*7c478bd9Sstevel@tonic-gate static int 3968*7c478bd9Sstevel@tonic-gate asytodm(int mcr_r, int msr_r) 3969*7c478bd9Sstevel@tonic-gate { 3970*7c478bd9Sstevel@tonic-gate int b = 0; 3971*7c478bd9Sstevel@tonic-gate 3972*7c478bd9Sstevel@tonic-gate /* MCR registers */ 3973*7c478bd9Sstevel@tonic-gate if (mcr_r & RTS) 3974*7c478bd9Sstevel@tonic-gate b |= TIOCM_RTS; 3975*7c478bd9Sstevel@tonic-gate 3976*7c478bd9Sstevel@tonic-gate if (mcr_r & DTR) 3977*7c478bd9Sstevel@tonic-gate b |= TIOCM_DTR; 3978*7c478bd9Sstevel@tonic-gate 3979*7c478bd9Sstevel@tonic-gate /* MSR registers */ 3980*7c478bd9Sstevel@tonic-gate if (msr_r & DCD) 3981*7c478bd9Sstevel@tonic-gate b |= TIOCM_CAR; 3982*7c478bd9Sstevel@tonic-gate 3983*7c478bd9Sstevel@tonic-gate if (msr_r & CTS) 3984*7c478bd9Sstevel@tonic-gate b |= TIOCM_CTS; 3985*7c478bd9Sstevel@tonic-gate 3986*7c478bd9Sstevel@tonic-gate if (msr_r & DSR) 3987*7c478bd9Sstevel@tonic-gate b |= TIOCM_DSR; 3988*7c478bd9Sstevel@tonic-gate 3989*7c478bd9Sstevel@tonic-gate if (msr_r & RI) 3990*7c478bd9Sstevel@tonic-gate b |= TIOCM_RNG; 3991*7c478bd9Sstevel@tonic-gate return (b); 3992*7c478bd9Sstevel@tonic-gate } 3993*7c478bd9Sstevel@tonic-gate 3994*7c478bd9Sstevel@tonic-gate static int 3995*7c478bd9Sstevel@tonic-gate dmtoasy(int bits) 3996*7c478bd9Sstevel@tonic-gate { 3997*7c478bd9Sstevel@tonic-gate int b = 0; 3998*7c478bd9Sstevel@tonic-gate 3999*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_MODEM, "dmtoasy: bits = %x\n", bits); 4000*7c478bd9Sstevel@tonic-gate #ifdef CAN_NOT_SET /* only DTR and RTS can be set */ 4001*7c478bd9Sstevel@tonic-gate if (bits & TIOCM_CAR) 4002*7c478bd9Sstevel@tonic-gate b |= DCD; 4003*7c478bd9Sstevel@tonic-gate if (bits & TIOCM_CTS) 4004*7c478bd9Sstevel@tonic-gate b |= CTS; 4005*7c478bd9Sstevel@tonic-gate if (bits & TIOCM_DSR) 4006*7c478bd9Sstevel@tonic-gate b |= DSR; 4007*7c478bd9Sstevel@tonic-gate if (bits & TIOCM_RNG) 4008*7c478bd9Sstevel@tonic-gate b |= RI; 4009*7c478bd9Sstevel@tonic-gate #endif 4010*7c478bd9Sstevel@tonic-gate 4011*7c478bd9Sstevel@tonic-gate if (bits & TIOCM_RTS) { 4012*7c478bd9Sstevel@tonic-gate DEBUGCONT0(ASY_DEBUG_MODEM, "dmtoasy: set b & RTS\n"); 4013*7c478bd9Sstevel@tonic-gate b |= RTS; 4014*7c478bd9Sstevel@tonic-gate } 4015*7c478bd9Sstevel@tonic-gate if (bits & TIOCM_DTR) { 4016*7c478bd9Sstevel@tonic-gate DEBUGCONT0(ASY_DEBUG_MODEM, "dmtoasy: set b & DTR\n"); 4017*7c478bd9Sstevel@tonic-gate b |= DTR; 4018*7c478bd9Sstevel@tonic-gate } 4019*7c478bd9Sstevel@tonic-gate 4020*7c478bd9Sstevel@tonic-gate return (b); 4021*7c478bd9Sstevel@tonic-gate } 4022*7c478bd9Sstevel@tonic-gate 4023*7c478bd9Sstevel@tonic-gate static void 4024*7c478bd9Sstevel@tonic-gate asyerror(int level, const char *fmt, ...) 4025*7c478bd9Sstevel@tonic-gate { 4026*7c478bd9Sstevel@tonic-gate va_list adx; 4027*7c478bd9Sstevel@tonic-gate static time_t last; 4028*7c478bd9Sstevel@tonic-gate static const char *lastfmt; 4029*7c478bd9Sstevel@tonic-gate time_t now; 4030*7c478bd9Sstevel@tonic-gate 4031*7c478bd9Sstevel@tonic-gate /* 4032*7c478bd9Sstevel@tonic-gate * Don't print the same error message too often. 4033*7c478bd9Sstevel@tonic-gate * Print the message only if we have not printed the 4034*7c478bd9Sstevel@tonic-gate * message within the last second. 4035*7c478bd9Sstevel@tonic-gate * Note: that fmt cannot be a pointer to a string 4036*7c478bd9Sstevel@tonic-gate * stored on the stack. The fmt pointer 4037*7c478bd9Sstevel@tonic-gate * must be in the data segment otherwise lastfmt would point 4038*7c478bd9Sstevel@tonic-gate * to non-sense. 4039*7c478bd9Sstevel@tonic-gate */ 4040*7c478bd9Sstevel@tonic-gate now = gethrestime_sec(); 4041*7c478bd9Sstevel@tonic-gate if (last == now && lastfmt == fmt) 4042*7c478bd9Sstevel@tonic-gate return; 4043*7c478bd9Sstevel@tonic-gate 4044*7c478bd9Sstevel@tonic-gate last = now; 4045*7c478bd9Sstevel@tonic-gate lastfmt = fmt; 4046*7c478bd9Sstevel@tonic-gate 4047*7c478bd9Sstevel@tonic-gate va_start(adx, fmt); 4048*7c478bd9Sstevel@tonic-gate vcmn_err(level, fmt, adx); 4049*7c478bd9Sstevel@tonic-gate va_end(adx); 4050*7c478bd9Sstevel@tonic-gate } 4051*7c478bd9Sstevel@tonic-gate 4052*7c478bd9Sstevel@tonic-gate /* 4053*7c478bd9Sstevel@tonic-gate * asy_parse_mode(dev_info_t *devi, struct asycom *asy) 4054*7c478bd9Sstevel@tonic-gate * The value of this property is in the form of "9600,8,n,1,-" 4055*7c478bd9Sstevel@tonic-gate * 1) speed: 9600, 4800, ... 4056*7c478bd9Sstevel@tonic-gate * 2) data bits 4057*7c478bd9Sstevel@tonic-gate * 3) parity: n(none), e(even), o(odd) 4058*7c478bd9Sstevel@tonic-gate * 4) stop bits 4059*7c478bd9Sstevel@tonic-gate * 5) handshake: -(none), h(hardware: rts/cts), s(software: xon/off) 4060*7c478bd9Sstevel@tonic-gate * 4061*7c478bd9Sstevel@tonic-gate * This parsing came from a SPARCstation eeprom. 4062*7c478bd9Sstevel@tonic-gate */ 4063*7c478bd9Sstevel@tonic-gate static void 4064*7c478bd9Sstevel@tonic-gate asy_parse_mode(dev_info_t *devi, struct asycom *asy) 4065*7c478bd9Sstevel@tonic-gate { 4066*7c478bd9Sstevel@tonic-gate char name[40]; 4067*7c478bd9Sstevel@tonic-gate char val[40]; 4068*7c478bd9Sstevel@tonic-gate int len; 4069*7c478bd9Sstevel@tonic-gate int ret; 4070*7c478bd9Sstevel@tonic-gate char *p; 4071*7c478bd9Sstevel@tonic-gate char *p1; 4072*7c478bd9Sstevel@tonic-gate 4073*7c478bd9Sstevel@tonic-gate ASSERT(asy->asy_com_port != 0); 4074*7c478bd9Sstevel@tonic-gate 4075*7c478bd9Sstevel@tonic-gate /* 4076*7c478bd9Sstevel@tonic-gate * Parse the ttyx-mode property 4077*7c478bd9Sstevel@tonic-gate */ 4078*7c478bd9Sstevel@tonic-gate (void) sprintf(name, "tty%c-mode", asy->asy_com_port + 'a' - 1); 4079*7c478bd9Sstevel@tonic-gate len = sizeof (val); 4080*7c478bd9Sstevel@tonic-gate ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len); 4081*7c478bd9Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) { 4082*7c478bd9Sstevel@tonic-gate (void) sprintf(name, "com%c-mode", asy->asy_com_port + '0'); 4083*7c478bd9Sstevel@tonic-gate len = sizeof (val); 4084*7c478bd9Sstevel@tonic-gate ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len); 4085*7c478bd9Sstevel@tonic-gate } 4086*7c478bd9Sstevel@tonic-gate 4087*7c478bd9Sstevel@tonic-gate /* no property to parse */ 4088*7c478bd9Sstevel@tonic-gate asy->asy_cflag = 0; 4089*7c478bd9Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) 4090*7c478bd9Sstevel@tonic-gate return; 4091*7c478bd9Sstevel@tonic-gate 4092*7c478bd9Sstevel@tonic-gate p = val; 4093*7c478bd9Sstevel@tonic-gate /* ---- baud rate ---- */ 4094*7c478bd9Sstevel@tonic-gate asy->asy_cflag = CREAD|B9600; /* initial default */ 4095*7c478bd9Sstevel@tonic-gate if (p && (p1 = strchr(p, ',')) != 0) { 4096*7c478bd9Sstevel@tonic-gate *p1++ = '\0'; 4097*7c478bd9Sstevel@tonic-gate } else { 4098*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= BITS8; /* add default bits */ 4099*7c478bd9Sstevel@tonic-gate return; 4100*7c478bd9Sstevel@tonic-gate } 4101*7c478bd9Sstevel@tonic-gate 4102*7c478bd9Sstevel@tonic-gate if (strcmp(p, "110") == 0) 4103*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B110; 4104*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "150") == 0) 4105*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B150; 4106*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "300") == 0) 4107*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B300; 4108*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "600") == 0) 4109*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B600; 4110*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "1200") == 0) 4111*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B1200; 4112*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "2400") == 0) 4113*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B2400; 4114*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "4800") == 0) 4115*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B4800; 4116*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "9600") == 0) 4117*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B9600; 4118*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "19200") == 0) 4119*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B19200; 4120*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "38400") == 0) 4121*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B38400; 4122*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "57600") == 0) 4123*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B57600; 4124*7c478bd9Sstevel@tonic-gate else if (strcmp(p, "115200") == 0) 4125*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B115200; 4126*7c478bd9Sstevel@tonic-gate else 4127*7c478bd9Sstevel@tonic-gate asy->asy_bidx = B9600; 4128*7c478bd9Sstevel@tonic-gate 4129*7c478bd9Sstevel@tonic-gate asy->asy_cflag &= ~CBAUD; 4130*7c478bd9Sstevel@tonic-gate if (asy->asy_bidx > CBAUD) { /* > 38400 uses the CBAUDEXT bit */ 4131*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= CBAUDEXT; 4132*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= asy->asy_bidx - CBAUD - 1; 4133*7c478bd9Sstevel@tonic-gate } else { 4134*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= asy->asy_bidx; 4135*7c478bd9Sstevel@tonic-gate } 4136*7c478bd9Sstevel@tonic-gate 4137*7c478bd9Sstevel@tonic-gate ASSERT(asy->asy_bidx == BAUDINDEX(asy->asy_cflag)); 4138*7c478bd9Sstevel@tonic-gate 4139*7c478bd9Sstevel@tonic-gate /* ---- Next item is data bits ---- */ 4140*7c478bd9Sstevel@tonic-gate p = p1; 4141*7c478bd9Sstevel@tonic-gate if (p && (p1 = strchr(p, ',')) != 0) { 4142*7c478bd9Sstevel@tonic-gate *p1++ = '\0'; 4143*7c478bd9Sstevel@tonic-gate } else { 4144*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= BITS8; /* add default bits */ 4145*7c478bd9Sstevel@tonic-gate return; 4146*7c478bd9Sstevel@tonic-gate } 4147*7c478bd9Sstevel@tonic-gate switch (*p) { 4148*7c478bd9Sstevel@tonic-gate default: 4149*7c478bd9Sstevel@tonic-gate case '8': 4150*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= CS8; 4151*7c478bd9Sstevel@tonic-gate asy->asy_lcr = BITS8; 4152*7c478bd9Sstevel@tonic-gate break; 4153*7c478bd9Sstevel@tonic-gate case '7': 4154*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= CS7; 4155*7c478bd9Sstevel@tonic-gate asy->asy_lcr = BITS7; 4156*7c478bd9Sstevel@tonic-gate break; 4157*7c478bd9Sstevel@tonic-gate case '6': 4158*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= CS6; 4159*7c478bd9Sstevel@tonic-gate asy->asy_lcr = BITS6; 4160*7c478bd9Sstevel@tonic-gate break; 4161*7c478bd9Sstevel@tonic-gate case '5': 4162*7c478bd9Sstevel@tonic-gate /* LINTED: CS5 is currently zero (but might change) */ 4163*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= CS5; 4164*7c478bd9Sstevel@tonic-gate asy->asy_lcr = BITS5; 4165*7c478bd9Sstevel@tonic-gate break; 4166*7c478bd9Sstevel@tonic-gate } 4167*7c478bd9Sstevel@tonic-gate 4168*7c478bd9Sstevel@tonic-gate /* ---- Parity info ---- */ 4169*7c478bd9Sstevel@tonic-gate p = p1; 4170*7c478bd9Sstevel@tonic-gate if (p && (p1 = strchr(p, ',')) != 0) { 4171*7c478bd9Sstevel@tonic-gate *p1++ = '\0'; 4172*7c478bd9Sstevel@tonic-gate } else { 4173*7c478bd9Sstevel@tonic-gate return; 4174*7c478bd9Sstevel@tonic-gate } 4175*7c478bd9Sstevel@tonic-gate switch (*p) { 4176*7c478bd9Sstevel@tonic-gate default: 4177*7c478bd9Sstevel@tonic-gate case 'n': 4178*7c478bd9Sstevel@tonic-gate break; 4179*7c478bd9Sstevel@tonic-gate case 'e': 4180*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= PARENB; 4181*7c478bd9Sstevel@tonic-gate asy->asy_lcr |= PEN; break; 4182*7c478bd9Sstevel@tonic-gate case 'o': 4183*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= PARENB|PARODD; 4184*7c478bd9Sstevel@tonic-gate asy->asy_lcr |= PEN|EPS; 4185*7c478bd9Sstevel@tonic-gate break; 4186*7c478bd9Sstevel@tonic-gate } 4187*7c478bd9Sstevel@tonic-gate 4188*7c478bd9Sstevel@tonic-gate /* ---- Find stop bits ---- */ 4189*7c478bd9Sstevel@tonic-gate p = p1; 4190*7c478bd9Sstevel@tonic-gate if (p && (p1 = strchr(p, ',')) != 0) { 4191*7c478bd9Sstevel@tonic-gate *p1++ = '\0'; 4192*7c478bd9Sstevel@tonic-gate } else { 4193*7c478bd9Sstevel@tonic-gate return; 4194*7c478bd9Sstevel@tonic-gate } 4195*7c478bd9Sstevel@tonic-gate if (*p == '2') { 4196*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= CSTOPB; 4197*7c478bd9Sstevel@tonic-gate asy->asy_lcr |= STB; 4198*7c478bd9Sstevel@tonic-gate } 4199*7c478bd9Sstevel@tonic-gate 4200*7c478bd9Sstevel@tonic-gate /* ---- handshake is next ---- */ 4201*7c478bd9Sstevel@tonic-gate p = p1; 4202*7c478bd9Sstevel@tonic-gate if (p) { 4203*7c478bd9Sstevel@tonic-gate if ((p1 = strchr(p, ',')) != 0) 4204*7c478bd9Sstevel@tonic-gate *p1++ = '\0'; 4205*7c478bd9Sstevel@tonic-gate 4206*7c478bd9Sstevel@tonic-gate if (*p == 'h') 4207*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= CRTSCTS; 4208*7c478bd9Sstevel@tonic-gate else if (*p == 's') 4209*7c478bd9Sstevel@tonic-gate asy->asy_cflag |= CRTSXOFF; 4210*7c478bd9Sstevel@tonic-gate } 4211*7c478bd9Sstevel@tonic-gate } 4212*7c478bd9Sstevel@tonic-gate 4213*7c478bd9Sstevel@tonic-gate /* 4214*7c478bd9Sstevel@tonic-gate * Check for abort character sequence 4215*7c478bd9Sstevel@tonic-gate */ 4216*7c478bd9Sstevel@tonic-gate static boolean_t 4217*7c478bd9Sstevel@tonic-gate abort_charseq_recognize(uchar_t ch) 4218*7c478bd9Sstevel@tonic-gate { 4219*7c478bd9Sstevel@tonic-gate static int state = 0; 4220*7c478bd9Sstevel@tonic-gate #define CNTRL(c) ((c)&037) 4221*7c478bd9Sstevel@tonic-gate static char sequence[] = { '\r', '~', CNTRL('b') }; 4222*7c478bd9Sstevel@tonic-gate 4223*7c478bd9Sstevel@tonic-gate if (ch == sequence[state]) { 4224*7c478bd9Sstevel@tonic-gate if (++state >= sizeof (sequence)) { 4225*7c478bd9Sstevel@tonic-gate state = 0; 4226*7c478bd9Sstevel@tonic-gate return (B_TRUE); 4227*7c478bd9Sstevel@tonic-gate } 4228*7c478bd9Sstevel@tonic-gate } else { 4229*7c478bd9Sstevel@tonic-gate state = (ch == sequence[0]) ? 1 : 0; 4230*7c478bd9Sstevel@tonic-gate } 4231*7c478bd9Sstevel@tonic-gate return (B_FALSE); 4232*7c478bd9Sstevel@tonic-gate } 4233*7c478bd9Sstevel@tonic-gate 4234*7c478bd9Sstevel@tonic-gate /* 4235*7c478bd9Sstevel@tonic-gate * Flow control functions 4236*7c478bd9Sstevel@tonic-gate */ 4237*7c478bd9Sstevel@tonic-gate /* 4238*7c478bd9Sstevel@tonic-gate * Software input flow control 4239*7c478bd9Sstevel@tonic-gate * This function can execute software input flow control sucessfully 4240*7c478bd9Sstevel@tonic-gate * at most of situations except that the line is in BREAK status 4241*7c478bd9Sstevel@tonic-gate * (timed and untimed break). 4242*7c478bd9Sstevel@tonic-gate * INPUT VALUE of onoff: 4243*7c478bd9Sstevel@tonic-gate * FLOW_START means to send out a XON char 4244*7c478bd9Sstevel@tonic-gate * and clear SW input flow control flag. 4245*7c478bd9Sstevel@tonic-gate * FLOW_STOP means to send out a XOFF char 4246*7c478bd9Sstevel@tonic-gate * and set SW input flow control flag. 4247*7c478bd9Sstevel@tonic-gate * FLOW_CHECK means to check whether there is pending XON/XOFF 4248*7c478bd9Sstevel@tonic-gate * if it is true, send it out. 4249*7c478bd9Sstevel@tonic-gate * INPUT VALUE of type: 4250*7c478bd9Sstevel@tonic-gate * IN_FLOW_RINGBUFF means flow control is due to RING BUFFER 4251*7c478bd9Sstevel@tonic-gate * IN_FLOW_STREAMS means flow control is due to STREAMS 4252*7c478bd9Sstevel@tonic-gate * IN_FLOW_USER means flow control is due to user's commands 4253*7c478bd9Sstevel@tonic-gate * RETURN VALUE: B_FALSE means no flow control char is sent 4254*7c478bd9Sstevel@tonic-gate * B_TRUE means one flow control char is sent 4255*7c478bd9Sstevel@tonic-gate */ 4256*7c478bd9Sstevel@tonic-gate static boolean_t 4257*7c478bd9Sstevel@tonic-gate async_flowcontrol_sw_input(struct asycom *asy, async_flowc_action onoff, 4258*7c478bd9Sstevel@tonic-gate int type) 4259*7c478bd9Sstevel@tonic-gate { 4260*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 4261*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 4262*7c478bd9Sstevel@tonic-gate int rval = B_FALSE; 4263*7c478bd9Sstevel@tonic-gate 4264*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl_hi)); 4265*7c478bd9Sstevel@tonic-gate 4266*7c478bd9Sstevel@tonic-gate if (!(async->async_ttycommon.t_iflag & IXOFF)) 4267*7c478bd9Sstevel@tonic-gate return (rval); 4268*7c478bd9Sstevel@tonic-gate 4269*7c478bd9Sstevel@tonic-gate /* 4270*7c478bd9Sstevel@tonic-gate * If we get this far, then we know IXOFF is set. 4271*7c478bd9Sstevel@tonic-gate */ 4272*7c478bd9Sstevel@tonic-gate switch (onoff) { 4273*7c478bd9Sstevel@tonic-gate case FLOW_STOP: 4274*7c478bd9Sstevel@tonic-gate async->async_inflow_source |= type; 4275*7c478bd9Sstevel@tonic-gate 4276*7c478bd9Sstevel@tonic-gate /* 4277*7c478bd9Sstevel@tonic-gate * We'll send an XOFF character for each of up to 4278*7c478bd9Sstevel@tonic-gate * three different input flow control attempts to stop input. 4279*7c478bd9Sstevel@tonic-gate * If we already send out one XOFF, but FLOW_STOP comes again, 4280*7c478bd9Sstevel@tonic-gate * it seems that input flow control becomes more serious, 4281*7c478bd9Sstevel@tonic-gate * then send XOFF again. 4282*7c478bd9Sstevel@tonic-gate */ 4283*7c478bd9Sstevel@tonic-gate if (async->async_inflow_source & (IN_FLOW_RINGBUFF | 4284*7c478bd9Sstevel@tonic-gate IN_FLOW_STREAMS | IN_FLOW_USER)) 4285*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_SW_IN_FLOW | 4286*7c478bd9Sstevel@tonic-gate ASYNC_SW_IN_NEEDED; 4287*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_SFLOW, "async%d: input sflow stop, " 4288*7c478bd9Sstevel@tonic-gate "type = %x\n", instance, async->async_inflow_source); 4289*7c478bd9Sstevel@tonic-gate break; 4290*7c478bd9Sstevel@tonic-gate case FLOW_START: 4291*7c478bd9Sstevel@tonic-gate async->async_inflow_source &= ~type; 4292*7c478bd9Sstevel@tonic-gate if (async->async_inflow_source == 0) { 4293*7c478bd9Sstevel@tonic-gate async->async_flags = (async->async_flags & 4294*7c478bd9Sstevel@tonic-gate ~ASYNC_SW_IN_FLOW) | ASYNC_SW_IN_NEEDED; 4295*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_SFLOW, "async%d: " 4296*7c478bd9Sstevel@tonic-gate "input sflow start\n", instance); 4297*7c478bd9Sstevel@tonic-gate } 4298*7c478bd9Sstevel@tonic-gate break; 4299*7c478bd9Sstevel@tonic-gate default: 4300*7c478bd9Sstevel@tonic-gate break; 4301*7c478bd9Sstevel@tonic-gate } 4302*7c478bd9Sstevel@tonic-gate 4303*7c478bd9Sstevel@tonic-gate if (((async->async_flags & (ASYNC_SW_IN_NEEDED | ASYNC_BREAK | 4304*7c478bd9Sstevel@tonic-gate ASYNC_OUT_SUSPEND)) == ASYNC_SW_IN_NEEDED) && 4305*7c478bd9Sstevel@tonic-gate (ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + LSR) & XHRE)) { 4306*7c478bd9Sstevel@tonic-gate /* 4307*7c478bd9Sstevel@tonic-gate * If we get this far, then we know we need to send out 4308*7c478bd9Sstevel@tonic-gate * XON or XOFF char. 4309*7c478bd9Sstevel@tonic-gate */ 4310*7c478bd9Sstevel@tonic-gate async->async_flags = (async->async_flags & 4311*7c478bd9Sstevel@tonic-gate ~ASYNC_SW_IN_NEEDED) | ASYNC_BUSY; 4312*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, asy->asy_ioaddr + DAT, 4313*7c478bd9Sstevel@tonic-gate async->async_flags & ASYNC_SW_IN_FLOW ? 4314*7c478bd9Sstevel@tonic-gate async->async_stopc : async->async_startc); 4315*7c478bd9Sstevel@tonic-gate rval = B_TRUE; 4316*7c478bd9Sstevel@tonic-gate } 4317*7c478bd9Sstevel@tonic-gate return (rval); 4318*7c478bd9Sstevel@tonic-gate } 4319*7c478bd9Sstevel@tonic-gate 4320*7c478bd9Sstevel@tonic-gate /* 4321*7c478bd9Sstevel@tonic-gate * Software output flow control 4322*7c478bd9Sstevel@tonic-gate * This function can be executed sucessfully at any situation. 4323*7c478bd9Sstevel@tonic-gate * It does not handle HW, and just change the SW output flow control flag. 4324*7c478bd9Sstevel@tonic-gate * INPUT VALUE of onoff: 4325*7c478bd9Sstevel@tonic-gate * FLOW_START means to clear SW output flow control flag, 4326*7c478bd9Sstevel@tonic-gate * also combine with HW output flow control status to 4327*7c478bd9Sstevel@tonic-gate * determine if we need to set ASYNC_OUT_FLW_RESUME. 4328*7c478bd9Sstevel@tonic-gate * FLOW_STOP means to set SW output flow control flag, 4329*7c478bd9Sstevel@tonic-gate * also clear ASYNC_OUT_FLW_RESUME. 4330*7c478bd9Sstevel@tonic-gate */ 4331*7c478bd9Sstevel@tonic-gate static void 4332*7c478bd9Sstevel@tonic-gate async_flowcontrol_sw_output(struct asycom *asy, async_flowc_action onoff) 4333*7c478bd9Sstevel@tonic-gate { 4334*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 4335*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 4336*7c478bd9Sstevel@tonic-gate 4337*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl_hi)); 4338*7c478bd9Sstevel@tonic-gate 4339*7c478bd9Sstevel@tonic-gate if (!(async->async_ttycommon.t_iflag & IXON)) 4340*7c478bd9Sstevel@tonic-gate return; 4341*7c478bd9Sstevel@tonic-gate 4342*7c478bd9Sstevel@tonic-gate switch (onoff) { 4343*7c478bd9Sstevel@tonic-gate case FLOW_STOP: 4344*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_SW_OUT_FLW; 4345*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_OUT_FLW_RESUME; 4346*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_SFLOW, "async%d: output sflow stop\n", 4347*7c478bd9Sstevel@tonic-gate instance); 4348*7c478bd9Sstevel@tonic-gate break; 4349*7c478bd9Sstevel@tonic-gate case FLOW_START: 4350*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_SW_OUT_FLW; 4351*7c478bd9Sstevel@tonic-gate if (!(async->async_flags & ASYNC_HW_OUT_FLW)) 4352*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_OUT_FLW_RESUME; 4353*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_SFLOW, "async%d: output sflow start\n", 4354*7c478bd9Sstevel@tonic-gate instance); 4355*7c478bd9Sstevel@tonic-gate break; 4356*7c478bd9Sstevel@tonic-gate default: 4357*7c478bd9Sstevel@tonic-gate break; 4358*7c478bd9Sstevel@tonic-gate } 4359*7c478bd9Sstevel@tonic-gate } 4360*7c478bd9Sstevel@tonic-gate 4361*7c478bd9Sstevel@tonic-gate /* 4362*7c478bd9Sstevel@tonic-gate * Hardware input flow control 4363*7c478bd9Sstevel@tonic-gate * This function can be executed sucessfully at any situation. 4364*7c478bd9Sstevel@tonic-gate * It directly changes RTS depending on input parameter onoff. 4365*7c478bd9Sstevel@tonic-gate * INPUT VALUE of onoff: 4366*7c478bd9Sstevel@tonic-gate * FLOW_START means to clear HW input flow control flag, 4367*7c478bd9Sstevel@tonic-gate * and pull up RTS if it is low. 4368*7c478bd9Sstevel@tonic-gate * FLOW_STOP means to set HW input flow control flag, 4369*7c478bd9Sstevel@tonic-gate * and low RTS if it is high. 4370*7c478bd9Sstevel@tonic-gate * INPUT VALUE of type: 4371*7c478bd9Sstevel@tonic-gate * IN_FLOW_RINGBUFF means flow control is due to RING BUFFER 4372*7c478bd9Sstevel@tonic-gate * IN_FLOW_STREAMS means flow control is due to STREAMS 4373*7c478bd9Sstevel@tonic-gate * IN_FLOW_USER means flow control is due to user's commands 4374*7c478bd9Sstevel@tonic-gate */ 4375*7c478bd9Sstevel@tonic-gate static void 4376*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_input(struct asycom *asy, async_flowc_action onoff, 4377*7c478bd9Sstevel@tonic-gate int type) 4378*7c478bd9Sstevel@tonic-gate { 4379*7c478bd9Sstevel@tonic-gate uchar_t mcr; 4380*7c478bd9Sstevel@tonic-gate uchar_t flag; 4381*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 4382*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 4383*7c478bd9Sstevel@tonic-gate 4384*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl_hi)); 4385*7c478bd9Sstevel@tonic-gate 4386*7c478bd9Sstevel@tonic-gate if (!(async->async_ttycommon.t_cflag & CRTSXOFF)) 4387*7c478bd9Sstevel@tonic-gate return; 4388*7c478bd9Sstevel@tonic-gate 4389*7c478bd9Sstevel@tonic-gate switch (onoff) { 4390*7c478bd9Sstevel@tonic-gate case FLOW_STOP: 4391*7c478bd9Sstevel@tonic-gate async->async_inflow_source |= type; 4392*7c478bd9Sstevel@tonic-gate if (async->async_inflow_source & (IN_FLOW_RINGBUFF | 4393*7c478bd9Sstevel@tonic-gate IN_FLOW_STREAMS | IN_FLOW_USER)) 4394*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_HW_IN_FLOW; 4395*7c478bd9Sstevel@tonic-gate DEBUGCONT2(ASY_DEBUG_HFLOW, "async%d: input hflow stop, " 4396*7c478bd9Sstevel@tonic-gate "type = %x\n", instance, async->async_inflow_source); 4397*7c478bd9Sstevel@tonic-gate break; 4398*7c478bd9Sstevel@tonic-gate case FLOW_START: 4399*7c478bd9Sstevel@tonic-gate async->async_inflow_source &= ~type; 4400*7c478bd9Sstevel@tonic-gate if (async->async_inflow_source == 0) { 4401*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_HW_IN_FLOW; 4402*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_HFLOW, "async%d: " 4403*7c478bd9Sstevel@tonic-gate "input hflow start\n", instance); 4404*7c478bd9Sstevel@tonic-gate } 4405*7c478bd9Sstevel@tonic-gate break; 4406*7c478bd9Sstevel@tonic-gate default: 4407*7c478bd9Sstevel@tonic-gate break; 4408*7c478bd9Sstevel@tonic-gate } 4409*7c478bd9Sstevel@tonic-gate mcr = ddi_io_get8(asy->asy_iohandle, asy->asy_ioaddr + MCR); 4410*7c478bd9Sstevel@tonic-gate flag = (async->async_flags & ASYNC_HW_IN_FLOW) ? 0 : RTS; 4411*7c478bd9Sstevel@tonic-gate 4412*7c478bd9Sstevel@tonic-gate if (((mcr ^ flag) & RTS) != 0) { 4413*7c478bd9Sstevel@tonic-gate ddi_io_put8(asy->asy_iohandle, 4414*7c478bd9Sstevel@tonic-gate asy->asy_ioaddr + MCR, (mcr ^ RTS)); 4415*7c478bd9Sstevel@tonic-gate } 4416*7c478bd9Sstevel@tonic-gate } 4417*7c478bd9Sstevel@tonic-gate 4418*7c478bd9Sstevel@tonic-gate /* 4419*7c478bd9Sstevel@tonic-gate * Hardware output flow control 4420*7c478bd9Sstevel@tonic-gate * This function can execute HW output flow control sucessfully 4421*7c478bd9Sstevel@tonic-gate * at any situation. 4422*7c478bd9Sstevel@tonic-gate * It doesn't really change RTS, and just change 4423*7c478bd9Sstevel@tonic-gate * HW output flow control flag depending on CTS status. 4424*7c478bd9Sstevel@tonic-gate * INPUT VALUE of onoff: 4425*7c478bd9Sstevel@tonic-gate * FLOW_START means to clear HW output flow control flag. 4426*7c478bd9Sstevel@tonic-gate * also combine with SW output flow control status to 4427*7c478bd9Sstevel@tonic-gate * determine if we need to set ASYNC_OUT_FLW_RESUME. 4428*7c478bd9Sstevel@tonic-gate * FLOW_STOP means to set HW output flow control flag. 4429*7c478bd9Sstevel@tonic-gate * also clear ASYNC_OUT_FLW_RESUME. 4430*7c478bd9Sstevel@tonic-gate */ 4431*7c478bd9Sstevel@tonic-gate static void 4432*7c478bd9Sstevel@tonic-gate async_flowcontrol_hw_output(struct asycom *asy, async_flowc_action onoff) 4433*7c478bd9Sstevel@tonic-gate { 4434*7c478bd9Sstevel@tonic-gate struct asyncline *async = asy->asy_priv; 4435*7c478bd9Sstevel@tonic-gate int instance = UNIT(async->async_dev); 4436*7c478bd9Sstevel@tonic-gate 4437*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&asy->asy_excl_hi)); 4438*7c478bd9Sstevel@tonic-gate 4439*7c478bd9Sstevel@tonic-gate if (!(async->async_ttycommon.t_cflag & CRTSCTS)) 4440*7c478bd9Sstevel@tonic-gate return; 4441*7c478bd9Sstevel@tonic-gate 4442*7c478bd9Sstevel@tonic-gate switch (onoff) { 4443*7c478bd9Sstevel@tonic-gate case FLOW_STOP: 4444*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_HW_OUT_FLW; 4445*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_OUT_FLW_RESUME; 4446*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_HFLOW, "async%d: output hflow stop\n", 4447*7c478bd9Sstevel@tonic-gate instance); 4448*7c478bd9Sstevel@tonic-gate break; 4449*7c478bd9Sstevel@tonic-gate case FLOW_START: 4450*7c478bd9Sstevel@tonic-gate async->async_flags &= ~ASYNC_HW_OUT_FLW; 4451*7c478bd9Sstevel@tonic-gate if (!(async->async_flags & ASYNC_SW_OUT_FLW)) 4452*7c478bd9Sstevel@tonic-gate async->async_flags |= ASYNC_OUT_FLW_RESUME; 4453*7c478bd9Sstevel@tonic-gate DEBUGCONT1(ASY_DEBUG_HFLOW, "async%d: output hflow start\n", 4454*7c478bd9Sstevel@tonic-gate instance); 4455*7c478bd9Sstevel@tonic-gate break; 4456*7c478bd9Sstevel@tonic-gate default: 4457*7c478bd9Sstevel@tonic-gate break; 4458*7c478bd9Sstevel@tonic-gate } 4459*7c478bd9Sstevel@tonic-gate } 4460