1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Asynchronous protocol handler for Z8530 chips 31*0Sstevel@tonic-gate * Handles normal UNIX support for terminals & modems 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <sys/types.h> 35*0Sstevel@tonic-gate #include <sys/param.h> 36*0Sstevel@tonic-gate #include <sys/systm.h> 37*0Sstevel@tonic-gate #include <sys/sysmacros.h> 38*0Sstevel@tonic-gate #include <sys/signal.h> 39*0Sstevel@tonic-gate #include <sys/kmem.h> 40*0Sstevel@tonic-gate #include <sys/termios.h> 41*0Sstevel@tonic-gate #include <sys/stropts.h> 42*0Sstevel@tonic-gate #include <sys/stream.h> 43*0Sstevel@tonic-gate #include <sys/strsun.h> 44*0Sstevel@tonic-gate #include <sys/tty.h> 45*0Sstevel@tonic-gate #include <sys/ptyvar.h> 46*0Sstevel@tonic-gate #include <sys/cred.h> 47*0Sstevel@tonic-gate #include <sys/user.h> 48*0Sstevel@tonic-gate #include <sys/proc.h> 49*0Sstevel@tonic-gate #include <sys/file.h> 50*0Sstevel@tonic-gate #include <sys/uio.h> 51*0Sstevel@tonic-gate #include <sys/buf.h> 52*0Sstevel@tonic-gate #include <sys/mkdev.h> 53*0Sstevel@tonic-gate #include <sys/cmn_err.h> 54*0Sstevel@tonic-gate #include <sys/strtty.h> 55*0Sstevel@tonic-gate #include <sys/consdev.h> 56*0Sstevel@tonic-gate #include <sys/zsdev.h> 57*0Sstevel@tonic-gate #include <sys/ser_async.h> 58*0Sstevel@tonic-gate #include <sys/debug.h> 59*0Sstevel@tonic-gate #include <sys/kbio.h> 60*0Sstevel@tonic-gate #include <sys/conf.h> 61*0Sstevel@tonic-gate #include <sys/ddi.h> 62*0Sstevel@tonic-gate #include <sys/sunddi.h> 63*0Sstevel@tonic-gate #include <sys/promif.h> 64*0Sstevel@tonic-gate #include <sys/policy.h> 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate /* 67*0Sstevel@tonic-gate * PPS (Pulse Per Second) support. 68*0Sstevel@tonic-gate */ 69*0Sstevel@tonic-gate extern void ddi_hardpps(struct timeval *, int); 70*0Sstevel@tonic-gate static struct ppsclockev ppsclockev; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate #ifdef PPSCLOCKLED 73*0Sstevel@tonic-gate /* XXX Use these to observe PPS latencies and jitter on a scope */ 74*0Sstevel@tonic-gate #define LED_ON 75*0Sstevel@tonic-gate #define LED_OFF 76*0Sstevel@tonic-gate #else 77*0Sstevel@tonic-gate #define LED_ON 78*0Sstevel@tonic-gate #define LED_OFF 79*0Sstevel@tonic-gate #endif 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate #define ZSA_RCV_SIZE 64 82*0Sstevel@tonic-gate #define ZA_KICK_RCV_COUNT 3 83*0Sstevel@tonic-gate #define ZSA_GRACE_MIN_FLOW_CONTROL 5 84*0Sstevel@tonic-gate #define ZSA_GRACE_MAX_FLOW_CONTROL 20 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate int zsasoftdtr = 0; /* if nonzero, softcarrier raises dtr at attach */ 87*0Sstevel@tonic-gate int zsb134_weird = 0; /* if set, old weird B134 behavior */ 88*0Sstevel@tonic-gate int g_zsticks = 0; /* if set, becomes the global zsticks value */ 89*0Sstevel@tonic-gate int g_nocluster = 0; /* if set, disables clustering of received data */ 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate unsigned int zsa_rstandby = ZSA_MIN_RSTANDBY; 92*0Sstevel@tonic-gate unsigned int zsa_rdone = ZSA_RDONE_MIN; 93*0Sstevel@tonic-gate unsigned int zsa_grace_flow_control = ZSA_GRACE_MIN_FLOW_CONTROL; 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate #define NSPEED 18 /* max # of speeds */ 97*0Sstevel@tonic-gate ushort_t zs_speeds[NSPEED] = { 98*0Sstevel@tonic-gate 0, 99*0Sstevel@tonic-gate ZSPEED(50), /* 1 */ 100*0Sstevel@tonic-gate ZSPEED(75), /* 2 */ 101*0Sstevel@tonic-gate ZSPEED(110), /* 3 */ 102*0Sstevel@tonic-gate #ifdef lint 103*0Sstevel@tonic-gate ZSPEED(134), /* 4 */ 104*0Sstevel@tonic-gate #else 105*0Sstevel@tonic-gate ZSPEED(269/2), /* XXX - This is sleazy */ 106*0Sstevel@tonic-gate #endif 107*0Sstevel@tonic-gate ZSPEED(150), /* 5 */ 108*0Sstevel@tonic-gate ZSPEED(200), /* 6 */ 109*0Sstevel@tonic-gate ZSPEED(300), /* 7 */ 110*0Sstevel@tonic-gate ZSPEED(600), /* 8 */ 111*0Sstevel@tonic-gate ZSPEED(1200), /* 9 */ 112*0Sstevel@tonic-gate ZSPEED(1800), /* 10 */ 113*0Sstevel@tonic-gate ZSPEED(2400), /* 11 */ 114*0Sstevel@tonic-gate ZSPEED(4800), /* 12 */ 115*0Sstevel@tonic-gate ZSPEED(9600), /* 13 */ 116*0Sstevel@tonic-gate ZSPEED(19200), /* 14 */ 117*0Sstevel@tonic-gate ZSPEED(38400), /* 15 */ 118*0Sstevel@tonic-gate ZSPEED(57680), /* 16 */ 119*0Sstevel@tonic-gate ZSPEED(76800) /* 17 */ 120*0Sstevel@tonic-gate }; 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate ushort_t zsticks[NSPEED] = { 123*0Sstevel@tonic-gate 3, /* 0 */ 124*0Sstevel@tonic-gate 3, /* 1 */ 125*0Sstevel@tonic-gate 3, /* 2 */ 126*0Sstevel@tonic-gate 3, /* 3 */ 127*0Sstevel@tonic-gate 3, /* 4 */ 128*0Sstevel@tonic-gate 3, /* 5 */ 129*0Sstevel@tonic-gate 3, /* 6 */ 130*0Sstevel@tonic-gate 3, /* 7 */ 131*0Sstevel@tonic-gate 3, /* 8 */ 132*0Sstevel@tonic-gate 3, /* 9 */ 133*0Sstevel@tonic-gate 3, /* 10 */ 134*0Sstevel@tonic-gate 3, /* 11 */ 135*0Sstevel@tonic-gate 3, /* 12 */ 136*0Sstevel@tonic-gate 3, /* 13 */ 137*0Sstevel@tonic-gate 2, /* 14 */ 138*0Sstevel@tonic-gate 1, /* 15 */ 139*0Sstevel@tonic-gate 1, /* 16 */ 140*0Sstevel@tonic-gate 1 /* 17 */ 141*0Sstevel@tonic-gate }; 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate #define ztdelay(nsp) (zsdelay[(nsp)]*(hz/100)) 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate ushort_t zsdelay[NSPEED] = { 146*0Sstevel@tonic-gate 0, 147*0Sstevel@tonic-gate ZDELAY(50), /* 1 */ 148*0Sstevel@tonic-gate ZDELAY(75), /* 2 */ 149*0Sstevel@tonic-gate ZDELAY(110), /* 3 */ 150*0Sstevel@tonic-gate #ifdef lint 151*0Sstevel@tonic-gate ZDELAY(134), /* 4 */ 152*0Sstevel@tonic-gate #else 153*0Sstevel@tonic-gate ZDELAY(269/2), 154*0Sstevel@tonic-gate #endif 155*0Sstevel@tonic-gate ZDELAY(150), /* 5 */ 156*0Sstevel@tonic-gate ZDELAY(200), /* 6 */ 157*0Sstevel@tonic-gate ZDELAY(300), /* 7 */ 158*0Sstevel@tonic-gate ZDELAY(600), /* 8 */ 159*0Sstevel@tonic-gate ZDELAY(1200), /* 9 */ 160*0Sstevel@tonic-gate ZDELAY(1800), /* 10 */ 161*0Sstevel@tonic-gate ZDELAY(2400), /* 11 */ 162*0Sstevel@tonic-gate ZDELAY(4800), /* 12 */ 163*0Sstevel@tonic-gate ZDELAY(9600), /* 13 */ 164*0Sstevel@tonic-gate ZDELAY(19200), /* 14 */ 165*0Sstevel@tonic-gate ZDELAY(38400), /* 15 */ 166*0Sstevel@tonic-gate ZDELAY(57600), /* 16 */ 167*0Sstevel@tonic-gate ZDELAY(76800) /* 17 */ 168*0Sstevel@tonic-gate }; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate ushort_t zslowat[NSPEED] = { 171*0Sstevel@tonic-gate 3, /* 0 */ 172*0Sstevel@tonic-gate 3, /* 1 */ 173*0Sstevel@tonic-gate 3, /* 2 */ 174*0Sstevel@tonic-gate 3, /* 3 */ 175*0Sstevel@tonic-gate 3, /* 4 */ 176*0Sstevel@tonic-gate 3, /* 5 */ 177*0Sstevel@tonic-gate 3, /* 6 */ 178*0Sstevel@tonic-gate 2, /* 7 */ 179*0Sstevel@tonic-gate 2, /* 8 */ 180*0Sstevel@tonic-gate 2, /* 9 */ 181*0Sstevel@tonic-gate 2, /* 10 */ 182*0Sstevel@tonic-gate 1, /* 11 */ 183*0Sstevel@tonic-gate 1, /* 12 */ 184*0Sstevel@tonic-gate 1, /* 13 */ 185*0Sstevel@tonic-gate 1, /* 14 */ 186*0Sstevel@tonic-gate 1, /* 15 */ 187*0Sstevel@tonic-gate 1, /* 16 */ 188*0Sstevel@tonic-gate 1 /* 17 */ 189*0Sstevel@tonic-gate }; 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate ushort_t zshiwat[NSPEED] = { 192*0Sstevel@tonic-gate 0, /* 0 */ 193*0Sstevel@tonic-gate 1, /* 1 */ 194*0Sstevel@tonic-gate 1, /* 2 */ 195*0Sstevel@tonic-gate 1, /* 3 */ 196*0Sstevel@tonic-gate 1, /* 4 */ 197*0Sstevel@tonic-gate 1, /* 5 */ 198*0Sstevel@tonic-gate 1, /* 6 */ 199*0Sstevel@tonic-gate 1, /* 7 */ 200*0Sstevel@tonic-gate 1, /* 8 */ 201*0Sstevel@tonic-gate 1, /* 9 */ 202*0Sstevel@tonic-gate 1, /* 10 */ 203*0Sstevel@tonic-gate 1, /* 11 */ 204*0Sstevel@tonic-gate 1, /* 12 */ 205*0Sstevel@tonic-gate 3, /* 13 */ 206*0Sstevel@tonic-gate 3, /* 14 */ 207*0Sstevel@tonic-gate 4, /* 15 */ 208*0Sstevel@tonic-gate 4, /* 16 */ 209*0Sstevel@tonic-gate 4 /* 17 */ 210*0Sstevel@tonic-gate }; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate #define SLAVIO_BUG /* this workaround required to fix bug 1102778 */ 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate #define SPEED(cflag) \ 215*0Sstevel@tonic-gate ((cflag) & CBAUDEXT) ? \ 216*0Sstevel@tonic-gate (((cflag) & 0x1) + CBAUD + 1) : ((cflag) & CBAUD) 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate /* 219*0Sstevel@tonic-gate * Special macros to handle STREAMS operations. 220*0Sstevel@tonic-gate * These are required to address memory leakage problems. 221*0Sstevel@tonic-gate * WARNING : the macro do NOT call ZSSETSOFT 222*0Sstevel@tonic-gate */ 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex. 226*0Sstevel@tonic-gate */ 227*0Sstevel@tonic-gate #define ZSA_GETBLOCK(zs, allocbcount) \ 228*0Sstevel@tonic-gate { \ 229*0Sstevel@tonic-gate register int n = zsa_rstandby; \ 230*0Sstevel@tonic-gate while (--n >= 0 && allocbcount > 0) { \ 231*0Sstevel@tonic-gate if (!za->za_rstandby[n]) { \ 232*0Sstevel@tonic-gate if ((za->za_rstandby[n] = allocb(ZSA_RCV_SIZE, \ 233*0Sstevel@tonic-gate BPRI_MED)) == NULL) { \ 234*0Sstevel@tonic-gate if (za->za_bufcid == 0) { \ 235*0Sstevel@tonic-gate za->za_bufcid = bufcall(ZSA_RCV_SIZE, \ 236*0Sstevel@tonic-gate BPRI_MED, \ 237*0Sstevel@tonic-gate zsa_callback, zs); \ 238*0Sstevel@tonic-gate break; \ 239*0Sstevel@tonic-gate } \ 240*0Sstevel@tonic-gate } \ 241*0Sstevel@tonic-gate allocbcount--; \ 242*0Sstevel@tonic-gate } \ 243*0Sstevel@tonic-gate } \ 244*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { \ 245*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); \ 246*0Sstevel@tonic-gate if (!(zs->zs_wreg[5] & ZSWR5_RTS)) { \ 247*0Sstevel@tonic-gate register int usedcnt = 0; \ 248*0Sstevel@tonic-gate for (n = 0; n < zsa_rstandby; n++) \ 249*0Sstevel@tonic-gate if (!za->za_rstandby[n]) \ 250*0Sstevel@tonic-gate usedcnt++; \ 251*0Sstevel@tonic-gate if ((ushort_t)usedcnt <= \ 252*0Sstevel@tonic-gate zslowat[SPEED(za->za_ttycommon.t_cflag)]) \ 253*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_RTS); \ 254*0Sstevel@tonic-gate } \ 255*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \ 256*0Sstevel@tonic-gate } \ 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate /* 260*0Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex. 261*0Sstevel@tonic-gate */ 262*0Sstevel@tonic-gate #define ZSA_ALLOCB(mp) \ 263*0Sstevel@tonic-gate { \ 264*0Sstevel@tonic-gate register int n = zsa_rstandby; \ 265*0Sstevel@tonic-gate while (--n >= 0) { \ 266*0Sstevel@tonic-gate if ((mp = za->za_rstandby[n]) != NULL) { \ 267*0Sstevel@tonic-gate za->za_rstandby[n] = NULL; \ 268*0Sstevel@tonic-gate break; \ 269*0Sstevel@tonic-gate } \ 270*0Sstevel@tonic-gate } \ 271*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { \ 272*0Sstevel@tonic-gate if (!mp) { \ 273*0Sstevel@tonic-gate if (zs->zs_wreg[5] & ZSWR5_RTS) \ 274*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS); \ 275*0Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d: message lost\n", \ 276*0Sstevel@tonic-gate UNIT(za->za_dev)); \ 277*0Sstevel@tonic-gate } else if (zs->zs_wreg[5] & ZSWR5_RTS) { \ 278*0Sstevel@tonic-gate register int usedcnt = 0; \ 279*0Sstevel@tonic-gate for (n = 0; n < zsa_rstandby; n++) \ 280*0Sstevel@tonic-gate if (!za->za_rstandby[n]) \ 281*0Sstevel@tonic-gate usedcnt++; \ 282*0Sstevel@tonic-gate if ((ushort_t)usedcnt >= (zsa_rstandby - \ 283*0Sstevel@tonic-gate zshiwat[SPEED(za->za_ttycommon.t_cflag)])) \ 284*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS); \ 285*0Sstevel@tonic-gate } \ 286*0Sstevel@tonic-gate } \ 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate /* 290*0Sstevel@tonic-gate * Should get the spin (zs_excl_hi) mutex. 291*0Sstevel@tonic-gate */ 292*0Sstevel@tonic-gate #define ZSA_QREPLY(q, mp) \ 293*0Sstevel@tonic-gate { \ 294*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); \ 295*0Sstevel@tonic-gate ZSA_PUTQ(mp); \ 296*0Sstevel@tonic-gate ZSSETSOFT(zs); \ 297*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \ 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex. 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate #define ZSA_PUTQ(mp) \ 304*0Sstevel@tonic-gate { \ 305*0Sstevel@tonic-gate register int wptr, rptr; \ 306*0Sstevel@tonic-gate wptr = za->za_rdone_wptr; \ 307*0Sstevel@tonic-gate rptr = za->za_rdone_rptr; \ 308*0Sstevel@tonic-gate za->za_rdone[wptr] = mp; \ 309*0Sstevel@tonic-gate if ((wptr)+1 == zsa_rdone) { \ 310*0Sstevel@tonic-gate za->za_rdone_wptr = wptr = 0; \ 311*0Sstevel@tonic-gate } else \ 312*0Sstevel@tonic-gate za->za_rdone_wptr = ++wptr; \ 313*0Sstevel@tonic-gate if (wptr == rptr) { \ 314*0Sstevel@tonic-gate SCC_BIC(1, ZSWR1_INIT); \ 315*0Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d disabled: input buffer overflow", \ 316*0Sstevel@tonic-gate UNIT(za->za_dev)); \ 317*0Sstevel@tonic-gate } \ 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate /* 321*0Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex. 322*0Sstevel@tonic-gate */ 323*0Sstevel@tonic-gate #define ZSA_KICK_RCV \ 324*0Sstevel@tonic-gate { \ 325*0Sstevel@tonic-gate register mblk_t *mp = za->za_rcvblk; \ 326*0Sstevel@tonic-gate if (mp) { \ 327*0Sstevel@tonic-gate if (zs->zs_rd_cur) { /* M_DATA */ \ 328*0Sstevel@tonic-gate mp->b_wptr = zs->zs_rd_cur; \ 329*0Sstevel@tonic-gate zs->zs_rd_cur = NULL; \ 330*0Sstevel@tonic-gate zs->zs_rd_lim = NULL; \ 331*0Sstevel@tonic-gate } \ 332*0Sstevel@tonic-gate za->za_rcvblk = NULL; \ 333*0Sstevel@tonic-gate ZSA_PUTQ(mp); \ 334*0Sstevel@tonic-gate ZSSETSOFT(zs); \ 335*0Sstevel@tonic-gate } \ 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate #define ZSA_SEEQ(mp) \ 339*0Sstevel@tonic-gate { \ 340*0Sstevel@tonic-gate if (za->za_rdone_rptr != za->za_rdone_wptr) { \ 341*0Sstevel@tonic-gate mp = za->za_rdone[za->za_rdone_rptr]; \ 342*0Sstevel@tonic-gate } else { \ 343*0Sstevel@tonic-gate mp = NULL; \ 344*0Sstevel@tonic-gate } \ 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate /* 349*0Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex. 350*0Sstevel@tonic-gate */ 351*0Sstevel@tonic-gate #define ZSA_GETQ(mp) \ 352*0Sstevel@tonic-gate { \ 353*0Sstevel@tonic-gate if (za->za_rdone_rptr != za->za_rdone_wptr) { \ 354*0Sstevel@tonic-gate mp = za->za_rdone[za->za_rdone_rptr]; \ 355*0Sstevel@tonic-gate za->za_rdone[za->za_rdone_rptr++] = NULL; \ 356*0Sstevel@tonic-gate if (za->za_rdone_rptr == zsa_rdone) \ 357*0Sstevel@tonic-gate za->za_rdone_rptr = 0; \ 358*0Sstevel@tonic-gate } else { \ 359*0Sstevel@tonic-gate mp = NULL; \ 360*0Sstevel@tonic-gate } \ 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate /* 364*0Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex. 365*0Sstevel@tonic-gate */ 366*0Sstevel@tonic-gate #define ZSA_FLUSHQ \ 367*0Sstevel@tonic-gate { \ 368*0Sstevel@tonic-gate register mblk_t *tmp; \ 369*0Sstevel@tonic-gate for (;;) { \ 370*0Sstevel@tonic-gate ZSA_GETQ(tmp); \ 371*0Sstevel@tonic-gate if (!(tmp)) \ 372*0Sstevel@tonic-gate break; \ 373*0Sstevel@tonic-gate freemsg(tmp); \ 374*0Sstevel@tonic-gate } \ 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate /* 379*0Sstevel@tonic-gate * Logging definitions 380*0Sstevel@tonic-gate */ 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate #ifdef ZSA_DEBUG 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate #ifdef ZS_DEBUG_ALL 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate extern char zs_h_log[]; 387*0Sstevel@tonic-gate extern int zs_h_log_n; 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate #define zsa_h_log_clear 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate #define zsa_h_log_add(c) \ 392*0Sstevel@tonic-gate { \ 393*0Sstevel@tonic-gate if (zs_h_log_n >= ZS_H_LOG_MAX) \ 394*0Sstevel@tonic-gate zs_h_log_n = 0; \ 395*0Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = 'A' + zs->zs_unit; \ 396*0Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = c; \ 397*0Sstevel@tonic-gate zs_h_log[zs_h_log_n] = '\0'; \ 398*0Sstevel@tonic-gate } 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate #else /* ZS_DEBUG_ALL */ 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate #define ZSA_H_LOG_MAX 0x4000 403*0Sstevel@tonic-gate char zsa_h_log[40][ZSA_H_LOG_MAX +10]; 404*0Sstevel@tonic-gate int zsa_h_log_n[40]; 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate #define zsa_h_log_add(c) \ 407*0Sstevel@tonic-gate { \ 408*0Sstevel@tonic-gate if (zsa_h_log_n[zs->zs_unit] >= ZSA_H_LOG_MAX) \ 409*0Sstevel@tonic-gate zsa_h_log_n[zs->zs_unit] = 0; \ 410*0Sstevel@tonic-gate zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]++] = c; \ 411*0Sstevel@tonic-gate zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]] = '\0'; \ 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate #define zsa_h_log_clear \ 415*0Sstevel@tonic-gate { \ 416*0Sstevel@tonic-gate register char *p; \ 417*0Sstevel@tonic-gate for (p = &zsa_h_log[zs->zs_unit][ZSA_H_LOG_MAX]; \ 418*0Sstevel@tonic-gate p >= &zsa_h_log[zs->zs_unit][0]; /* null */) \ 419*0Sstevel@tonic-gate *p-- = '\0'; \ 420*0Sstevel@tonic-gate zsa_h_log_n[zs->zs_unit] = 0; \ 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate #endif /* ZS_DEBUG_ALL */ 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate #define ZSA_R0_LOG(r0) \ 426*0Sstevel@tonic-gate { \ 427*0Sstevel@tonic-gate if (r0 & ZSRR0_RX_READY) zsa_h_log_add('R'); \ 428*0Sstevel@tonic-gate if (r0 & ZSRR0_TIMER) zsa_h_log_add('Z'); \ 429*0Sstevel@tonic-gate if (r0 & ZSRR0_TX_READY) zsa_h_log_add('T'); \ 430*0Sstevel@tonic-gate if (r0 & ZSRR0_CD) zsa_h_log_add('D'); \ 431*0Sstevel@tonic-gate if (r0 & ZSRR0_SYNC) zsa_h_log_add('S'); \ 432*0Sstevel@tonic-gate if (r0 & ZSRR0_CTS) zsa_h_log_add('C'); \ 433*0Sstevel@tonic-gate if (r0 & ZSRR0_TXUNDER) zsa_h_log_add('U'); \ 434*0Sstevel@tonic-gate if (r0 & ZSRR0_BREAK) zsa_h_log_add('B'); \ 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate #else /* ZSA_DEBUG */ 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate #define zsa_h_log_clear 440*0Sstevel@tonic-gate #define zsa_h_log_add(c) 441*0Sstevel@tonic-gate #define ZSA_R0_LOG(r0) 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate #endif /* ZSA_DEBUG */ 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate static int zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 448*0Sstevel@tonic-gate static int zsa_close(queue_t *q, int flag); 449*0Sstevel@tonic-gate static void zsa_wput(queue_t *q, mblk_t *mp); 450*0Sstevel@tonic-gate static void zsa_rsrv(queue_t *q); 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate static struct module_info asyncm_info = { 453*0Sstevel@tonic-gate 0, 454*0Sstevel@tonic-gate "zs", 455*0Sstevel@tonic-gate 0, 456*0Sstevel@tonic-gate INFPSZ, 457*0Sstevel@tonic-gate 2048, 458*0Sstevel@tonic-gate 128 459*0Sstevel@tonic-gate }; 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate static struct qinit async_rinit = { 462*0Sstevel@tonic-gate putq, 463*0Sstevel@tonic-gate (int (*)())zsa_rsrv, 464*0Sstevel@tonic-gate zsa_open, 465*0Sstevel@tonic-gate zsa_close, 466*0Sstevel@tonic-gate NULL, 467*0Sstevel@tonic-gate &asyncm_info, 468*0Sstevel@tonic-gate NULL 469*0Sstevel@tonic-gate }; 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate static struct qinit async_winit = { 472*0Sstevel@tonic-gate (int (*)())zsa_wput, 473*0Sstevel@tonic-gate NULL, 474*0Sstevel@tonic-gate NULL, 475*0Sstevel@tonic-gate NULL, 476*0Sstevel@tonic-gate NULL, 477*0Sstevel@tonic-gate &asyncm_info, 478*0Sstevel@tonic-gate NULL 479*0Sstevel@tonic-gate }; 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate struct streamtab asynctab = { 482*0Sstevel@tonic-gate &async_rinit, 483*0Sstevel@tonic-gate &async_winit, 484*0Sstevel@tonic-gate NULL, 485*0Sstevel@tonic-gate NULL, 486*0Sstevel@tonic-gate }; 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate /* 489*0Sstevel@tonic-gate * The async interrupt entry points. 490*0Sstevel@tonic-gate */ 491*0Sstevel@tonic-gate static void zsa_txint(struct zscom *zs); 492*0Sstevel@tonic-gate static void zsa_xsint(struct zscom *zs); 493*0Sstevel@tonic-gate static void zsa_rxint(struct zscom *zs); 494*0Sstevel@tonic-gate static void zsa_srint(struct zscom *zs); 495*0Sstevel@tonic-gate static int zsa_softint(struct zscom *zs); 496*0Sstevel@tonic-gate static int zsa_suspend(struct zscom *zs); 497*0Sstevel@tonic-gate static int zsa_resume(struct zscom *zs); 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate static void 500*0Sstevel@tonic-gate zsa_null(struct zscom *zs) 501*0Sstevel@tonic-gate { 502*0Sstevel@tonic-gate /* LINTED */ 503*0Sstevel@tonic-gate register short c; 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 506*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 507*0Sstevel@tonic-gate c = SCC_READDATA(); 508*0Sstevel@tonic-gate ZSDELAY(); 509*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate /*ARGSUSED*/ 513*0Sstevel@tonic-gate static int 514*0Sstevel@tonic-gate zsa_null_int(struct zscom *zs) 515*0Sstevel@tonic-gate { 516*0Sstevel@tonic-gate return (0); 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate struct zsops zsops_null_async = { 520*0Sstevel@tonic-gate zsa_null, 521*0Sstevel@tonic-gate zsa_null, 522*0Sstevel@tonic-gate zsa_null, 523*0Sstevel@tonic-gate zsa_null, 524*0Sstevel@tonic-gate zsa_null_int, 525*0Sstevel@tonic-gate zsa_null_int, 526*0Sstevel@tonic-gate zsa_null_int 527*0Sstevel@tonic-gate }; 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate struct zsops zsops_async = { 530*0Sstevel@tonic-gate zsa_txint, 531*0Sstevel@tonic-gate zsa_xsint, 532*0Sstevel@tonic-gate zsa_rxint, 533*0Sstevel@tonic-gate zsa_srint, 534*0Sstevel@tonic-gate zsa_softint, 535*0Sstevel@tonic-gate zsa_suspend, 536*0Sstevel@tonic-gate zsa_resume 537*0Sstevel@tonic-gate }; 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate static int dmtozs(int bits); 540*0Sstevel@tonic-gate static int zstodm(int bits); 541*0Sstevel@tonic-gate static void zsa_restart(void *); 542*0Sstevel@tonic-gate static void zsa_reioctl(void *); 543*0Sstevel@tonic-gate static void zsa_ioctl(struct asyncline *za, queue_t *q, mblk_t *mp); 544*0Sstevel@tonic-gate static void zsa_program(struct asyncline *za, int setibaud); 545*0Sstevel@tonic-gate static void zsa_start(struct zscom *zs); 546*0Sstevel@tonic-gate static void zsa_kick_rcv(void *); 547*0Sstevel@tonic-gate static void zsa_callback(void *); 548*0Sstevel@tonic-gate static void zsa_set_za_rcv_flags_mask(struct asyncline *za); 549*0Sstevel@tonic-gate int zsgetspeed(dev_t dev); 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate static boolean_t abort_charseq_recognize(uchar_t ch); 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate /* ARGSUSED */ 554*0Sstevel@tonic-gate int 555*0Sstevel@tonic-gate zsc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 556*0Sstevel@tonic-gate void **result) 557*0Sstevel@tonic-gate { 558*0Sstevel@tonic-gate register dev_t dev = (dev_t)arg; 559*0Sstevel@tonic-gate register int unit, error; 560*0Sstevel@tonic-gate register struct zscom *zs; 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate if ((unit = UNIT(dev)) >= nzs) 563*0Sstevel@tonic-gate return (DDI_FAILURE); 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate switch (infocmd) { 566*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 567*0Sstevel@tonic-gate zs = &zscom[unit]; 568*0Sstevel@tonic-gate *result = zs->zs_dip; 569*0Sstevel@tonic-gate error = DDI_SUCCESS; 570*0Sstevel@tonic-gate break; 571*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 572*0Sstevel@tonic-gate *result = (void *)(unit / 2); 573*0Sstevel@tonic-gate error = DDI_SUCCESS; 574*0Sstevel@tonic-gate break; 575*0Sstevel@tonic-gate default: 576*0Sstevel@tonic-gate error = DDI_FAILURE; 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate return (error); 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* 582*0Sstevel@tonic-gate * The Asynchronous Driver. 583*0Sstevel@tonic-gate */ 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate /* 586*0Sstevel@tonic-gate * Determine if the zsminor device is in use as either a stdin or stdout 587*0Sstevel@tonic-gate * device, so we can be careful about how we initialize the DUART, if 588*0Sstevel@tonic-gate * it is, in fact, in use. 589*0Sstevel@tonic-gate * 590*0Sstevel@tonic-gate * Since this is expensive, we do it once and store away the answers, 591*0Sstevel@tonic-gate * since this gets called a number of times per phyical zs device. 592*0Sstevel@tonic-gate * Perhaps, this should be in a loadable module, so it can get thrown 593*0Sstevel@tonic-gate * away after all the zs devices are attached? 594*0Sstevel@tonic-gate */ 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate /* 597*0Sstevel@tonic-gate * To determine if a given unit is being used by the PROM, 598*0Sstevel@tonic-gate * we need to map stdin/stdout devices as known to the PROM 599*0Sstevel@tonic-gate * to zs internal minor device numbers: 600*0Sstevel@tonic-gate * 601*0Sstevel@tonic-gate * PROM (real device) zs minor device 602*0Sstevel@tonic-gate * 603*0Sstevel@tonic-gate * "zs", 0, "a" 0 ttya 604*0Sstevel@tonic-gate * "zs", 0, "b" 1 ttyb 605*0Sstevel@tonic-gate * "zs", 1, "a" 2 keyboard 606*0Sstevel@tonic-gate * "zs", 1, "b" 3 mouse 607*0Sstevel@tonic-gate * "zs", 2, "a" 4 ttyc 608*0Sstevel@tonic-gate * "zs", 2, "b" 5 ttyd 609*0Sstevel@tonic-gate * 610*0Sstevel@tonic-gate * The following value mapping lines assume that insource 611*0Sstevel@tonic-gate * and outsink map as "screen, a, b, c, d, ...", and that 612*0Sstevel@tonic-gate * zs minors are "a, b, kbd, mouse, c, d, ...". 613*0Sstevel@tonic-gate */ 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate static int zsa_inuse; /* Strictly for debugging */ 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate int 618*0Sstevel@tonic-gate zsa_channel_is_active_in_rom(dev_info_t *dev, int zsminor) 619*0Sstevel@tonic-gate { 620*0Sstevel@tonic-gate char pathname[OBP_MAXPATHLEN]; 621*0Sstevel@tonic-gate char default_pathname[OBP_MAXPATHLEN]; 622*0Sstevel@tonic-gate char *stdioname; 623*0Sstevel@tonic-gate char minordata[3]; 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /* 626*0Sstevel@tonic-gate * Basically, get my name and compare it to stdio devnames 627*0Sstevel@tonic-gate * and if we get a match, then the device is in use as either 628*0Sstevel@tonic-gate * stdin or stdout device (console tip line or keyboard device). 629*0Sstevel@tonic-gate * 630*0Sstevel@tonic-gate * We get two forms of the pathname, one complete with the 631*0Sstevel@tonic-gate * the channel number, and if the channel is 'a', then 632*0Sstevel@tonic-gate * we also deal with the user's ability to default to 633*0Sstevel@tonic-gate * channel 'a', by omitting the channel number option. 634*0Sstevel@tonic-gate * We then compare these pathnames to both the stdin and 635*0Sstevel@tonic-gate * stdout pathnames. If any of these match, then the channel 636*0Sstevel@tonic-gate * is in use. 637*0Sstevel@tonic-gate */ 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate (void) ddi_pathname(dev, pathname); /* device pathname */ 640*0Sstevel@tonic-gate default_pathname[0] = (char)0; /* default pathname if channel 'a' */ 641*0Sstevel@tonic-gate if ((zsminor & 1) == 0) 642*0Sstevel@tonic-gate (void) strcpy(default_pathname, pathname); 643*0Sstevel@tonic-gate minordata[0] = ':'; 644*0Sstevel@tonic-gate minordata[1] = (char)('a' + (zsminor & 1)); 645*0Sstevel@tonic-gate minordata[2] = (char)0; 646*0Sstevel@tonic-gate (void) strcat(pathname, minordata); 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate stdioname = prom_stdinpath(); 649*0Sstevel@tonic-gate if (strcmp(pathname, stdioname) == 0) { 650*0Sstevel@tonic-gate zsa_inuse |= (1 << zsminor); 651*0Sstevel@tonic-gate return (1); 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate if (strcmp(default_pathname, stdioname) == 0) { 654*0Sstevel@tonic-gate zsa_inuse |= (1 << zsminor); 655*0Sstevel@tonic-gate return (1); 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate stdioname = prom_stdoutpath(); 659*0Sstevel@tonic-gate if (strcmp(pathname, stdioname) == 0) { 660*0Sstevel@tonic-gate zsa_inuse |= (1 << zsminor); 661*0Sstevel@tonic-gate return (1); 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate if (strcmp(default_pathname, stdioname) == 0) { 664*0Sstevel@tonic-gate zsa_inuse |= (1 << zsminor); 665*0Sstevel@tonic-gate return (1); 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate return (0); 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate /* 672*0Sstevel@tonic-gate * Initialize zs 673*0Sstevel@tonic-gate */ 674*0Sstevel@tonic-gate void 675*0Sstevel@tonic-gate zsa_init(struct zscom *zs) 676*0Sstevel@tonic-gate { 677*0Sstevel@tonic-gate /* 678*0Sstevel@tonic-gate * This routine is called near the end of the zs module's attach 679*0Sstevel@tonic-gate * process. It initializes the TTY protocol-private data for this 680*0Sstevel@tonic-gate * channel that needs to be in place before interrupts are enabled. 681*0Sstevel@tonic-gate */ 682*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 683*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate /* 686*0Sstevel@tonic-gate * Raise modem control lines on serial ports associated 687*0Sstevel@tonic-gate * with the console and (optionally) softcarrier lines. 688*0Sstevel@tonic-gate * Drop modem control lines on all others so that modems 689*0Sstevel@tonic-gate * will not answer and portselectors will skip these 690*0Sstevel@tonic-gate * lines until they are opened by a getty. 691*0Sstevel@tonic-gate */ 692*0Sstevel@tonic-gate if (zsa_channel_is_active_in_rom(zs->zs_dip, zs->zs_unit)) 693*0Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); /* raise dtr */ 694*0Sstevel@tonic-gate else if (zsasoftdtr && (zssoftCAR[zs->zs_unit])) 695*0Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); /* raise dtr */ 696*0Sstevel@tonic-gate else 697*0Sstevel@tonic-gate (void) zsmctl(zs, ZS_OFF, DMSET); /* drop dtr */ 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate if (zsa_rstandby > ZSA_MAX_RSTANDBY) 700*0Sstevel@tonic-gate zsa_rstandby = ZSA_MAX_RSTANDBY; 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate if (zsa_rdone > ZSA_RDONE_MAX) 703*0Sstevel@tonic-gate zsa_rdone = ZSA_RDONE_MAX; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate if (zsa_grace_flow_control > ZSA_GRACE_MAX_FLOW_CONTROL) 706*0Sstevel@tonic-gate zsa_grace_flow_control = ZSA_GRACE_MAX_FLOW_CONTROL; 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 709*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate /* 714*0Sstevel@tonic-gate * Open routine. 715*0Sstevel@tonic-gate */ 716*0Sstevel@tonic-gate /*ARGSUSED*/ 717*0Sstevel@tonic-gate static int 718*0Sstevel@tonic-gate zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 719*0Sstevel@tonic-gate { 720*0Sstevel@tonic-gate register struct zscom *zs; 721*0Sstevel@tonic-gate register struct asyncline *za; 722*0Sstevel@tonic-gate register int speed, unit; 723*0Sstevel@tonic-gate struct termios *termiosp; 724*0Sstevel@tonic-gate int len; 725*0Sstevel@tonic-gate register int allocbcount = zsa_rstandby; 726*0Sstevel@tonic-gate boolean_t set_zsoptinit = B_FALSE; 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate unit = UNIT(*dev); 729*0Sstevel@tonic-gate if (unit >= nzs) 730*0Sstevel@tonic-gate return (ENXIO); /* unit not configured */ 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate /* zscom is allocated by zsattach, and thus cannot be NULL here */ 733*0Sstevel@tonic-gate zs = &zscom[unit]; 734*0Sstevel@tonic-gate if (zs->zs_ops == NULL) { 735*0Sstevel@tonic-gate return (ENXIO); /* device not found by autoconfig */ 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate mutex_enter(zs->zs_ocexcl); 739*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 740*0Sstevel@tonic-gate again: 741*0Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) && 742*0Sstevel@tonic-gate (zs->zs_ops != &zsops_async)) { 743*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 744*0Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 745*0Sstevel@tonic-gate return (EBUSY); /* another protocol got here first */ 746*0Sstevel@tonic-gate } 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate za = (struct asyncline *)&zs->zs_priv_str; 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate if (zs->zs_suspended) { 751*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 752*0Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 753*0Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1); 754*0Sstevel@tonic-gate mutex_enter(zs->zs_ocexcl); 755*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate /* Mark device as busy (for power management) */ 759*0Sstevel@tonic-gate (void) pm_busy_component(zs->zs_dip, unit%2+1); 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate if (zs->zs_ops == &zsops_null) { 762*0Sstevel@tonic-gate bzero(za, sizeof (zs->zs_priv_str)); 763*0Sstevel@tonic-gate za->za_common = zs; 764*0Sstevel@tonic-gate if (zssoftCAR[zs->zs_unit]) 765*0Sstevel@tonic-gate za->za_ttycommon.t_flags |= TS_SOFTCAR; 766*0Sstevel@tonic-gate zsopinit(zs, &zsops_async); 767*0Sstevel@tonic-gate set_zsoptinit = B_TRUE; 768*0Sstevel@tonic-gate za->za_rdone_wptr = 0; 769*0Sstevel@tonic-gate za->za_rdone_rptr = 0; 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate zs->zs_priv = (caddr_t)za; 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate /* 775*0Sstevel@tonic-gate * Block waiting for carrier to come up, 776*0Sstevel@tonic-gate * unless this is a no-delay open. 777*0Sstevel@tonic-gate */ 778*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 779*0Sstevel@tonic-gate if (!(za->za_flags & ZAS_ISOPEN)) { 780*0Sstevel@tonic-gate /* 781*0Sstevel@tonic-gate * Get the default termios settings (cflag). 782*0Sstevel@tonic-gate * These are stored as a property in the 783*0Sstevel@tonic-gate * "options" node. 784*0Sstevel@tonic-gate */ 785*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 786*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, 787*0Sstevel@tonic-gate ddi_root_node(), 0, "ttymodes", 788*0Sstevel@tonic-gate (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS && 789*0Sstevel@tonic-gate len == sizeof (struct termios)) { 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate za->za_ttycommon.t_cflag = termiosp->c_cflag; 792*0Sstevel@tonic-gate kmem_free(termiosp, len); 793*0Sstevel@tonic-gate } else { 794*0Sstevel@tonic-gate /* 795*0Sstevel@tonic-gate * Gack! Whine about it. 796*0Sstevel@tonic-gate */ 797*0Sstevel@tonic-gate cmn_err(CE_WARN, 798*0Sstevel@tonic-gate "zs: Couldn't get ttymodes property!"); 799*0Sstevel@tonic-gate } 800*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 801*0Sstevel@tonic-gate if ((*dev == rconsdev) || (*dev == kbddev) || 802*0Sstevel@tonic-gate (*dev == stdindev)) { 803*0Sstevel@tonic-gate speed = zsgetspeed(*dev); 804*0Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~(CBAUD); 805*0Sstevel@tonic-gate if (speed > CBAUD) { 806*0Sstevel@tonic-gate za->za_ttycommon.t_cflag |= CBAUDEXT; 807*0Sstevel@tonic-gate za->za_ttycommon.t_cflag |= 808*0Sstevel@tonic-gate ((speed - CBAUD - 1) & CBAUD); 809*0Sstevel@tonic-gate } else { 810*0Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~CBAUDEXT; 811*0Sstevel@tonic-gate za->za_ttycommon.t_cflag |= (speed & CBAUD); 812*0Sstevel@tonic-gate } 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate za->za_overrun = 0; 815*0Sstevel@tonic-gate za->za_ttycommon.t_iflag = 0; 816*0Sstevel@tonic-gate za->za_ttycommon.t_iocpending = NULL; 817*0Sstevel@tonic-gate za->za_ttycommon.t_size.ws_row = 0; 818*0Sstevel@tonic-gate za->za_ttycommon.t_size.ws_col = 0; 819*0Sstevel@tonic-gate za->za_ttycommon.t_size.ws_xpixel = 0; 820*0Sstevel@tonic-gate za->za_ttycommon.t_size.ws_ypixel = 0; 821*0Sstevel@tonic-gate za->za_dev = *dev; 822*0Sstevel@tonic-gate za->za_wbufcid = 0; 823*0Sstevel@tonic-gate zsa_program(za, za->za_ttycommon.t_cflag & (CIBAUDEXT|CIBAUD)); 824*0Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(za); 825*0Sstevel@tonic-gate } else if ((za->za_ttycommon.t_flags & TS_XCLUDE) && 826*0Sstevel@tonic-gate secpolicy_excl_open(cr) != 0) { 827*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 828*0Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 829*0Sstevel@tonic-gate zsopinit(zs, &zsops_null); 830*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 831*0Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 832*0Sstevel@tonic-gate return (EBUSY); 833*0Sstevel@tonic-gate } else if ((*dev & OUTLINE) && !(za->za_flags & ZAS_OUT)) { 834*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 835*0Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 836*0Sstevel@tonic-gate zsopinit(zs, &zsops_null); 837*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 838*0Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 839*0Sstevel@tonic-gate return (EBUSY); 840*0Sstevel@tonic-gate } 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate if (*dev & OUTLINE) 843*0Sstevel@tonic-gate za->za_flags |= ZAS_OUT; 844*0Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate /* 847*0Sstevel@tonic-gate * Check carrier. 848*0Sstevel@tonic-gate */ 849*0Sstevel@tonic-gate if ((za->za_ttycommon.t_flags & TS_SOFTCAR) || 850*0Sstevel@tonic-gate (zsmctl(zs, 0, DMGET) & ZSRR0_CD)) 851*0Sstevel@tonic-gate za->za_flags |= ZAS_CARR_ON; 852*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate /* 855*0Sstevel@tonic-gate * If FNDELAY and FNONBLOCK are clear, block until carrier up. 856*0Sstevel@tonic-gate * Quit on interrupt. 857*0Sstevel@tonic-gate */ 858*0Sstevel@tonic-gate if (!(flag & (FNDELAY|FNONBLOCK)) && 859*0Sstevel@tonic-gate !(za->za_ttycommon.t_cflag & CLOCAL)) { 860*0Sstevel@tonic-gate if (!(za->za_flags & (ZAS_CARR_ON|ZAS_OUT)) || 861*0Sstevel@tonic-gate ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE))) { 862*0Sstevel@tonic-gate za->za_flags |= ZAS_WOPEN; 863*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 864*0Sstevel@tonic-gate if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_ocexcl) == 0) { 865*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 866*0Sstevel@tonic-gate if (zs->zs_suspended) { 867*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 868*0Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 869*0Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 870*0Sstevel@tonic-gate 0, 1); 871*0Sstevel@tonic-gate mutex_enter(zs->zs_ocexcl); 872*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 873*0Sstevel@tonic-gate } 874*0Sstevel@tonic-gate za->za_flags &= ~ZAS_WOPEN; 875*0Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 876*0Sstevel@tonic-gate zsopinit(zs, &zsops_null); 877*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 878*0Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 879*0Sstevel@tonic-gate return (EINTR); 880*0Sstevel@tonic-gate } 881*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 882*0Sstevel@tonic-gate za->za_flags &= ~ZAS_WOPEN; 883*0Sstevel@tonic-gate if ((zs->zs_ops == &zsops_null) || 884*0Sstevel@tonic-gate (zs->zs_ops == &zsops_async)) 885*0Sstevel@tonic-gate goto again; 886*0Sstevel@tonic-gate else { 887*0Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 888*0Sstevel@tonic-gate zsopinit(zs, &zsops_null); 889*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 890*0Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 891*0Sstevel@tonic-gate return (EBUSY); 892*0Sstevel@tonic-gate } 893*0Sstevel@tonic-gate } 894*0Sstevel@tonic-gate } else if ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE)) { 895*0Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 896*0Sstevel@tonic-gate zsopinit(zs, &zsops_null); 897*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 898*0Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 899*0Sstevel@tonic-gate return (EBUSY); 900*0Sstevel@tonic-gate } 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gate za->za_ttycommon.t_readq = rq; 903*0Sstevel@tonic-gate za->za_ttycommon.t_writeq = WR(rq); 904*0Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = (caddr_t)za; 905*0Sstevel@tonic-gate 906*0Sstevel@tonic-gate za->za_flags |= ZAS_ISOPEN; 907*0Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount); 908*0Sstevel@tonic-gate qprocson(rq); 909*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 910*0Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 911*0Sstevel@tonic-gate return (0); 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate static void 915*0Sstevel@tonic-gate zs_progress_check(void *arg) 916*0Sstevel@tonic-gate { 917*0Sstevel@tonic-gate struct asyncline *za = arg; 918*0Sstevel@tonic-gate struct zscom *zs = za->za_common; 919*0Sstevel@tonic-gate mblk_t *bp; 920*0Sstevel@tonic-gate 921*0Sstevel@tonic-gate /* 922*0Sstevel@tonic-gate * We define "progress" as either waiting on a timed break or delay, or 923*0Sstevel@tonic-gate * having had at least one transmitter interrupt. If none of these are 924*0Sstevel@tonic-gate * true, then just terminate the output and wake up that close thread. 925*0Sstevel@tonic-gate */ 926*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 927*0Sstevel@tonic-gate if (!(zs->zs_flags & ZS_PROGRESS) && 928*0Sstevel@tonic-gate !(za->za_flags & (ZAS_BREAK|ZAS_DELAY))) { 929*0Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 930*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 931*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 932*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 933*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 934*0Sstevel@tonic-gate bp = za->za_xmitblk; 935*0Sstevel@tonic-gate za->za_xmitblk = NULL; 936*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 937*0Sstevel@tonic-gate zs->zs_timer = 0; 938*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 939*0Sstevel@tonic-gate if (bp != NULL) 940*0Sstevel@tonic-gate freeb(bp); 941*0Sstevel@tonic-gate /* 942*0Sstevel@tonic-gate * Since this timer is running, we know that we're in exit(2). 943*0Sstevel@tonic-gate * That means that the user can't possibly be waiting on any 944*0Sstevel@tonic-gate * valid ioctl(2) completion anymore, and we should just flush 945*0Sstevel@tonic-gate * everything. 946*0Sstevel@tonic-gate */ 947*0Sstevel@tonic-gate flushq(za->za_ttycommon.t_writeq, FLUSHALL); 948*0Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 949*0Sstevel@tonic-gate } else { 950*0Sstevel@tonic-gate zs->zs_flags &= ~ZS_PROGRESS; 951*0Sstevel@tonic-gate zs->zs_timer = timeout(zs_progress_check, za, 952*0Sstevel@tonic-gate drv_usectohz(zs_drain_check)); 953*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 954*0Sstevel@tonic-gate } 955*0Sstevel@tonic-gate } 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate /* 958*0Sstevel@tonic-gate * Close routine. 959*0Sstevel@tonic-gate * 960*0Sstevel@tonic-gate * Important locking note: the zs_ocexcl lock is not held at all in this 961*0Sstevel@tonic-gate * routine. This is intentional. That lock is used to coordinate multiple 962*0Sstevel@tonic-gate * simultaneous opens on a stream, and there's no such thing as multiple 963*0Sstevel@tonic-gate * simultaneous closes on a stream. 964*0Sstevel@tonic-gate */ 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate /*ARGSUSED*/ 967*0Sstevel@tonic-gate static int 968*0Sstevel@tonic-gate zsa_close(queue_t *q, int flag) 969*0Sstevel@tonic-gate { 970*0Sstevel@tonic-gate struct asyncline *za; 971*0Sstevel@tonic-gate struct zscom *zs; 972*0Sstevel@tonic-gate int i; 973*0Sstevel@tonic-gate mblk_t *bp; 974*0Sstevel@tonic-gate timeout_id_t za_zsa_restart_id, za_kick_rcv_id; 975*0Sstevel@tonic-gate bufcall_id_t za_bufcid, za_wbufcid; 976*0Sstevel@tonic-gate int tmp; 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate za = q->q_ptr; 979*0Sstevel@tonic-gate ASSERT(za != NULL); 980*0Sstevel@tonic-gate 981*0Sstevel@tonic-gate zs = za->za_common; 982*0Sstevel@tonic-gate 983*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 984*0Sstevel@tonic-gate zs->zs_flags |= ZS_CLOSING; 985*0Sstevel@tonic-gate 986*0Sstevel@tonic-gate /* 987*0Sstevel@tonic-gate * There are two flavors of break -- timed (M_BREAK or TCSBRK) and 988*0Sstevel@tonic-gate * untimed (TIOCSBRK). For the timed case, these are enqueued on our 989*0Sstevel@tonic-gate * write queue and there's a timer running, so we don't have to worry 990*0Sstevel@tonic-gate * about them. For the untimed case, though, the user obviously made a 991*0Sstevel@tonic-gate * mistake, because these are handled immediately. We'll terminate the 992*0Sstevel@tonic-gate * break now and honor his implicit request by discarding the rest of 993*0Sstevel@tonic-gate * the data. 994*0Sstevel@tonic-gate */ 995*0Sstevel@tonic-gate if (!(za->za_flags & ZAS_BREAK) && (zs->zs_wreg[5] & ZSWR5_BREAK)) 996*0Sstevel@tonic-gate goto nodrain; 997*0Sstevel@tonic-gate 998*0Sstevel@tonic-gate /* 999*0Sstevel@tonic-gate * If the user told us not to delay the close ("non-blocking"), then 1000*0Sstevel@tonic-gate * don't bother trying to drain. 1001*0Sstevel@tonic-gate * 1002*0Sstevel@tonic-gate * If the user did M_STOP (ASYNC_STOPPED), there's no hope of ever 1003*0Sstevel@tonic-gate * getting an M_START (since these messages aren't enqueued), and the 1004*0Sstevel@tonic-gate * only other way to clear the stop condition is by loss of DCD, which 1005*0Sstevel@tonic-gate * would discard the queue data. Thus, we drop the output data if 1006*0Sstevel@tonic-gate * ASYNC_STOPPED is set. 1007*0Sstevel@tonic-gate */ 1008*0Sstevel@tonic-gate if ((flag & (FNDELAY|FNONBLOCK)) || (za->za_flags & ZAS_STOPPED)) 1009*0Sstevel@tonic-gate goto nodrain; 1010*0Sstevel@tonic-gate 1011*0Sstevel@tonic-gate /* 1012*0Sstevel@tonic-gate * If there's any pending output, then we have to try to drain it. 1013*0Sstevel@tonic-gate * There are two main cases to be handled: 1014*0Sstevel@tonic-gate * - called by close(2): need to drain until done or until 1015*0Sstevel@tonic-gate * a signal is received. No timeout. 1016*0Sstevel@tonic-gate * - called by exit(2): need to drain while making progress 1017*0Sstevel@tonic-gate * or until a timeout occurs. No signals. 1018*0Sstevel@tonic-gate * 1019*0Sstevel@tonic-gate * If we can't rely on receiving a signal to get us out of a hung 1020*0Sstevel@tonic-gate * session, then we have to use a timer. In this case, we set a timer 1021*0Sstevel@tonic-gate * to check for progress in sending the output data -- all that we ask 1022*0Sstevel@tonic-gate * (at each interval) is that there's been some progress made. Since 1023*0Sstevel@tonic-gate * the interrupt routine grabs buffers from the write queue, we can't 1024*0Sstevel@tonic-gate * trust changes in zs_wr_cur. Instead, we use a progress flag. 1025*0Sstevel@tonic-gate * 1026*0Sstevel@tonic-gate * Note that loss of carrier will cause the output queue to be flushed, 1027*0Sstevel@tonic-gate * and we'll wake up again and finish normally. 1028*0Sstevel@tonic-gate */ 1029*0Sstevel@tonic-gate if (!ddi_can_receive_sig() && zs_drain_check != 0) { 1030*0Sstevel@tonic-gate zs->zs_flags &= ~ZS_PROGRESS; 1031*0Sstevel@tonic-gate zs->zs_timer = timeout(zs_progress_check, za, 1032*0Sstevel@tonic-gate drv_usectohz(zs_drain_check)); 1033*0Sstevel@tonic-gate } 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate while (zs->zs_wr_cur != NULL || 1036*0Sstevel@tonic-gate za->za_ttycommon.t_writeq->q_first != NULL || 1037*0Sstevel@tonic-gate (za->za_flags & (ZAS_BUSY|ZAS_DELAY|ZAS_BREAK))) { 1038*0Sstevel@tonic-gate if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_excl) == 0) 1039*0Sstevel@tonic-gate break; 1040*0Sstevel@tonic-gate } 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate if (zs->zs_timer != 0) { 1043*0Sstevel@tonic-gate (void) untimeout(zs->zs_timer); 1044*0Sstevel@tonic-gate zs->zs_timer = 0; 1045*0Sstevel@tonic-gate } 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate nodrain: 1048*0Sstevel@tonic-gate /* 1049*0Sstevel@tonic-gate * If break is in progress, stop it. 1050*0Sstevel@tonic-gate */ 1051*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1052*0Sstevel@tonic-gate if (zs->zs_wreg[5] & ZSWR5_BREAK) { 1053*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK); 1054*0Sstevel@tonic-gate za->za_flags &= ~ZAS_BREAK; 1055*0Sstevel@tonic-gate } 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate za_wbufcid = za->za_wbufcid; 1058*0Sstevel@tonic-gate za_bufcid = za->za_bufcid; 1059*0Sstevel@tonic-gate za_zsa_restart_id = za->za_zsa_restart_id; 1060*0Sstevel@tonic-gate za_kick_rcv_id = za->za_kick_rcv_id; 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate za->za_wbufcid = za->za_bufcid = 0; 1063*0Sstevel@tonic-gate za->za_zsa_restart_id = za->za_kick_rcv_id = 0; 1064*0Sstevel@tonic-gate 1065*0Sstevel@tonic-gate /* 1066*0Sstevel@tonic-gate * If line has HUPCL set or is incompletely opened, 1067*0Sstevel@tonic-gate * and it is not the console or the keyboard, 1068*0Sstevel@tonic-gate * fix up the modem lines. 1069*0Sstevel@tonic-gate */ 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate zsopinit(zs, &zsops_null_async); 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate /* 1074*0Sstevel@tonic-gate * Nobody, zsh or zs can now open this port until 1075*0Sstevel@tonic-gate * zsopinit(zs, &zsops_null); 1076*0Sstevel@tonic-gate * 1077*0Sstevel@tonic-gate */ 1078*0Sstevel@tonic-gate 1079*0Sstevel@tonic-gate if ((za->za_dev != rconsdev) && (za->za_dev != kbddev) && 1080*0Sstevel@tonic-gate (za->za_dev != stdindev) && 1081*0Sstevel@tonic-gate (((za->za_flags & (ZAS_WOPEN|ZAS_ISOPEN)) != ZAS_ISOPEN) || 1082*0Sstevel@tonic-gate (za->za_ttycommon.t_cflag & HUPCL))) { 1083*0Sstevel@tonic-gate /* 1084*0Sstevel@tonic-gate * If DTR is being held high by softcarrier, 1085*0Sstevel@tonic-gate * set up the ZS_ON set; if not, hang up. 1086*0Sstevel@tonic-gate */ 1087*0Sstevel@tonic-gate if (zsasoftdtr && (za->za_ttycommon.t_flags & TS_SOFTCAR)) 1088*0Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); 1089*0Sstevel@tonic-gate else 1090*0Sstevel@tonic-gate (void) zsmctl(zs, ZS_OFF, DMSET); 1091*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1092*0Sstevel@tonic-gate /* 1093*0Sstevel@tonic-gate * Don't let an interrupt in the middle of close 1094*0Sstevel@tonic-gate * bounce us back to the top; just continue 1095*0Sstevel@tonic-gate * closing as if nothing had happened. 1096*0Sstevel@tonic-gate */ 1097*0Sstevel@tonic-gate tmp = cv_timedwait_sig(&zs->zs_flags_cv, zs->zs_excl, 1098*0Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(10000)); 1099*0Sstevel@tonic-gate if (zs->zs_suspended) { 1100*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1101*0Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1); 1102*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1103*0Sstevel@tonic-gate } 1104*0Sstevel@tonic-gate if (tmp == 0) 1105*0Sstevel@tonic-gate goto out; 1106*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1107*0Sstevel@tonic-gate } 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate /* 1110*0Sstevel@tonic-gate * If nobody's now using it, turn off receiver interrupts. 1111*0Sstevel@tonic-gate */ 1112*0Sstevel@tonic-gate if ((za->za_flags & (ZAS_ISOPEN|ZAS_WOPEN)) == 0) 1113*0Sstevel@tonic-gate SCC_BIC(1, ZSWR1_RIE); 1114*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate out: 1117*0Sstevel@tonic-gate /* 1118*0Sstevel@tonic-gate * Clear out device state. 1119*0Sstevel@tonic-gate */ 1120*0Sstevel@tonic-gate ttycommon_close(&za->za_ttycommon); 1121*0Sstevel@tonic-gate 1122*0Sstevel@tonic-gate za->za_ttycommon.t_readq = NULL; 1123*0Sstevel@tonic-gate za->za_ttycommon.t_writeq = NULL; 1124*0Sstevel@tonic-gate 1125*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1126*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 1127*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 1128*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 1129*0Sstevel@tonic-gate bp = za->za_xmitblk; 1130*0Sstevel@tonic-gate za->za_xmitblk = NULL; 1131*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1132*0Sstevel@tonic-gate if (bp) 1133*0Sstevel@tonic-gate freemsg(bp); 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1136*0Sstevel@tonic-gate zs->zs_rd_cur = NULL; 1137*0Sstevel@tonic-gate zs->zs_rd_lim = NULL; 1138*0Sstevel@tonic-gate bp = za->za_rcvblk; 1139*0Sstevel@tonic-gate za->za_rcvblk = NULL; 1140*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1141*0Sstevel@tonic-gate if (bp) 1142*0Sstevel@tonic-gate freemsg(bp); 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate for (i = 0; i < zsa_rstandby; i++) { 1145*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1146*0Sstevel@tonic-gate bp = za->za_rstandby[i]; 1147*0Sstevel@tonic-gate za->za_rstandby[i] = NULL; 1148*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1149*0Sstevel@tonic-gate if (bp) 1150*0Sstevel@tonic-gate freemsg(bp); 1151*0Sstevel@tonic-gate } 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate if (za->za_soft_active || za->za_kick_active) { 1154*0Sstevel@tonic-gate zs->zs_flags |= ZS_CLOSED; 1155*0Sstevel@tonic-gate while (za->za_soft_active || za->za_kick_active) 1156*0Sstevel@tonic-gate cv_wait(&zs->zs_flags_cv, zs->zs_excl); 1157*0Sstevel@tonic-gate } 1158*0Sstevel@tonic-gate if (zs->zs_suspended) { 1159*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1160*0Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1); 1161*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1162*0Sstevel@tonic-gate } 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate ZSA_FLUSHQ; 1165*0Sstevel@tonic-gate bzero(za, sizeof (struct asyncline)); 1166*0Sstevel@tonic-gate qprocsoff(q); 1167*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate /* 1170*0Sstevel@tonic-gate * Cancel outstanding "bufcall" request. 1171*0Sstevel@tonic-gate */ 1172*0Sstevel@tonic-gate if (za_wbufcid) 1173*0Sstevel@tonic-gate unbufcall(za_wbufcid); 1174*0Sstevel@tonic-gate if (za_bufcid) 1175*0Sstevel@tonic-gate unbufcall(za_bufcid); 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate /* 1178*0Sstevel@tonic-gate * Cancel outstanding timeout. 1179*0Sstevel@tonic-gate */ 1180*0Sstevel@tonic-gate if (za_zsa_restart_id) 1181*0Sstevel@tonic-gate (void) untimeout(za_zsa_restart_id); 1182*0Sstevel@tonic-gate 1183*0Sstevel@tonic-gate if (za_kick_rcv_id) 1184*0Sstevel@tonic-gate (void) untimeout(za_kick_rcv_id); 1185*0Sstevel@tonic-gate 1186*0Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL; 1187*0Sstevel@tonic-gate zsopinit(zs, &zsops_null); 1188*0Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate /* Mark device as available for power management */ 1191*0Sstevel@tonic-gate (void) pm_idle_component(zs->zs_dip, zs->zs_unit%2+1); 1192*0Sstevel@tonic-gate return (0); 1193*0Sstevel@tonic-gate } 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate /* 1196*0Sstevel@tonic-gate * Put procedure for write queue. 1197*0Sstevel@tonic-gate * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here; 1198*0Sstevel@tonic-gate * set the flow control character for M_STOPI and M_STARTI messages; 1199*0Sstevel@tonic-gate * queue up M_BREAK, M_DELAY, and M_DATA messages for processing 1200*0Sstevel@tonic-gate * by the start routine, and then call the start routine; discard 1201*0Sstevel@tonic-gate * everything else. Note that this driver does not incorporate any 1202*0Sstevel@tonic-gate * mechanism to negotiate to handle the canonicalization process. 1203*0Sstevel@tonic-gate * It expects that these functions are handled in upper module(s), 1204*0Sstevel@tonic-gate * as we do in ldterm. 1205*0Sstevel@tonic-gate */ 1206*0Sstevel@tonic-gate static void 1207*0Sstevel@tonic-gate zsa_wput(queue_t *q, mblk_t *mp) 1208*0Sstevel@tonic-gate { 1209*0Sstevel@tonic-gate register struct asyncline *za; 1210*0Sstevel@tonic-gate register struct zscom *zs; 1211*0Sstevel@tonic-gate register struct copyresp *resp; 1212*0Sstevel@tonic-gate register mblk_t *bp = NULL; 1213*0Sstevel@tonic-gate int error; 1214*0Sstevel@tonic-gate struct iocblk *iocp; 1215*0Sstevel@tonic-gate 1216*0Sstevel@tonic-gate za = (struct asyncline *)q->q_ptr; 1217*0Sstevel@tonic-gate zs = za->za_common; 1218*0Sstevel@tonic-gate if (zs->zs_flags & ZS_NEEDSOFT) { 1219*0Sstevel@tonic-gate zs->zs_flags &= ~ZS_NEEDSOFT; 1220*0Sstevel@tonic-gate (void) zsa_softint(zs); 1221*0Sstevel@tonic-gate } 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 1224*0Sstevel@tonic-gate 1225*0Sstevel@tonic-gate case M_STOP: 1226*0Sstevel@tonic-gate /* 1227*0Sstevel@tonic-gate * Since we don't do real DMA, we can just let the 1228*0Sstevel@tonic-gate * chip coast to a stop after applying the brakes. 1229*0Sstevel@tonic-gate */ 1230*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1231*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1232*0Sstevel@tonic-gate za->za_flags |= ZAS_STOPPED; 1233*0Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) { 1234*0Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 1235*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 1236*0Sstevel@tonic-gate bp = za->za_xmitblk; 1237*0Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur; 1238*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 1239*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 1240*0Sstevel@tonic-gate za->za_xmitblk = NULL; 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1243*0Sstevel@tonic-gate if (bp) 1244*0Sstevel@tonic-gate (void) putbq(q, bp); 1245*0Sstevel@tonic-gate freemsg(mp); 1246*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1247*0Sstevel@tonic-gate break; 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate case M_START: 1250*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1251*0Sstevel@tonic-gate if (za->za_flags & ZAS_STOPPED) { 1252*0Sstevel@tonic-gate za->za_flags &= ~ZAS_STOPPED; 1253*0Sstevel@tonic-gate /* 1254*0Sstevel@tonic-gate * If an output operation is in progress, 1255*0Sstevel@tonic-gate * resume it. Otherwise, prod the start 1256*0Sstevel@tonic-gate * routine. 1257*0Sstevel@tonic-gate */ 1258*0Sstevel@tonic-gate zsa_start(zs); 1259*0Sstevel@tonic-gate } 1260*0Sstevel@tonic-gate freemsg(mp); 1261*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1262*0Sstevel@tonic-gate break; 1263*0Sstevel@tonic-gate 1264*0Sstevel@tonic-gate case M_IOCTL: 1265*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1266*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 1267*0Sstevel@tonic-gate 1268*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 1269*0Sstevel@tonic-gate 1270*0Sstevel@tonic-gate case TIOCGPPS: 1271*0Sstevel@tonic-gate /* 1272*0Sstevel@tonic-gate * Get PPS state. 1273*0Sstevel@tonic-gate */ 1274*0Sstevel@tonic-gate if (mp->b_cont != NULL) 1275*0Sstevel@tonic-gate freemsg(mp->b_cont); 1276*0Sstevel@tonic-gate 1277*0Sstevel@tonic-gate mp->b_cont = allocb(sizeof (int), BPRI_HI); 1278*0Sstevel@tonic-gate if (mp->b_cont == NULL) { 1279*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 1280*0Sstevel@tonic-gate iocp->ioc_error = ENOMEM; 1281*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1282*0Sstevel@tonic-gate break; 1283*0Sstevel@tonic-gate } 1284*0Sstevel@tonic-gate if (za->za_pps) 1285*0Sstevel@tonic-gate *(int *)mp->b_cont->b_wptr = 1; 1286*0Sstevel@tonic-gate else 1287*0Sstevel@tonic-gate *(int *)mp->b_cont->b_wptr = 0; 1288*0Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (int); 1289*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 1290*0Sstevel@tonic-gate iocp->ioc_count = sizeof (int); 1291*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1292*0Sstevel@tonic-gate break; 1293*0Sstevel@tonic-gate 1294*0Sstevel@tonic-gate case TIOCSPPS: 1295*0Sstevel@tonic-gate /* 1296*0Sstevel@tonic-gate * Set PPS state. 1297*0Sstevel@tonic-gate */ 1298*0Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 1299*0Sstevel@tonic-gate if (error != 0) { 1300*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 1301*0Sstevel@tonic-gate iocp->ioc_error = error; 1302*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1303*0Sstevel@tonic-gate break; 1304*0Sstevel@tonic-gate } 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate za->za_pps = (*(int *)mp->b_cont->b_rptr != 0); 1307*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 1308*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1309*0Sstevel@tonic-gate break; 1310*0Sstevel@tonic-gate 1311*0Sstevel@tonic-gate case TIOCGPPSEV: 1312*0Sstevel@tonic-gate { 1313*0Sstevel@tonic-gate /* 1314*0Sstevel@tonic-gate * Get PPS event data. 1315*0Sstevel@tonic-gate */ 1316*0Sstevel@tonic-gate void *buf; 1317*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1318*0Sstevel@tonic-gate struct ppsclockev32 p32; 1319*0Sstevel@tonic-gate #endif 1320*0Sstevel@tonic-gate 1321*0Sstevel@tonic-gate if (mp->b_cont != NULL) { 1322*0Sstevel@tonic-gate freemsg(mp->b_cont); 1323*0Sstevel@tonic-gate mp->b_cont = NULL; 1324*0Sstevel@tonic-gate } 1325*0Sstevel@tonic-gate if (za->za_pps == NULL) { 1326*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 1327*0Sstevel@tonic-gate iocp->ioc_error = ENXIO; 1328*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1329*0Sstevel@tonic-gate break; 1330*0Sstevel@tonic-gate } 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1333*0Sstevel@tonic-gate if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) { 1334*0Sstevel@tonic-gate TIMEVAL_TO_TIMEVAL32(&p32.tv, &ppsclockev.tv); 1335*0Sstevel@tonic-gate p32.serial = ppsclockev.serial; 1336*0Sstevel@tonic-gate buf = &p32; 1337*0Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ppsclockev32); 1338*0Sstevel@tonic-gate } else 1339*0Sstevel@tonic-gate #endif 1340*0Sstevel@tonic-gate { 1341*0Sstevel@tonic-gate buf = &ppsclockev; 1342*0Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ppsclockev); 1343*0Sstevel@tonic-gate } 1344*0Sstevel@tonic-gate 1345*0Sstevel@tonic-gate if ((bp = allocb(iocp->ioc_count, BPRI_HI)) == NULL) { 1346*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 1347*0Sstevel@tonic-gate iocp->ioc_error = ENOMEM; 1348*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1349*0Sstevel@tonic-gate break; 1350*0Sstevel@tonic-gate } 1351*0Sstevel@tonic-gate mp->b_cont = bp; 1352*0Sstevel@tonic-gate 1353*0Sstevel@tonic-gate bcopy(buf, bp->b_wptr, iocp->ioc_count); 1354*0Sstevel@tonic-gate bp->b_wptr += iocp->ioc_count; 1355*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 1356*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1357*0Sstevel@tonic-gate break; 1358*0Sstevel@tonic-gate } 1359*0Sstevel@tonic-gate 1360*0Sstevel@tonic-gate case TCSETSW: 1361*0Sstevel@tonic-gate case TCSETSF: 1362*0Sstevel@tonic-gate case TCSETAW: 1363*0Sstevel@tonic-gate case TCSETAF: 1364*0Sstevel@tonic-gate case TCSBRK: 1365*0Sstevel@tonic-gate /* 1366*0Sstevel@tonic-gate * The changes do not take effect until all 1367*0Sstevel@tonic-gate * output queued before them is drained. 1368*0Sstevel@tonic-gate * Put this message on the queue, so that 1369*0Sstevel@tonic-gate * "zsa_start" will see it when it's done 1370*0Sstevel@tonic-gate * with the output before it. Poke the 1371*0Sstevel@tonic-gate * start routine, just in case. 1372*0Sstevel@tonic-gate */ 1373*0Sstevel@tonic-gate (void) putq(q, mp); 1374*0Sstevel@tonic-gate zsa_start(zs); 1375*0Sstevel@tonic-gate break; 1376*0Sstevel@tonic-gate 1377*0Sstevel@tonic-gate default: 1378*0Sstevel@tonic-gate /* 1379*0Sstevel@tonic-gate * Do it now. 1380*0Sstevel@tonic-gate */ 1381*0Sstevel@tonic-gate zsa_ioctl(za, q, mp); 1382*0Sstevel@tonic-gate break; 1383*0Sstevel@tonic-gate } 1384*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1385*0Sstevel@tonic-gate break; 1386*0Sstevel@tonic-gate 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate case M_IOCDATA: 1389*0Sstevel@tonic-gate 1390*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1391*0Sstevel@tonic-gate resp = (struct copyresp *)mp->b_rptr; 1392*0Sstevel@tonic-gate if (resp->cp_rval) { 1393*0Sstevel@tonic-gate /* 1394*0Sstevel@tonic-gate * Just free message on failure. 1395*0Sstevel@tonic-gate */ 1396*0Sstevel@tonic-gate freemsg(mp); 1397*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1398*0Sstevel@tonic-gate break; 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate switch (resp->cp_cmd) { 1401*0Sstevel@tonic-gate 1402*0Sstevel@tonic-gate case TIOCMSET: 1403*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1404*0Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr), 1405*0Sstevel@tonic-gate DMSET); 1406*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1407*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1408*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1409*0Sstevel@tonic-gate break; 1410*0Sstevel@tonic-gate 1411*0Sstevel@tonic-gate case TIOCMBIS: 1412*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1413*0Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr), 1414*0Sstevel@tonic-gate DMBIS); 1415*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1416*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1417*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1418*0Sstevel@tonic-gate break; 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate case TIOCMBIC: 1421*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1422*0Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr), 1423*0Sstevel@tonic-gate DMBIC); 1424*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1425*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1426*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1427*0Sstevel@tonic-gate break; 1428*0Sstevel@tonic-gate 1429*0Sstevel@tonic-gate case TIOCMGET: 1430*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 1431*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1432*0Sstevel@tonic-gate break; 1433*0Sstevel@tonic-gate 1434*0Sstevel@tonic-gate default: 1435*0Sstevel@tonic-gate freemsg(mp); 1436*0Sstevel@tonic-gate 1437*0Sstevel@tonic-gate } 1438*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1439*0Sstevel@tonic-gate break; 1440*0Sstevel@tonic-gate 1441*0Sstevel@tonic-gate 1442*0Sstevel@tonic-gate case M_FLUSH: 1443*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1444*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate /* 1447*0Sstevel@tonic-gate * Abort any output in progress. 1448*0Sstevel@tonic-gate */ 1449*0Sstevel@tonic-gate if (za->za_flags & ZAS_BUSY) { 1450*0Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 1451*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1452*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 1453*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 1454*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 1455*0Sstevel@tonic-gate bp = za->za_xmitblk; 1456*0Sstevel@tonic-gate za->za_xmitblk = NULL; 1457*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1458*0Sstevel@tonic-gate if (bp) 1459*0Sstevel@tonic-gate freemsg(bp); 1460*0Sstevel@tonic-gate } 1461*0Sstevel@tonic-gate /* 1462*0Sstevel@tonic-gate * Flush our write queue. 1463*0Sstevel@tonic-gate */ 1464*0Sstevel@tonic-gate flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */ 1465*0Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; /* it has been flushed */ 1466*0Sstevel@tonic-gate } 1467*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 1468*0Sstevel@tonic-gate /* 1469*0Sstevel@tonic-gate * Flush any data in the temporary receive buffer 1470*0Sstevel@tonic-gate */ 1471*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1472*0Sstevel@tonic-gate if ((za->za_ttycommon.t_flags & TS_SOFTCAR) || 1473*0Sstevel@tonic-gate (SCC_READ0() & ZSRR0_CD)) { 1474*0Sstevel@tonic-gate ZSA_KICK_RCV; 1475*0Sstevel@tonic-gate } else { 1476*0Sstevel@tonic-gate ZSA_KICK_RCV; 1477*0Sstevel@tonic-gate if (!(SCC_READ0() & ZSRR0_RX_READY)) { 1478*0Sstevel@tonic-gate /* 1479*0Sstevel@tonic-gate * settle time for 1 character shift 1480*0Sstevel@tonic-gate */ 1481*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1482*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1483*0Sstevel@tonic-gate delay(ztdelay( 1484*0Sstevel@tonic-gate SPEED(za->za_ttycommon.t_cflag))/3 + 1); 1485*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1486*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1487*0Sstevel@tonic-gate if (!(SCC_READ0() & ZSRR0_CD)) 1488*0Sstevel@tonic-gate ZSA_KICK_RCV; 1489*0Sstevel@tonic-gate } 1490*0Sstevel@tonic-gate while ((SCC_READ0() & 1491*0Sstevel@tonic-gate (ZSRR0_CD|ZSRR0_RX_READY)) == ZSRR0_RX_READY) { 1492*0Sstevel@tonic-gate /* 1493*0Sstevel@tonic-gate * Empty Receiver 1494*0Sstevel@tonic-gate */ 1495*0Sstevel@tonic-gate (void) SCC_READDATA(); 1496*0Sstevel@tonic-gate } 1497*0Sstevel@tonic-gate } 1498*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1499*0Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 1500*0Sstevel@tonic-gate ZSA_QREPLY(q, mp); 1501*0Sstevel@tonic-gate /* 1502*0Sstevel@tonic-gate * give the read queues a crack at it 1503*0Sstevel@tonic-gate */ 1504*0Sstevel@tonic-gate } else 1505*0Sstevel@tonic-gate freemsg(mp); 1506*0Sstevel@tonic-gate 1507*0Sstevel@tonic-gate /* 1508*0Sstevel@tonic-gate * We must make sure we process messages that survive the 1509*0Sstevel@tonic-gate * write-side flush. Without this call, the close protocol 1510*0Sstevel@tonic-gate * with ldterm can hang forever. (ldterm will have sent us a 1511*0Sstevel@tonic-gate * TCSBRK ioctl that it expects a response to.) 1512*0Sstevel@tonic-gate */ 1513*0Sstevel@tonic-gate zsa_start(zs); 1514*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1515*0Sstevel@tonic-gate break; 1516*0Sstevel@tonic-gate 1517*0Sstevel@tonic-gate case M_BREAK: 1518*0Sstevel@tonic-gate case M_DELAY: 1519*0Sstevel@tonic-gate case M_DATA: 1520*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1521*0Sstevel@tonic-gate /* 1522*0Sstevel@tonic-gate * Queue the message up to be transmitted, 1523*0Sstevel@tonic-gate * and poke the start routine. 1524*0Sstevel@tonic-gate */ 1525*0Sstevel@tonic-gate (void) putq(q, mp); 1526*0Sstevel@tonic-gate zsa_start(zs); 1527*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1528*0Sstevel@tonic-gate break; 1529*0Sstevel@tonic-gate 1530*0Sstevel@tonic-gate case M_STOPI: 1531*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1532*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1533*0Sstevel@tonic-gate za->za_flowc = za->za_ttycommon.t_stopc; 1534*0Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) { 1535*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 1536*0Sstevel@tonic-gate bp = za->za_xmitblk; 1537*0Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur; 1538*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 1539*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 1540*0Sstevel@tonic-gate za->za_xmitblk = NULL; 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1543*0Sstevel@tonic-gate if (bp) 1544*0Sstevel@tonic-gate (void) putbq(q, bp); 1545*0Sstevel@tonic-gate else 1546*0Sstevel@tonic-gate zsa_start(zs); /* poke the start routine */ 1547*0Sstevel@tonic-gate freemsg(mp); 1548*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1549*0Sstevel@tonic-gate break; 1550*0Sstevel@tonic-gate 1551*0Sstevel@tonic-gate case M_STARTI: 1552*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1553*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1554*0Sstevel@tonic-gate za->za_flowc = za->za_ttycommon.t_startc; 1555*0Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) { 1556*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 1557*0Sstevel@tonic-gate bp = za->za_xmitblk; 1558*0Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur; 1559*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 1560*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 1561*0Sstevel@tonic-gate za->za_xmitblk = NULL; 1562*0Sstevel@tonic-gate } 1563*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1564*0Sstevel@tonic-gate if (bp) 1565*0Sstevel@tonic-gate (void) putbq(q, bp); 1566*0Sstevel@tonic-gate else 1567*0Sstevel@tonic-gate zsa_start(zs); /* poke the start routine */ 1568*0Sstevel@tonic-gate freemsg(mp); 1569*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1570*0Sstevel@tonic-gate break; 1571*0Sstevel@tonic-gate 1572*0Sstevel@tonic-gate case M_CTL: 1573*0Sstevel@tonic-gate if (MBLKL(mp) >= sizeof (struct iocblk) && 1574*0Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) { 1575*0Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd = MC_HAS_POSIX; 1576*0Sstevel@tonic-gate qreply(q, mp); 1577*0Sstevel@tonic-gate } else { 1578*0Sstevel@tonic-gate /* 1579*0Sstevel@tonic-gate * These MC_SERVICE type messages are used by upper 1580*0Sstevel@tonic-gate * modules to tell this driver to send input up 1581*0Sstevel@tonic-gate * immediately, or that it can wait for normal 1582*0Sstevel@tonic-gate * processing that may or may not be done. Sun 1583*0Sstevel@tonic-gate * requires these for the mouse module. 1584*0Sstevel@tonic-gate */ 1585*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 1586*0Sstevel@tonic-gate switch (*mp->b_rptr) { 1587*0Sstevel@tonic-gate 1588*0Sstevel@tonic-gate case MC_SERVICEIMM: 1589*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1590*0Sstevel@tonic-gate za->za_flags |= ZAS_SERVICEIMM; 1591*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1592*0Sstevel@tonic-gate break; 1593*0Sstevel@tonic-gate 1594*0Sstevel@tonic-gate case MC_SERVICEDEF: 1595*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1596*0Sstevel@tonic-gate za->za_flags &= ~ZAS_SERVICEIMM; 1597*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1598*0Sstevel@tonic-gate break; 1599*0Sstevel@tonic-gate } 1600*0Sstevel@tonic-gate freemsg(mp); 1601*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 1602*0Sstevel@tonic-gate } 1603*0Sstevel@tonic-gate break; 1604*0Sstevel@tonic-gate 1605*0Sstevel@tonic-gate default: 1606*0Sstevel@tonic-gate /* 1607*0Sstevel@tonic-gate * "No, I don't want a subscription to Chain Store Age, 1608*0Sstevel@tonic-gate * thank you anyway." 1609*0Sstevel@tonic-gate */ 1610*0Sstevel@tonic-gate freemsg(mp); 1611*0Sstevel@tonic-gate break; 1612*0Sstevel@tonic-gate } 1613*0Sstevel@tonic-gate } 1614*0Sstevel@tonic-gate 1615*0Sstevel@tonic-gate /* 1616*0Sstevel@tonic-gate * zs read service procedure 1617*0Sstevel@tonic-gate */ 1618*0Sstevel@tonic-gate static void 1619*0Sstevel@tonic-gate zsa_rsrv(queue_t *q) 1620*0Sstevel@tonic-gate { 1621*0Sstevel@tonic-gate struct asyncline *za; 1622*0Sstevel@tonic-gate struct zscom *zs; 1623*0Sstevel@tonic-gate 1624*0Sstevel@tonic-gate if (((za = (struct asyncline *)q->q_ptr) != NULL) && 1625*0Sstevel@tonic-gate (za->za_ttycommon.t_cflag & CRTSXOFF)) { 1626*0Sstevel@tonic-gate zs = za->za_common; 1627*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 1628*0Sstevel@tonic-gate ZSSETSOFT(zs); 1629*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 1630*0Sstevel@tonic-gate } 1631*0Sstevel@tonic-gate } 1632*0Sstevel@tonic-gate 1633*0Sstevel@tonic-gate /* 1634*0Sstevel@tonic-gate * Transmitter interrupt service routine. 1635*0Sstevel@tonic-gate * If there's more data to transmit in the current pseudo-DMA block, 1636*0Sstevel@tonic-gate * and the transmitter is ready, send the next character if output 1637*0Sstevel@tonic-gate * is not stopped or draining. 1638*0Sstevel@tonic-gate * Otherwise, queue up a soft interrupt. 1639*0Sstevel@tonic-gate */ 1640*0Sstevel@tonic-gate static void 1641*0Sstevel@tonic-gate zsa_txint(struct zscom *zs) 1642*0Sstevel@tonic-gate { 1643*0Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 1644*0Sstevel@tonic-gate register uchar_t *wr_cur; 1645*0Sstevel@tonic-gate register uchar_t s0; 1646*0Sstevel@tonic-gate 1647*0Sstevel@tonic-gate s0 = SCC_READ0(); 1648*0Sstevel@tonic-gate 1649*0Sstevel@tonic-gate if ((wr_cur = zs->zs_wr_cur) != NULL) { 1650*0Sstevel@tonic-gate if (wr_cur < zs->zs_wr_lim) { 1651*0Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) && 1652*0Sstevel@tonic-gate !(s0 & ZSRR0_CTS)) { 1653*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1654*0Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_RETRANSMIT; 1655*0Sstevel@tonic-gate return; 1656*0Sstevel@tonic-gate } 1657*0Sstevel@tonic-gate SCC_WRITEDATA(*wr_cur++); 1658*0Sstevel@tonic-gate #ifdef ZSA_DEBUG 1659*0Sstevel@tonic-gate za->za_wr++; 1660*0Sstevel@tonic-gate #endif 1661*0Sstevel@tonic-gate zs->zs_wr_cur = wr_cur; 1662*0Sstevel@tonic-gate zs->zs_flags |= ZS_PROGRESS; 1663*0Sstevel@tonic-gate return; 1664*0Sstevel@tonic-gate } else { 1665*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 1666*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 1667*0Sstevel@tonic-gate /* 1668*0Sstevel@tonic-gate * Use the rcv_flags_mask as it is set and 1669*0Sstevel@tonic-gate * test while holding the zs_excl_hi mutex 1670*0Sstevel@tonic-gate */ 1671*0Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT; 1672*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1673*0Sstevel@tonic-gate ZSSETSOFT(zs); 1674*0Sstevel@tonic-gate return; 1675*0Sstevel@tonic-gate } 1676*0Sstevel@tonic-gate } 1677*0Sstevel@tonic-gate 1678*0Sstevel@tonic-gate if (za->za_flowc != '\0' && (!(za->za_flags & ZAS_DRAINING))) { 1679*0Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) && 1680*0Sstevel@tonic-gate !(s0 & ZSRR0_CTS)) { 1681*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1682*0Sstevel@tonic-gate return; 1683*0Sstevel@tonic-gate } 1684*0Sstevel@tonic-gate SCC_WRITEDATA(za->za_flowc); 1685*0Sstevel@tonic-gate za->za_flowc = '\0'; 1686*0Sstevel@tonic-gate return; 1687*0Sstevel@tonic-gate } 1688*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 1689*0Sstevel@tonic-gate /* 1690*0Sstevel@tonic-gate * Set DO_TRANSMIT bit so that the soft interrupt can 1691*0Sstevel@tonic-gate * test it and unset the ZAS_BUSY in za_flags while holding 1692*0Sstevel@tonic-gate * the mutex zs_excl and zs_excl_hi 1693*0Sstevel@tonic-gate */ 1694*0Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT; 1695*0Sstevel@tonic-gate ZSSETSOFT(zs); 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate 1698*0Sstevel@tonic-gate /* 1699*0Sstevel@tonic-gate * External/Status interrupt. 1700*0Sstevel@tonic-gate */ 1701*0Sstevel@tonic-gate static void 1702*0Sstevel@tonic-gate zsa_xsint(struct zscom *zs) 1703*0Sstevel@tonic-gate { 1704*0Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 1705*0Sstevel@tonic-gate register uchar_t s0, x0; 1706*0Sstevel@tonic-gate 1707*0Sstevel@tonic-gate s0 = SCC_READ0(); 1708*0Sstevel@tonic-gate ZSA_R0_LOG(s0); 1709*0Sstevel@tonic-gate x0 = s0 ^ za->za_rr0; 1710*0Sstevel@tonic-gate za->za_rr0 = s0; 1711*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gate /* 1714*0Sstevel@tonic-gate * PPS (Pulse Per Second) support. 1715*0Sstevel@tonic-gate */ 1716*0Sstevel@tonic-gate if (za->za_pps && (x0 & ZSRR0_CD) && (s0 & ZSRR0_CD)) { 1717*0Sstevel@tonic-gate /* 1718*0Sstevel@tonic-gate * This code captures a timestamp at the designated 1719*0Sstevel@tonic-gate * transition of the PPS signal (CD asserted). The 1720*0Sstevel@tonic-gate * code provides a pointer to the timestamp, as well 1721*0Sstevel@tonic-gate * as the hardware counter value at the capture. 1722*0Sstevel@tonic-gate * 1723*0Sstevel@tonic-gate * Note: the kernel has nano based time values while 1724*0Sstevel@tonic-gate * NTP requires micro based, an in-line fast algorithm 1725*0Sstevel@tonic-gate * to convert nsec to usec is used here -- see hrt2ts() 1726*0Sstevel@tonic-gate * in common/os/timers.c for a full description. 1727*0Sstevel@tonic-gate */ 1728*0Sstevel@tonic-gate struct timeval *tvp = &ppsclockev.tv; 1729*0Sstevel@tonic-gate timespec_t ts; 1730*0Sstevel@tonic-gate int nsec, usec; 1731*0Sstevel@tonic-gate 1732*0Sstevel@tonic-gate LED_OFF; 1733*0Sstevel@tonic-gate gethrestime(&ts); 1734*0Sstevel@tonic-gate LED_ON; 1735*0Sstevel@tonic-gate nsec = ts.tv_nsec; 1736*0Sstevel@tonic-gate usec = nsec + (nsec >> 2); 1737*0Sstevel@tonic-gate usec = nsec + (usec >> 1); 1738*0Sstevel@tonic-gate usec = nsec + (usec >> 2); 1739*0Sstevel@tonic-gate usec = nsec + (usec >> 4); 1740*0Sstevel@tonic-gate usec = nsec - (usec >> 3); 1741*0Sstevel@tonic-gate usec = nsec + (usec >> 2); 1742*0Sstevel@tonic-gate usec = nsec + (usec >> 3); 1743*0Sstevel@tonic-gate usec = nsec + (usec >> 4); 1744*0Sstevel@tonic-gate usec = nsec + (usec >> 1); 1745*0Sstevel@tonic-gate usec = nsec + (usec >> 6); 1746*0Sstevel@tonic-gate tvp->tv_usec = usec >> 10; 1747*0Sstevel@tonic-gate tvp->tv_sec = ts.tv_sec; 1748*0Sstevel@tonic-gate 1749*0Sstevel@tonic-gate ++ppsclockev.serial; 1750*0Sstevel@tonic-gate 1751*0Sstevel@tonic-gate /* 1752*0Sstevel@tonic-gate * Because the kernel keeps a high-resolution time, pass the 1753*0Sstevel@tonic-gate * current highres timestamp in tvp and zero in usec. 1754*0Sstevel@tonic-gate */ 1755*0Sstevel@tonic-gate ddi_hardpps(tvp, 0); 1756*0Sstevel@tonic-gate } 1757*0Sstevel@tonic-gate 1758*0Sstevel@tonic-gate ZSA_KICK_RCV; 1759*0Sstevel@tonic-gate 1760*0Sstevel@tonic-gate if ((x0 & ZSRR0_BREAK) && (s0 & ZSRR0_BREAK) == 0) { 1761*0Sstevel@tonic-gate #ifdef SLAVIO_BUG 1762*0Sstevel@tonic-gate /* 1763*0Sstevel@tonic-gate * ZSRR0_BREAK turned off. This means that the break sequence 1764*0Sstevel@tonic-gate * has completed (i.e., the stop bit finally arrived). 1765*0Sstevel@tonic-gate */ 1766*0Sstevel@tonic-gate if ((s0 & ZSRR0_RX_READY) == 0) { 1767*0Sstevel@tonic-gate /* 1768*0Sstevel@tonic-gate * SLAVIO will generate a separate STATUS change 1769*0Sstevel@tonic-gate * interrupt when the break sequence completes. 1770*0Sstevel@tonic-gate * SCC will combine both, taking the higher priority 1771*0Sstevel@tonic-gate * one, the receive. Should still see the ext/stat. 1772*0Sstevel@tonic-gate * bit in REG3 on SCC. If no ext/stat, it must be 1773*0Sstevel@tonic-gate * a SLAVIO. 1774*0Sstevel@tonic-gate */ 1775*0Sstevel@tonic-gate za->za_breakoff = 1; 1776*0Sstevel@tonic-gate } else { 1777*0Sstevel@tonic-gate /* 1778*0Sstevel@tonic-gate * The NUL character in the receiver is part of the 1779*0Sstevel@tonic-gate * break sequence; it is discarded. 1780*0Sstevel@tonic-gate */ 1781*0Sstevel@tonic-gate (void) SCC_READDATA(); /* swallow null */ 1782*0Sstevel@tonic-gate } 1783*0Sstevel@tonic-gate #else /* SLAVIO_BUG */ 1784*0Sstevel@tonic-gate /* 1785*0Sstevel@tonic-gate * ZSRR0_BREAK turned off. This means that the break sequence 1786*0Sstevel@tonic-gate * has completed (i.e., the stop bit finally arrived). The NUL 1787*0Sstevel@tonic-gate * character in the receiver is part of the break sequence; 1788*0Sstevel@tonic-gate * it is discarded. 1789*0Sstevel@tonic-gate */ 1790*0Sstevel@tonic-gate (void) SCC_READDATA(); /* swallow null */ 1791*0Sstevel@tonic-gate #endif /* SLAVIO_BUG */ 1792*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 1793*0Sstevel@tonic-gate 1794*0Sstevel@tonic-gate /* 1795*0Sstevel@tonic-gate * Note: this will cause an abort if a break occurs on 1796*0Sstevel@tonic-gate * the "keyboard device", regardless of whether the 1797*0Sstevel@tonic-gate * "keyboard device" is a real keyboard or just a 1798*0Sstevel@tonic-gate * terminal on a serial line. This permits you to 1799*0Sstevel@tonic-gate * abort a workstation by unplugging the keyboard, 1800*0Sstevel@tonic-gate * even if the normal abort key sequence isn't working. 1801*0Sstevel@tonic-gate */ 1802*0Sstevel@tonic-gate if ((za->za_dev == kbddev) || 1803*0Sstevel@tonic-gate ((za->za_dev == rconsdev) || (za->za_dev == stdindev)) && 1804*0Sstevel@tonic-gate (abort_enable != KIOCABORTALTERNATE)) { 1805*0Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 1806*0Sstevel@tonic-gate /* 1807*0Sstevel@tonic-gate * We just broke into the monitor or debugger, 1808*0Sstevel@tonic-gate * ignore the break in this case so whatever 1809*0Sstevel@tonic-gate * random program that was running doesn't get 1810*0Sstevel@tonic-gate * a SIGINT. 1811*0Sstevel@tonic-gate */ 1812*0Sstevel@tonic-gate return; 1813*0Sstevel@tonic-gate } 1814*0Sstevel@tonic-gate za->za_break = 1; 1815*0Sstevel@tonic-gate } 1816*0Sstevel@tonic-gate 1817*0Sstevel@tonic-gate /* 1818*0Sstevel@tonic-gate * If hardware flow control is enabled, (re)start output 1819*0Sstevel@tonic-gate * when CTS is reasserted. 1820*0Sstevel@tonic-gate */ 1821*0Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) && 1822*0Sstevel@tonic-gate (x0 & ZSRR0_CTS) && (s0 & ZSRR0_CTS) && 1823*0Sstevel@tonic-gate (za->za_rcv_flags_mask & DO_RETRANSMIT)) 1824*0Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT; 1825*0Sstevel@tonic-gate 1826*0Sstevel@tonic-gate za->za_ext = 1; 1827*0Sstevel@tonic-gate ZSSETSOFT(zs); 1828*0Sstevel@tonic-gate } 1829*0Sstevel@tonic-gate 1830*0Sstevel@tonic-gate /* 1831*0Sstevel@tonic-gate * Receive Interrupt 1832*0Sstevel@tonic-gate */ 1833*0Sstevel@tonic-gate static void 1834*0Sstevel@tonic-gate zsa_rxint(struct zscom *zs) 1835*0Sstevel@tonic-gate { 1836*0Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 1837*0Sstevel@tonic-gate register uchar_t c; 1838*0Sstevel@tonic-gate register uchar_t *rd_cur = zs->zs_rd_cur; 1839*0Sstevel@tonic-gate register uchar_t *rd_lim = zs->zs_rd_lim; 1840*0Sstevel@tonic-gate register mblk_t *bp; 1841*0Sstevel@tonic-gate register uint_t fm = za->za_rcv_flags_mask; 1842*0Sstevel@tonic-gate 1843*0Sstevel@tonic-gate 1844*0Sstevel@tonic-gate #ifdef ZSA_DEBUG 1845*0Sstevel@tonic-gate za->za_rd++; 1846*0Sstevel@tonic-gate #endif 1847*0Sstevel@tonic-gate c = (fm >> 16) & (SCC_READDATA()); 1848*0Sstevel@tonic-gate 1849*0Sstevel@tonic-gate /* 1850*0Sstevel@tonic-gate * Check for character break sequence 1851*0Sstevel@tonic-gate */ 1852*0Sstevel@tonic-gate if ((abort_enable == KIOCABORTALTERNATE) && (za->za_dev == rconsdev)) { 1853*0Sstevel@tonic-gate if (abort_charseq_recognize(c)) 1854*0Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 1855*0Sstevel@tonic-gate } 1856*0Sstevel@tonic-gate 1857*0Sstevel@tonic-gate if (!rd_cur) { 1858*0Sstevel@tonic-gate #ifdef SLAVIO_BUG 1859*0Sstevel@tonic-gate /* 1860*0Sstevel@tonic-gate * SLAVIO generates FE for the start of break and 1861*0Sstevel@tonic-gate * during break when parity is set. End of break is 1862*0Sstevel@tonic-gate * detected when the first character is received. 1863*0Sstevel@tonic-gate * This character is always garbage and is thrown away. 1864*0Sstevel@tonic-gate */ 1865*0Sstevel@tonic-gate if (za->za_slav_break) { 1866*0Sstevel@tonic-gate za->za_slav_break = 0; 1867*0Sstevel@tonic-gate za->za_rr0 |= ZSRR0_BREAK; 1868*0Sstevel@tonic-gate zsa_xsint(zs); 1869*0Sstevel@tonic-gate return; 1870*0Sstevel@tonic-gate } 1871*0Sstevel@tonic-gate #endif /* SLAVIO_BUG */ 1872*0Sstevel@tonic-gate 1873*0Sstevel@tonic-gate if (c == 0 && (za->za_rr0 & ZSRR0_BREAK)) { 1874*0Sstevel@tonic-gate /* 1875*0Sstevel@tonic-gate * A break sequence was under way, and a NUL character 1876*0Sstevel@tonic-gate * was received. Discard the NUL character, as it is 1877*0Sstevel@tonic-gate * part of the break sequence; if ZSRR0_BREAK turned 1878*0Sstevel@tonic-gate * off, indicating that the break sequence has com- 1879*0Sstevel@tonic-gate * pleted, call "zsa_xsint" to properly handle the 1880*0Sstevel@tonic-gate * error. It would appear that External/Status 1881*0Sstevel@tonic-gate * interrupts get lost occasionally, so this ensures 1882*0Sstevel@tonic-gate * that one is delivered. 1883*0Sstevel@tonic-gate */ 1884*0Sstevel@tonic-gate c = SCC_READ0(); 1885*0Sstevel@tonic-gate if (!(c & ZSRR0_BREAK)) 1886*0Sstevel@tonic-gate zsa_xsint(zs); 1887*0Sstevel@tonic-gate return; 1888*0Sstevel@tonic-gate } 1889*0Sstevel@tonic-gate 1890*0Sstevel@tonic-gate #ifdef SLAVIO_BUG 1891*0Sstevel@tonic-gate if (c == 0 && za->za_breakoff) { 1892*0Sstevel@tonic-gate /* 1893*0Sstevel@tonic-gate * A break sequence completed, but SLAVIO generates 1894*0Sstevel@tonic-gate * the NULL character interrupt late, so we throw the 1895*0Sstevel@tonic-gate * NULL away now. 1896*0Sstevel@tonic-gate */ 1897*0Sstevel@tonic-gate return; 1898*0Sstevel@tonic-gate } 1899*0Sstevel@tonic-gate 1900*0Sstevel@tonic-gate /* 1901*0Sstevel@tonic-gate * make sure it gets cleared. 1902*0Sstevel@tonic-gate */ 1903*0Sstevel@tonic-gate za->za_breakoff = 0; 1904*0Sstevel@tonic-gate #endif /* SLAVIO_BUG */ 1905*0Sstevel@tonic-gate 1906*0Sstevel@tonic-gate ZSA_KICK_RCV; /* We can have M_BREAK msg */ 1907*0Sstevel@tonic-gate ZSA_ALLOCB(bp); 1908*0Sstevel@tonic-gate if (!bp) { 1909*0Sstevel@tonic-gate za->za_sw_overrun++; 1910*0Sstevel@tonic-gate ZSSETSOFT(zs); 1911*0Sstevel@tonic-gate return; 1912*0Sstevel@tonic-gate } 1913*0Sstevel@tonic-gate za->za_rcvblk = bp; 1914*0Sstevel@tonic-gate zs->zs_rd_cur = rd_cur = bp->b_wptr; 1915*0Sstevel@tonic-gate zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim; 1916*0Sstevel@tonic-gate if (za->za_kick_rcv_id == 0) 1917*0Sstevel@tonic-gate ZSSETSOFT(zs); 1918*0Sstevel@tonic-gate } 1919*0Sstevel@tonic-gate if (c == 0377 && (fm & DO_ESC)) { 1920*0Sstevel@tonic-gate if (rd_lim < rd_cur + 2) { 1921*0Sstevel@tonic-gate ZSA_ALLOCB(bp); 1922*0Sstevel@tonic-gate ZSA_KICK_RCV; 1923*0Sstevel@tonic-gate if (!bp) { 1924*0Sstevel@tonic-gate za->za_sw_overrun++; 1925*0Sstevel@tonic-gate return; 1926*0Sstevel@tonic-gate } 1927*0Sstevel@tonic-gate za->za_rcvblk = bp; 1928*0Sstevel@tonic-gate zs->zs_rd_cur = rd_cur = bp->b_wptr; 1929*0Sstevel@tonic-gate zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim; 1930*0Sstevel@tonic-gate } 1931*0Sstevel@tonic-gate *rd_cur++ = c; 1932*0Sstevel@tonic-gate } 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate 1935*0Sstevel@tonic-gate *rd_cur++ = c; 1936*0Sstevel@tonic-gate zs->zs_rd_cur = rd_cur; 1937*0Sstevel@tonic-gate 1938*0Sstevel@tonic-gate if (rd_cur == rd_lim) { 1939*0Sstevel@tonic-gate ZSA_KICK_RCV; 1940*0Sstevel@tonic-gate } else if ((fm & DO_STOPC) && (c == (fm & 0xff))) { 1941*0Sstevel@tonic-gate za->za_do_kick_rcv_in_softint = 1; 1942*0Sstevel@tonic-gate ZSSETSOFT(zs); 1943*0Sstevel@tonic-gate } 1944*0Sstevel@tonic-gate 1945*0Sstevel@tonic-gate if ((za->za_flags & ZAS_SERVICEIMM) || g_nocluster) { 1946*0Sstevel@tonic-gate /* 1947*0Sstevel@tonic-gate * Send the data up immediately 1948*0Sstevel@tonic-gate */ 1949*0Sstevel@tonic-gate ZSA_KICK_RCV; 1950*0Sstevel@tonic-gate } 1951*0Sstevel@tonic-gate } 1952*0Sstevel@tonic-gate 1953*0Sstevel@tonic-gate /* 1954*0Sstevel@tonic-gate * Special receive condition interrupt handler. 1955*0Sstevel@tonic-gate */ 1956*0Sstevel@tonic-gate static void 1957*0Sstevel@tonic-gate zsa_srint(struct zscom *zs) 1958*0Sstevel@tonic-gate { 1959*0Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 1960*0Sstevel@tonic-gate register short s1; 1961*0Sstevel@tonic-gate register uchar_t c; 1962*0Sstevel@tonic-gate register uchar_t c1; 1963*0Sstevel@tonic-gate register mblk_t *bp = za->za_rcvblk; 1964*0Sstevel@tonic-gate register uchar_t *rd_cur = zs->zs_rd_cur; 1965*0Sstevel@tonic-gate 1966*0Sstevel@tonic-gate SCC_READ(1, s1); 1967*0Sstevel@tonic-gate if (s1 & (ZSRR1_FE | ZSRR1_PE | ZSRR1_DO)) { 1968*0Sstevel@tonic-gate c = SCC_READDATA(); /* swallow bad character */ 1969*0Sstevel@tonic-gate } 1970*0Sstevel@tonic-gate #ifdef SLAVIO_BUG 1971*0Sstevel@tonic-gate /* 1972*0Sstevel@tonic-gate * SLAVIO does not handle breaks properly when parity is enabled. 1973*0Sstevel@tonic-gate * 1974*0Sstevel@tonic-gate * In general, if a null character is received when a framing 1975*0Sstevel@tonic-gate * error occurs then it is a break condition and not a real 1976*0Sstevel@tonic-gate * framing error. The null character must be limited to the 1977*0Sstevel@tonic-gate * number of bits including the parity bit. For example, a 6 1978*0Sstevel@tonic-gate * bit character with parity would be null if the lower 7 bits 1979*0Sstevel@tonic-gate * read from the receive fifo were 0. (The higher order bits are 1980*0Sstevel@tonic-gate * padded with 1 and/or the stop bits.) The only exception to this 1981*0Sstevel@tonic-gate * general rule would be an 8 bit null character with parity being 1982*0Sstevel@tonic-gate * a 1 in the parity bit and a framing error. This exception 1983*0Sstevel@tonic-gate * can be determined by examining the parity error bit in RREG 1. 1984*0Sstevel@tonic-gate * 1985*0Sstevel@tonic-gate * A null character, even parity, 8 bits, no parity error, 1986*0Sstevel@tonic-gate * (0 0000 0000) with framing error is a break condition. 1987*0Sstevel@tonic-gate * 1988*0Sstevel@tonic-gate * A null character, even parity, 8 bits, parity error, 1989*0Sstevel@tonic-gate * (1 0000 0000) with framing error is a framing error. 1990*0Sstevel@tonic-gate * 1991*0Sstevel@tonic-gate * A null character, odd parity, 8 bits, parity error 1992*0Sstevel@tonic-gate * (0 0000 0000) with framing error is a break condition. 1993*0Sstevel@tonic-gate * 1994*0Sstevel@tonic-gate * A null character, odd parity, 8 bits, no parity error, 1995*0Sstevel@tonic-gate * (1 0000 0000) with framing error is a framing error. 1996*0Sstevel@tonic-gate */ 1997*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARENB) { 1998*0Sstevel@tonic-gate switch (za->za_ttycommon.t_cflag & CSIZE) { 1999*0Sstevel@tonic-gate 2000*0Sstevel@tonic-gate case CS5: 2001*0Sstevel@tonic-gate c1 = c & 0x3f; 2002*0Sstevel@tonic-gate break; 2003*0Sstevel@tonic-gate 2004*0Sstevel@tonic-gate case CS6: 2005*0Sstevel@tonic-gate c1 = c & 0x7f; 2006*0Sstevel@tonic-gate break; 2007*0Sstevel@tonic-gate 2008*0Sstevel@tonic-gate case CS7: 2009*0Sstevel@tonic-gate c1 = c & 0xff; 2010*0Sstevel@tonic-gate break; 2011*0Sstevel@tonic-gate 2012*0Sstevel@tonic-gate case CS8: 2013*0Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & PARODD) && 2014*0Sstevel@tonic-gate !(s1 & ZSRR1_PE)) 2015*0Sstevel@tonic-gate c1 = 0xff; 2016*0Sstevel@tonic-gate else if (!(za->za_ttycommon.t_cflag & PARODD) && 2017*0Sstevel@tonic-gate (s1 & ZSRR1_PE)) 2018*0Sstevel@tonic-gate c1 = 0xff; 2019*0Sstevel@tonic-gate else 2020*0Sstevel@tonic-gate c1 = c; 2021*0Sstevel@tonic-gate break; 2022*0Sstevel@tonic-gate } 2023*0Sstevel@tonic-gate 2024*0Sstevel@tonic-gate /* 2025*0Sstevel@tonic-gate * We fake start of break condition. 2026*0Sstevel@tonic-gate */ 2027*0Sstevel@tonic-gate if ((s1 & ZSRR1_FE) && c1 == 0) { 2028*0Sstevel@tonic-gate za->za_slav_break = 1; 2029*0Sstevel@tonic-gate return; 2030*0Sstevel@tonic-gate } 2031*0Sstevel@tonic-gate } 2032*0Sstevel@tonic-gate #endif /* SLAVIO_BUG */ 2033*0Sstevel@tonic-gate 2034*0Sstevel@tonic-gate if (s1 & ZSRR1_PE) { 2035*0Sstevel@tonic-gate 2036*0Sstevel@tonic-gate /* 2037*0Sstevel@tonic-gate * Mark the parity error so zsa_process will 2038*0Sstevel@tonic-gate * notice it and send it up in an M_BREAK 2039*0Sstevel@tonic-gate * message; ldterm will do the actual parity error 2040*0Sstevel@tonic-gate * processing 2041*0Sstevel@tonic-gate */ 2042*0Sstevel@tonic-gate 2043*0Sstevel@tonic-gate if (bp && zs->zs_rd_cur) { /* M_DATA msg */ 2044*0Sstevel@tonic-gate ZSA_KICK_RCV; 2045*0Sstevel@tonic-gate bp = NULL; 2046*0Sstevel@tonic-gate } 2047*0Sstevel@tonic-gate if (!bp) 2048*0Sstevel@tonic-gate ZSA_ALLOCB(bp); 2049*0Sstevel@tonic-gate if (!bp) { 2050*0Sstevel@tonic-gate za->za_sw_overrun++; 2051*0Sstevel@tonic-gate ZSSETSOFT(zs); 2052*0Sstevel@tonic-gate } else { 2053*0Sstevel@tonic-gate za->za_rcvblk = bp; 2054*0Sstevel@tonic-gate zs->zs_rd_cur = rd_cur = bp->b_wptr; 2055*0Sstevel@tonic-gate zs->zs_rd_lim = bp->b_datap->db_lim; 2056*0Sstevel@tonic-gate *rd_cur++ = c; 2057*0Sstevel@tonic-gate zs->zs_rd_cur = rd_cur; 2058*0Sstevel@tonic-gate bp->b_datap->db_type = M_BREAK; 2059*0Sstevel@tonic-gate if (bp->b_datap->db_lim <= rd_cur) 2060*0Sstevel@tonic-gate ZSA_KICK_RCV; 2061*0Sstevel@tonic-gate za->za_do_kick_rcv_in_softint = 1; 2062*0Sstevel@tonic-gate ZSSETSOFT(zs); 2063*0Sstevel@tonic-gate 2064*0Sstevel@tonic-gate } 2065*0Sstevel@tonic-gate } 2066*0Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 2067*0Sstevel@tonic-gate if (s1 & ZSRR1_DO) { 2068*0Sstevel@tonic-gate za->za_hw_overrun++; 2069*0Sstevel@tonic-gate ZSSETSOFT(zs); 2070*0Sstevel@tonic-gate } 2071*0Sstevel@tonic-gate } 2072*0Sstevel@tonic-gate 2073*0Sstevel@tonic-gate /* 2074*0Sstevel@tonic-gate * Process software interrupts (or poll) 2075*0Sstevel@tonic-gate * Crucial points: 2076*0Sstevel@tonic-gate * 3. BUG - breaks are handled "out-of-band" - their relative position 2077*0Sstevel@tonic-gate * among input events is lost, as well as multiple breaks together. 2078*0Sstevel@tonic-gate * This is probably not a problem in practice. 2079*0Sstevel@tonic-gate */ 2080*0Sstevel@tonic-gate static int 2081*0Sstevel@tonic-gate zsa_softint(struct zscom *zs) 2082*0Sstevel@tonic-gate { 2083*0Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 2084*0Sstevel@tonic-gate register uchar_t r0; 2085*0Sstevel@tonic-gate register uchar_t za_kick_active; 2086*0Sstevel@tonic-gate register int m_error; 2087*0Sstevel@tonic-gate register int allocbcount = 0; 2088*0Sstevel@tonic-gate register int do_ttycommon_qfull = 0; 2089*0Sstevel@tonic-gate boolean_t hangup = B_FALSE, unhangup = B_FALSE; 2090*0Sstevel@tonic-gate boolean_t m_break = B_FALSE, wakeup = B_FALSE; 2091*0Sstevel@tonic-gate register queue_t *q; 2092*0Sstevel@tonic-gate register mblk_t *bp; 2093*0Sstevel@tonic-gate register mblk_t *head = NULL, *tail = NULL; 2094*0Sstevel@tonic-gate 2095*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2096*0Sstevel@tonic-gate if (zs->zs_suspended || (zs->zs_flags & ZS_CLOSED)) { 2097*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2098*0Sstevel@tonic-gate return (0); 2099*0Sstevel@tonic-gate } 2100*0Sstevel@tonic-gate q = za->za_ttycommon.t_readq; 2101*0Sstevel@tonic-gate if (za->za_flags & ZAS_WOPEN && !q) { 2102*0Sstevel@tonic-gate if (za->za_ext) { 2103*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2104*0Sstevel@tonic-gate r0 = SCC_READ0(); 2105*0Sstevel@tonic-gate za->za_ext = 0; 2106*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2107*0Sstevel@tonic-gate /* 2108*0Sstevel@tonic-gate * carrier up? 2109*0Sstevel@tonic-gate */ 2110*0Sstevel@tonic-gate if ((r0 & ZSRR0_CD) || 2111*0Sstevel@tonic-gate (za->za_ttycommon.t_flags & TS_SOFTCAR)) { 2112*0Sstevel@tonic-gate /* 2113*0Sstevel@tonic-gate * carrier present 2114*0Sstevel@tonic-gate */ 2115*0Sstevel@tonic-gate if ((za->za_flags & ZAS_CARR_ON) == 0) { 2116*0Sstevel@tonic-gate za->za_flags |= ZAS_CARR_ON; 2117*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2118*0Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 2119*0Sstevel@tonic-gate return (0); 2120*0Sstevel@tonic-gate } 2121*0Sstevel@tonic-gate } 2122*0Sstevel@tonic-gate } 2123*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2124*0Sstevel@tonic-gate return (0); 2125*0Sstevel@tonic-gate } 2126*0Sstevel@tonic-gate q = za->za_ttycommon.t_readq; 2127*0Sstevel@tonic-gate if (!q) { 2128*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2129*0Sstevel@tonic-gate return (0); 2130*0Sstevel@tonic-gate } 2131*0Sstevel@tonic-gate 2132*0Sstevel@tonic-gate m_error = za->za_m_error; 2133*0Sstevel@tonic-gate za->za_m_error = 0; 2134*0Sstevel@tonic-gate 2135*0Sstevel@tonic-gate if (za->za_do_kick_rcv_in_softint) { 2136*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2137*0Sstevel@tonic-gate ZSA_KICK_RCV; 2138*0Sstevel@tonic-gate za->za_do_kick_rcv_in_softint = 0; 2139*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2140*0Sstevel@tonic-gate } 2141*0Sstevel@tonic-gate 2142*0Sstevel@tonic-gate za_kick_active = za->za_kick_active; 2143*0Sstevel@tonic-gate 2144*0Sstevel@tonic-gate while (!za_kick_active) { 2145*0Sstevel@tonic-gate ZSA_SEEQ(bp); 2146*0Sstevel@tonic-gate if (!bp) 2147*0Sstevel@tonic-gate break; 2148*0Sstevel@tonic-gate 2149*0Sstevel@tonic-gate allocbcount++; 2150*0Sstevel@tonic-gate 2151*0Sstevel@tonic-gate if (bp->b_datap->db_type <= QPCTL) { 2152*0Sstevel@tonic-gate if (!(canputnext(q))) { 2153*0Sstevel@tonic-gate if (za->za_grace_flow_control >= 2154*0Sstevel@tonic-gate zsa_grace_flow_control) { 2155*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { 2156*0Sstevel@tonic-gate allocbcount--; 2157*0Sstevel@tonic-gate break; 2158*0Sstevel@tonic-gate } 2159*0Sstevel@tonic-gate ZSA_GETQ(bp); 2160*0Sstevel@tonic-gate freemsg(bp); 2161*0Sstevel@tonic-gate do_ttycommon_qfull = 1; 2162*0Sstevel@tonic-gate continue; 2163*0Sstevel@tonic-gate } else 2164*0Sstevel@tonic-gate za->za_grace_flow_control++; 2165*0Sstevel@tonic-gate } else 2166*0Sstevel@tonic-gate za->za_grace_flow_control = 0; 2167*0Sstevel@tonic-gate } 2168*0Sstevel@tonic-gate ZSA_GETQ(bp); 2169*0Sstevel@tonic-gate if (!head) { 2170*0Sstevel@tonic-gate head = bp; 2171*0Sstevel@tonic-gate } else { 2172*0Sstevel@tonic-gate if (!tail) 2173*0Sstevel@tonic-gate tail = head; 2174*0Sstevel@tonic-gate tail->b_next = bp; 2175*0Sstevel@tonic-gate tail = bp; 2176*0Sstevel@tonic-gate } 2177*0Sstevel@tonic-gate } 2178*0Sstevel@tonic-gate 2179*0Sstevel@tonic-gate if (allocbcount) 2180*0Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount); 2181*0Sstevel@tonic-gate 2182*0Sstevel@tonic-gate if (za->za_ext) { 2183*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2184*0Sstevel@tonic-gate r0 = SCC_READ0(); 2185*0Sstevel@tonic-gate za->za_ext = 0; 2186*0Sstevel@tonic-gate /* 2187*0Sstevel@tonic-gate * carrier up? 2188*0Sstevel@tonic-gate */ 2189*0Sstevel@tonic-gate if ((r0 & ZSRR0_CD) || 2190*0Sstevel@tonic-gate (za->za_ttycommon.t_flags & TS_SOFTCAR)) { 2191*0Sstevel@tonic-gate /* 2192*0Sstevel@tonic-gate * carrier present 2193*0Sstevel@tonic-gate */ 2194*0Sstevel@tonic-gate if ((za->za_flags & ZAS_CARR_ON) == 0) { 2195*0Sstevel@tonic-gate za->za_flags |= ZAS_CARR_ON; 2196*0Sstevel@tonic-gate unhangup = B_TRUE; 2197*0Sstevel@tonic-gate wakeup = B_TRUE; 2198*0Sstevel@tonic-gate } 2199*0Sstevel@tonic-gate } else { 2200*0Sstevel@tonic-gate if ((za->za_flags & ZAS_CARR_ON) && 2201*0Sstevel@tonic-gate !(za->za_ttycommon.t_cflag & CLOCAL)) { 2202*0Sstevel@tonic-gate /* 2203*0Sstevel@tonic-gate * Carrier went away. 2204*0Sstevel@tonic-gate * Drop DTR, abort any output in progress, 2205*0Sstevel@tonic-gate * indicate that output is not stopped, and 2206*0Sstevel@tonic-gate * send a hangup notification upstream. 2207*0Sstevel@tonic-gate */ 2208*0Sstevel@tonic-gate (void) zsmctl(zs, ZSWR5_DTR, DMBIC); 2209*0Sstevel@tonic-gate if ((za->za_flags & ZAS_BUSY) && 2210*0Sstevel@tonic-gate (zs->zs_wr_cur != NULL)) { 2211*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 2212*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 2213*0Sstevel@tonic-gate } 2214*0Sstevel@tonic-gate hangup = B_TRUE; 2215*0Sstevel@tonic-gate wakeup = B_TRUE; 2216*0Sstevel@tonic-gate za->za_flags &= ~(ZAS_STOPPED | ZAS_CARR_ON | 2217*0Sstevel@tonic-gate ZAS_BUSY); 2218*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~(DO_TRANSMIT | 2219*0Sstevel@tonic-gate DO_RETRANSMIT); 2220*0Sstevel@tonic-gate } 2221*0Sstevel@tonic-gate } 2222*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2223*0Sstevel@tonic-gate if (hangup && (bp = za->za_xmitblk) != NULL) { 2224*0Sstevel@tonic-gate za->za_xmitblk = NULL; 2225*0Sstevel@tonic-gate freeb(bp); 2226*0Sstevel@tonic-gate } 2227*0Sstevel@tonic-gate } 2228*0Sstevel@tonic-gate 2229*0Sstevel@tonic-gate if (za->za_break != 0) { 2230*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2231*0Sstevel@tonic-gate r0 = SCC_READ0(); 2232*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2233*0Sstevel@tonic-gate if ((r0 & ZSRR0_BREAK) == 0) { 2234*0Sstevel@tonic-gate za->za_break = 0; 2235*0Sstevel@tonic-gate m_break = B_TRUE; 2236*0Sstevel@tonic-gate } 2237*0Sstevel@tonic-gate } 2238*0Sstevel@tonic-gate 2239*0Sstevel@tonic-gate /* 2240*0Sstevel@tonic-gate * If a transmission has finished, indicate that it's 2241*0Sstevel@tonic-gate * finished, and start that line up again. 2242*0Sstevel@tonic-gate */ 2243*0Sstevel@tonic-gate 2244*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2245*0Sstevel@tonic-gate if (za->za_rcv_flags_mask & DO_TRANSMIT) { 2246*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_TRANSMIT; 2247*0Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 2248*0Sstevel@tonic-gate 2249*0Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) && 2250*0Sstevel@tonic-gate (za->za_rcv_flags_mask & DO_RETRANSMIT) && 2251*0Sstevel@tonic-gate zs->zs_wr_cur) 2252*0Sstevel@tonic-gate bp = NULL; 2253*0Sstevel@tonic-gate else { 2254*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 2255*0Sstevel@tonic-gate bp = za->za_xmitblk; 2256*0Sstevel@tonic-gate za->za_xmitblk = 0; 2257*0Sstevel@tonic-gate } 2258*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2259*0Sstevel@tonic-gate if (bp) 2260*0Sstevel@tonic-gate freemsg(bp); 2261*0Sstevel@tonic-gate zsa_start(zs); 2262*0Sstevel@tonic-gate /* if we didn't start anything, then notify waiters */ 2263*0Sstevel@tonic-gate if (!(za->za_flags & ZAS_BUSY)) 2264*0Sstevel@tonic-gate wakeup = B_TRUE; 2265*0Sstevel@tonic-gate } else { 2266*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2267*0Sstevel@tonic-gate } 2268*0Sstevel@tonic-gate 2269*0Sstevel@tonic-gate 2270*0Sstevel@tonic-gate /* 2271*0Sstevel@tonic-gate * A note about these overrun bits: all they do is *tell* someone 2272*0Sstevel@tonic-gate * about an error- They do not track multiple errors. In fact, 2273*0Sstevel@tonic-gate * you could consider them latched register bits if you like. 2274*0Sstevel@tonic-gate * We are only interested in printing the error message once for 2275*0Sstevel@tonic-gate * any cluster of overrun errrors. 2276*0Sstevel@tonic-gate */ 2277*0Sstevel@tonic-gate if ((!za->za_kick_rcv_id) && (zs->zs_rd_cur || za_kick_active)) { 2278*0Sstevel@tonic-gate if (g_zsticks) 2279*0Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs, g_zsticks); 2280*0Sstevel@tonic-gate else 2281*0Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs, 2282*0Sstevel@tonic-gate zsticks[SPEED(za->za_ttycommon.t_cflag)]); 2283*0Sstevel@tonic-gate za->za_kick_rcv_count = ZA_KICK_RCV_COUNT; 2284*0Sstevel@tonic-gate } 2285*0Sstevel@tonic-gate za->za_soft_active = 1; 2286*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2287*0Sstevel@tonic-gate 2288*0Sstevel@tonic-gate if (!hangup && do_ttycommon_qfull) { 2289*0Sstevel@tonic-gate ttycommon_qfull(&za->za_ttycommon, q); 2290*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2291*0Sstevel@tonic-gate zsa_start(zs); 2292*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2293*0Sstevel@tonic-gate } 2294*0Sstevel@tonic-gate 2295*0Sstevel@tonic-gate if (za->za_hw_overrun > 10) { 2296*0Sstevel@tonic-gate cmn_err(CE_NOTE, "zs%d: silo overflow\n", UNIT(za->za_dev)); 2297*0Sstevel@tonic-gate za->za_hw_overrun = 0; 2298*0Sstevel@tonic-gate } 2299*0Sstevel@tonic-gate 2300*0Sstevel@tonic-gate if (za->za_sw_overrun > 10) { 2301*0Sstevel@tonic-gate cmn_err(CE_NOTE, "zs%d:ring buffer overflow\n", 2302*0Sstevel@tonic-gate UNIT(za->za_dev)); 2303*0Sstevel@tonic-gate za->za_sw_overrun = 0; 2304*0Sstevel@tonic-gate } 2305*0Sstevel@tonic-gate 2306*0Sstevel@tonic-gate if (unhangup) 2307*0Sstevel@tonic-gate (void) putnextctl(q, M_UNHANGUP); 2308*0Sstevel@tonic-gate 2309*0Sstevel@tonic-gate if (m_break) 2310*0Sstevel@tonic-gate (void) putnextctl(q, M_BREAK); 2311*0Sstevel@tonic-gate 2312*0Sstevel@tonic-gate while (head) { 2313*0Sstevel@tonic-gate if (!tail) { 2314*0Sstevel@tonic-gate putnext(q, head); 2315*0Sstevel@tonic-gate break; 2316*0Sstevel@tonic-gate } 2317*0Sstevel@tonic-gate bp = head; 2318*0Sstevel@tonic-gate head = head->b_next; 2319*0Sstevel@tonic-gate bp->b_next = NULL; 2320*0Sstevel@tonic-gate putnext(q, bp); 2321*0Sstevel@tonic-gate } 2322*0Sstevel@tonic-gate 2323*0Sstevel@tonic-gate if (hangup) { 2324*0Sstevel@tonic-gate int flushflag; 2325*0Sstevel@tonic-gate 2326*0Sstevel@tonic-gate /* 2327*0Sstevel@tonic-gate * If we're in the midst of close, then flush everything. Don't 2328*0Sstevel@tonic-gate * leave stale ioctls lying about. 2329*0Sstevel@tonic-gate */ 2330*0Sstevel@tonic-gate flushflag = (zs->zs_flags & ZS_CLOSING) ? FLUSHALL : FLUSHDATA; 2331*0Sstevel@tonic-gate flushq(za->za_ttycommon.t_writeq, flushflag); 2332*0Sstevel@tonic-gate (void) putnextctl(q, M_HANGUP); 2333*0Sstevel@tonic-gate } 2334*0Sstevel@tonic-gate 2335*0Sstevel@tonic-gate if (m_error) 2336*0Sstevel@tonic-gate (void) putnextctl1(q, M_ERROR, m_error); 2337*0Sstevel@tonic-gate 2338*0Sstevel@tonic-gate za->za_soft_active = 0; 2339*0Sstevel@tonic-gate 2340*0Sstevel@tonic-gate if (wakeup || (zs->zs_flags & ZS_CLOSED)) 2341*0Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 2342*0Sstevel@tonic-gate 2343*0Sstevel@tonic-gate return (0); 2344*0Sstevel@tonic-gate } 2345*0Sstevel@tonic-gate 2346*0Sstevel@tonic-gate /* 2347*0Sstevel@tonic-gate * Start output on a line, unless it's busy, frozen, or otherwise. 2348*0Sstevel@tonic-gate */ 2349*0Sstevel@tonic-gate static void 2350*0Sstevel@tonic-gate zsa_start(struct zscom *zs) 2351*0Sstevel@tonic-gate { 2352*0Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 2353*0Sstevel@tonic-gate register int cc; 2354*0Sstevel@tonic-gate register queue_t *q; 2355*0Sstevel@tonic-gate register mblk_t *bp; 2356*0Sstevel@tonic-gate uchar_t *rptr, *wptr; 2357*0Sstevel@tonic-gate 2358*0Sstevel@tonic-gate /* 2359*0Sstevel@tonic-gate * If the chip is busy (i.e., we're waiting for a break timeout 2360*0Sstevel@tonic-gate * to expire, or for the current transmission to finish, or for 2361*0Sstevel@tonic-gate * output to finish draining from chip), don't grab anything new. 2362*0Sstevel@tonic-gate */ 2363*0Sstevel@tonic-gate if ((za->za_flags & (ZAS_BREAK|ZAS_BUSY|ZAS_DRAINING)) || 2364*0Sstevel@tonic-gate zs->zs_suspended) 2365*0Sstevel@tonic-gate return; 2366*0Sstevel@tonic-gate 2367*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) { 2368*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2369*0Sstevel@tonic-gate if (za->za_rcv_flags_mask & DO_RETRANSMIT) { 2370*0Sstevel@tonic-gate rptr = zs->zs_wr_cur; 2371*0Sstevel@tonic-gate wptr = zs->zs_wr_lim; 2372*0Sstevel@tonic-gate goto zsa_start_retransmit; 2373*0Sstevel@tonic-gate 2374*0Sstevel@tonic-gate } 2375*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2376*0Sstevel@tonic-gate } 2377*0Sstevel@tonic-gate 2378*0Sstevel@tonic-gate /* 2379*0Sstevel@tonic-gate * If we have a flow-control character to transmit, do it now. 2380*0Sstevel@tonic-gate */ 2381*0Sstevel@tonic-gate if (za->za_flowc != '\0') { 2382*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2383*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) { 2384*0Sstevel@tonic-gate if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) != 2385*0Sstevel@tonic-gate (ZSRR0_CTS|ZSRR0_TX_READY)) { 2386*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2387*0Sstevel@tonic-gate return; 2388*0Sstevel@tonic-gate } 2389*0Sstevel@tonic-gate } else if (!(SCC_READ0() & ZSRR0_TX_READY)) { 2390*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2391*0Sstevel@tonic-gate return; 2392*0Sstevel@tonic-gate } 2393*0Sstevel@tonic-gate 2394*0Sstevel@tonic-gate ZSDELAY(); 2395*0Sstevel@tonic-gate SCC_WRITEDATA(za->za_flowc); 2396*0Sstevel@tonic-gate za->za_flowc = '\0'; 2397*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2398*0Sstevel@tonic-gate return; 2399*0Sstevel@tonic-gate } 2400*0Sstevel@tonic-gate 2401*0Sstevel@tonic-gate /* 2402*0Sstevel@tonic-gate * If we're waiting for a delay timeout to expire, don't grab 2403*0Sstevel@tonic-gate * anything new. 2404*0Sstevel@tonic-gate */ 2405*0Sstevel@tonic-gate if (za->za_flags & ZAS_DELAY) 2406*0Sstevel@tonic-gate return; 2407*0Sstevel@tonic-gate 2408*0Sstevel@tonic-gate if ((q = za->za_ttycommon.t_writeq) == NULL) 2409*0Sstevel@tonic-gate return; /* not attached to a stream */ 2410*0Sstevel@tonic-gate 2411*0Sstevel@tonic-gate zsa_start_again: 2412*0Sstevel@tonic-gate for (;;) { 2413*0Sstevel@tonic-gate if ((bp = getq(q)) == NULL) 2414*0Sstevel@tonic-gate return; /* no data to transmit */ 2415*0Sstevel@tonic-gate 2416*0Sstevel@tonic-gate /* 2417*0Sstevel@tonic-gate * We have a message block to work on. 2418*0Sstevel@tonic-gate * Check whether it's a break, a delay, or an ioctl (the latter 2419*0Sstevel@tonic-gate * occurs if the ioctl in question was waiting for the output 2420*0Sstevel@tonic-gate * to drain). If it's one of those, process it immediately. 2421*0Sstevel@tonic-gate */ 2422*0Sstevel@tonic-gate switch (bp->b_datap->db_type) { 2423*0Sstevel@tonic-gate 2424*0Sstevel@tonic-gate case M_BREAK: 2425*0Sstevel@tonic-gate /* 2426*0Sstevel@tonic-gate * Set the break bit, and arrange for "zsa_restart" 2427*0Sstevel@tonic-gate * to be called in 1/4 second; it will turn the 2428*0Sstevel@tonic-gate * break bit off, and call "zsa_start" to grab 2429*0Sstevel@tonic-gate * the next message. 2430*0Sstevel@tonic-gate */ 2431*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2432*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_BREAK); 2433*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2434*0Sstevel@tonic-gate if (!za->za_zsa_restart_id) { 2435*0Sstevel@tonic-gate za->za_zsa_restart_id = 2436*0Sstevel@tonic-gate timeout(zsa_restart, zs, hz/4); 2437*0Sstevel@tonic-gate } 2438*0Sstevel@tonic-gate za->za_flags |= ZAS_BREAK; 2439*0Sstevel@tonic-gate freemsg(bp); 2440*0Sstevel@tonic-gate return; /* wait for this to finish */ 2441*0Sstevel@tonic-gate 2442*0Sstevel@tonic-gate case M_DELAY: 2443*0Sstevel@tonic-gate /* 2444*0Sstevel@tonic-gate * Arrange for "zsa_restart" to be called when the 2445*0Sstevel@tonic-gate * delay expires; it will turn MTS_DELAY off, 2446*0Sstevel@tonic-gate * and call "zsa_start" to grab the next message. 2447*0Sstevel@tonic-gate */ 2448*0Sstevel@tonic-gate if (! za->za_zsa_restart_id) { 2449*0Sstevel@tonic-gate za->za_zsa_restart_id = timeout(zsa_restart, 2450*0Sstevel@tonic-gate zs, 2451*0Sstevel@tonic-gate (int)(*(unsigned char *)bp->b_rptr + 6)); 2452*0Sstevel@tonic-gate } 2453*0Sstevel@tonic-gate za->za_flags |= ZAS_DELAY; 2454*0Sstevel@tonic-gate freemsg(bp); 2455*0Sstevel@tonic-gate return; /* wait for this to finish */ 2456*0Sstevel@tonic-gate 2457*0Sstevel@tonic-gate case M_IOCTL: 2458*0Sstevel@tonic-gate /* 2459*0Sstevel@tonic-gate * This ioctl was waiting for the output ahead of 2460*0Sstevel@tonic-gate * it to drain; obviously, it has. Do it, and 2461*0Sstevel@tonic-gate * then grab the next message after it. 2462*0Sstevel@tonic-gate */ 2463*0Sstevel@tonic-gate zsa_ioctl(za, q, bp); 2464*0Sstevel@tonic-gate continue; 2465*0Sstevel@tonic-gate default: /* M_DATA */ 2466*0Sstevel@tonic-gate goto zsa_start_transmit; 2467*0Sstevel@tonic-gate } 2468*0Sstevel@tonic-gate 2469*0Sstevel@tonic-gate } 2470*0Sstevel@tonic-gate zsa_start_transmit: 2471*0Sstevel@tonic-gate /* 2472*0Sstevel@tonic-gate * We have data to transmit. If output is stopped, put 2473*0Sstevel@tonic-gate * it back and try again later. 2474*0Sstevel@tonic-gate */ 2475*0Sstevel@tonic-gate if (za->za_flags & ZAS_STOPPED) { 2476*0Sstevel@tonic-gate (void) putbq(q, bp); 2477*0Sstevel@tonic-gate return; 2478*0Sstevel@tonic-gate } 2479*0Sstevel@tonic-gate 2480*0Sstevel@tonic-gate za->za_xmitblk = bp; 2481*0Sstevel@tonic-gate rptr = bp->b_rptr; 2482*0Sstevel@tonic-gate wptr = bp->b_wptr; 2483*0Sstevel@tonic-gate cc = wptr - rptr; 2484*0Sstevel@tonic-gate bp = bp->b_cont; 2485*0Sstevel@tonic-gate if (bp != NULL) { 2486*0Sstevel@tonic-gate za->za_xmitblk->b_cont = NULL; 2487*0Sstevel@tonic-gate (void) putbq(q, bp); /* not done with this message yet */ 2488*0Sstevel@tonic-gate } 2489*0Sstevel@tonic-gate 2490*0Sstevel@tonic-gate if (rptr >= wptr) { 2491*0Sstevel@tonic-gate freeb(za->za_xmitblk); 2492*0Sstevel@tonic-gate za->za_xmitblk = NULL; 2493*0Sstevel@tonic-gate goto zsa_start_again; 2494*0Sstevel@tonic-gate } 2495*0Sstevel@tonic-gate 2496*0Sstevel@tonic-gate /* 2497*0Sstevel@tonic-gate * In 5-bit mode, the high order bits are used 2498*0Sstevel@tonic-gate * to indicate character sizes less than five, 2499*0Sstevel@tonic-gate * so we need to explicitly mask before transmitting 2500*0Sstevel@tonic-gate */ 2501*0Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CSIZE) == CS5) { 2502*0Sstevel@tonic-gate register unsigned char *p = rptr; 2503*0Sstevel@tonic-gate register int cnt = cc; 2504*0Sstevel@tonic-gate 2505*0Sstevel@tonic-gate while (cnt--) 2506*0Sstevel@tonic-gate *p++ &= (unsigned char) 0x1f; 2507*0Sstevel@tonic-gate } 2508*0Sstevel@tonic-gate 2509*0Sstevel@tonic-gate /* 2510*0Sstevel@tonic-gate * Set up this block for pseudo-DMA. 2511*0Sstevel@tonic-gate */ 2512*0Sstevel@tonic-gate 2513*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2514*0Sstevel@tonic-gate zs->zs_wr_cur = rptr; 2515*0Sstevel@tonic-gate zs->zs_wr_lim = wptr; 2516*0Sstevel@tonic-gate 2517*0Sstevel@tonic-gate zsa_start_retransmit: 2518*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_TRANSMIT; 2519*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) { 2520*0Sstevel@tonic-gate if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) != 2521*0Sstevel@tonic-gate (ZSRR0_CTS|ZSRR0_TX_READY)) { 2522*0Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_RETRANSMIT; 2523*0Sstevel@tonic-gate za->za_flags |= ZAS_BUSY; 2524*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2525*0Sstevel@tonic-gate return; 2526*0Sstevel@tonic-gate } 2527*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 2528*0Sstevel@tonic-gate } else if (!(SCC_READ0() & ZSRR0_TX_READY)) { 2529*0Sstevel@tonic-gate za->za_flags |= ZAS_BUSY; 2530*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2531*0Sstevel@tonic-gate return; 2532*0Sstevel@tonic-gate } 2533*0Sstevel@tonic-gate /* 2534*0Sstevel@tonic-gate * If the transmitter is ready, shove the first 2535*0Sstevel@tonic-gate * character out. 2536*0Sstevel@tonic-gate */ 2537*0Sstevel@tonic-gate ZSDELAY(); 2538*0Sstevel@tonic-gate SCC_WRITEDATA(*rptr++); 2539*0Sstevel@tonic-gate #ifdef ZSA_DEBUG 2540*0Sstevel@tonic-gate za->za_wr++; 2541*0Sstevel@tonic-gate #endif 2542*0Sstevel@tonic-gate zs->zs_wr_cur = rptr; 2543*0Sstevel@tonic-gate za->za_flags |= ZAS_BUSY; 2544*0Sstevel@tonic-gate zs->zs_flags |= ZS_PROGRESS; 2545*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2546*0Sstevel@tonic-gate } 2547*0Sstevel@tonic-gate 2548*0Sstevel@tonic-gate /* 2549*0Sstevel@tonic-gate * Restart output on a line after a delay or break timer expired. 2550*0Sstevel@tonic-gate */ 2551*0Sstevel@tonic-gate static void 2552*0Sstevel@tonic-gate zsa_restart(void *arg) 2553*0Sstevel@tonic-gate { 2554*0Sstevel@tonic-gate struct zscom *zs = arg; 2555*0Sstevel@tonic-gate struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 2556*0Sstevel@tonic-gate 2557*0Sstevel@tonic-gate /* 2558*0Sstevel@tonic-gate * If break timer expired, turn off the break bit. 2559*0Sstevel@tonic-gate */ 2560*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2561*0Sstevel@tonic-gate if (!za->za_zsa_restart_id) { 2562*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2563*0Sstevel@tonic-gate return; 2564*0Sstevel@tonic-gate } 2565*0Sstevel@tonic-gate za->za_zsa_restart_id = 0; 2566*0Sstevel@tonic-gate if (za->za_flags & ZAS_BREAK) { 2567*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2568*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK); 2569*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2570*0Sstevel@tonic-gate } 2571*0Sstevel@tonic-gate za->za_flags &= ~(ZAS_DELAY|ZAS_BREAK); 2572*0Sstevel@tonic-gate if (za->za_ttycommon.t_writeq != NULL) 2573*0Sstevel@tonic-gate zsa_start(zs); 2574*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2575*0Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 2576*0Sstevel@tonic-gate } 2577*0Sstevel@tonic-gate 2578*0Sstevel@tonic-gate /* 2579*0Sstevel@tonic-gate * See if the receiver has any data after zs_tick delay 2580*0Sstevel@tonic-gate */ 2581*0Sstevel@tonic-gate static void 2582*0Sstevel@tonic-gate zsa_kick_rcv(void *arg) 2583*0Sstevel@tonic-gate { 2584*0Sstevel@tonic-gate struct zscom *zs = arg; 2585*0Sstevel@tonic-gate struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 2586*0Sstevel@tonic-gate queue_t *q; 2587*0Sstevel@tonic-gate int tmp; 2588*0Sstevel@tonic-gate mblk_t *mp; 2589*0Sstevel@tonic-gate uchar_t za_soft_active, za_kick_active; 2590*0Sstevel@tonic-gate int allocbcount = 0; 2591*0Sstevel@tonic-gate int do_ttycommon_qfull = 0; 2592*0Sstevel@tonic-gate mblk_t *head = NULL, *tail = NULL; 2593*0Sstevel@tonic-gate 2594*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2595*0Sstevel@tonic-gate if (za->za_kick_rcv_id == 0 || (zs->zs_flags & ZS_CLOSED)) { 2596*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2597*0Sstevel@tonic-gate return; 2598*0Sstevel@tonic-gate } 2599*0Sstevel@tonic-gate za_soft_active = za->za_soft_active; 2600*0Sstevel@tonic-gate za_kick_active = za->za_kick_active; 2601*0Sstevel@tonic-gate q = za->za_ttycommon.t_readq; 2602*0Sstevel@tonic-gate if (!q) { 2603*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2604*0Sstevel@tonic-gate return; 2605*0Sstevel@tonic-gate } 2606*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2607*0Sstevel@tonic-gate if (zs->zs_rd_cur) { 2608*0Sstevel@tonic-gate ZSA_KICK_RCV; 2609*0Sstevel@tonic-gate za->za_kick_rcv_count = tmp = ZA_KICK_RCV_COUNT; 2610*0Sstevel@tonic-gate } else 2611*0Sstevel@tonic-gate tmp = --za->za_kick_rcv_count; 2612*0Sstevel@tonic-gate if (tmp > 0 || za_soft_active || za_kick_active) { 2613*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2614*0Sstevel@tonic-gate if (g_zsticks) 2615*0Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv, 2616*0Sstevel@tonic-gate zs, g_zsticks); 2617*0Sstevel@tonic-gate else 2618*0Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv, 2619*0Sstevel@tonic-gate zs, zsticks[SPEED(za->za_ttycommon.t_cflag)]); 2620*0Sstevel@tonic-gate if (za_soft_active || za_kick_active) { 2621*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2622*0Sstevel@tonic-gate return; 2623*0Sstevel@tonic-gate } 2624*0Sstevel@tonic-gate } else { 2625*0Sstevel@tonic-gate za->za_kick_rcv_id = 0; 2626*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2627*0Sstevel@tonic-gate } 2628*0Sstevel@tonic-gate 2629*0Sstevel@tonic-gate 2630*0Sstevel@tonic-gate for (;;) { 2631*0Sstevel@tonic-gate ZSA_SEEQ(mp); 2632*0Sstevel@tonic-gate if (!mp) 2633*0Sstevel@tonic-gate break; 2634*0Sstevel@tonic-gate 2635*0Sstevel@tonic-gate allocbcount++; 2636*0Sstevel@tonic-gate 2637*0Sstevel@tonic-gate if (mp->b_datap->db_type <= QPCTL) { 2638*0Sstevel@tonic-gate if (!(canputnext(q))) { 2639*0Sstevel@tonic-gate if (za->za_grace_flow_control >= 2640*0Sstevel@tonic-gate zsa_grace_flow_control) { 2641*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { 2642*0Sstevel@tonic-gate allocbcount--; 2643*0Sstevel@tonic-gate break; 2644*0Sstevel@tonic-gate } 2645*0Sstevel@tonic-gate ZSA_GETQ(mp); 2646*0Sstevel@tonic-gate freemsg(mp); 2647*0Sstevel@tonic-gate do_ttycommon_qfull = 1; 2648*0Sstevel@tonic-gate continue; 2649*0Sstevel@tonic-gate } else 2650*0Sstevel@tonic-gate za->za_grace_flow_control++; 2651*0Sstevel@tonic-gate } else 2652*0Sstevel@tonic-gate za->za_grace_flow_control = 0; 2653*0Sstevel@tonic-gate } 2654*0Sstevel@tonic-gate ZSA_GETQ(mp); 2655*0Sstevel@tonic-gate if (!head) { 2656*0Sstevel@tonic-gate head = mp; 2657*0Sstevel@tonic-gate } else { 2658*0Sstevel@tonic-gate if (!tail) 2659*0Sstevel@tonic-gate tail = head; 2660*0Sstevel@tonic-gate tail->b_next = mp; 2661*0Sstevel@tonic-gate tail = mp; 2662*0Sstevel@tonic-gate } 2663*0Sstevel@tonic-gate } 2664*0Sstevel@tonic-gate 2665*0Sstevel@tonic-gate if (allocbcount) 2666*0Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount); 2667*0Sstevel@tonic-gate 2668*0Sstevel@tonic-gate za->za_kick_active = 1; 2669*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2670*0Sstevel@tonic-gate 2671*0Sstevel@tonic-gate if (do_ttycommon_qfull) { 2672*0Sstevel@tonic-gate ttycommon_qfull(&za->za_ttycommon, q); 2673*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2674*0Sstevel@tonic-gate zsa_start(zs); 2675*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2676*0Sstevel@tonic-gate } 2677*0Sstevel@tonic-gate 2678*0Sstevel@tonic-gate while (head) { 2679*0Sstevel@tonic-gate if (!tail) { 2680*0Sstevel@tonic-gate putnext(q, head); 2681*0Sstevel@tonic-gate break; 2682*0Sstevel@tonic-gate } 2683*0Sstevel@tonic-gate mp = head; 2684*0Sstevel@tonic-gate head = head->b_next; 2685*0Sstevel@tonic-gate mp->b_next = NULL; 2686*0Sstevel@tonic-gate putnext(q, mp); 2687*0Sstevel@tonic-gate 2688*0Sstevel@tonic-gate } 2689*0Sstevel@tonic-gate za->za_kick_active = 0; 2690*0Sstevel@tonic-gate 2691*0Sstevel@tonic-gate if (zs->zs_flags & ZS_CLOSED) 2692*0Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 2693*0Sstevel@tonic-gate } 2694*0Sstevel@tonic-gate 2695*0Sstevel@tonic-gate /* 2696*0Sstevel@tonic-gate * Retry an "ioctl", now that "bufcall" claims we may be able to allocate 2697*0Sstevel@tonic-gate * the buffer we need. 2698*0Sstevel@tonic-gate */ 2699*0Sstevel@tonic-gate static void 2700*0Sstevel@tonic-gate zsa_reioctl(void *arg) 2701*0Sstevel@tonic-gate { 2702*0Sstevel@tonic-gate struct asyncline *za = arg; 2703*0Sstevel@tonic-gate struct zscom *zs = za->za_common; 2704*0Sstevel@tonic-gate queue_t *q; 2705*0Sstevel@tonic-gate mblk_t *mp; 2706*0Sstevel@tonic-gate 2707*0Sstevel@tonic-gate /* 2708*0Sstevel@tonic-gate * The bufcall is no longer pending. 2709*0Sstevel@tonic-gate */ 2710*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2711*0Sstevel@tonic-gate if (!za->za_wbufcid) { 2712*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2713*0Sstevel@tonic-gate return; 2714*0Sstevel@tonic-gate } 2715*0Sstevel@tonic-gate za->za_wbufcid = 0; 2716*0Sstevel@tonic-gate if ((q = za->za_ttycommon.t_writeq) == NULL) { 2717*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2718*0Sstevel@tonic-gate return; 2719*0Sstevel@tonic-gate } 2720*0Sstevel@tonic-gate if ((mp = za->za_ttycommon.t_iocpending) != NULL) { 2721*0Sstevel@tonic-gate /* 2722*0Sstevel@tonic-gate * not pending any more 2723*0Sstevel@tonic-gate */ 2724*0Sstevel@tonic-gate za->za_ttycommon.t_iocpending = NULL; 2725*0Sstevel@tonic-gate zsa_ioctl(za, q, mp); 2726*0Sstevel@tonic-gate } 2727*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2728*0Sstevel@tonic-gate } 2729*0Sstevel@tonic-gate 2730*0Sstevel@tonic-gate /* 2731*0Sstevel@tonic-gate * Process an "ioctl" message sent down to us. 2732*0Sstevel@tonic-gate * Note that we don't need to get any locks until we are ready to access 2733*0Sstevel@tonic-gate * the hardware. Nothing we access until then is going to be altered 2734*0Sstevel@tonic-gate * outside of the STREAMS framework, so we should be safe. 2735*0Sstevel@tonic-gate */ 2736*0Sstevel@tonic-gate static void 2737*0Sstevel@tonic-gate zsa_ioctl(struct asyncline *za, queue_t *wq, mblk_t *mp) 2738*0Sstevel@tonic-gate { 2739*0Sstevel@tonic-gate register struct zscom *zs = za->za_common; 2740*0Sstevel@tonic-gate register struct iocblk *iocp; 2741*0Sstevel@tonic-gate register unsigned datasize; 2742*0Sstevel@tonic-gate int error; 2743*0Sstevel@tonic-gate register mblk_t *tmp; 2744*0Sstevel@tonic-gate 2745*0Sstevel@tonic-gate if (za->za_ttycommon.t_iocpending != NULL) { 2746*0Sstevel@tonic-gate /* 2747*0Sstevel@tonic-gate * We were holding an "ioctl" response pending the 2748*0Sstevel@tonic-gate * availability of an "mblk" to hold data to be passed up; 2749*0Sstevel@tonic-gate * another "ioctl" came through, which means that "ioctl" 2750*0Sstevel@tonic-gate * must have timed out or been aborted. 2751*0Sstevel@tonic-gate */ 2752*0Sstevel@tonic-gate freemsg(za->za_ttycommon.t_iocpending); 2753*0Sstevel@tonic-gate za->za_ttycommon.t_iocpending = NULL; 2754*0Sstevel@tonic-gate } 2755*0Sstevel@tonic-gate 2756*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 2757*0Sstevel@tonic-gate 2758*0Sstevel@tonic-gate /* 2759*0Sstevel@tonic-gate * The only way in which "ttycommon_ioctl" can fail is if the "ioctl" 2760*0Sstevel@tonic-gate * requires a response containing data to be returned to the user, 2761*0Sstevel@tonic-gate * and no mblk could be allocated for the data. 2762*0Sstevel@tonic-gate * No such "ioctl" alters our state. Thus, we always go ahead and 2763*0Sstevel@tonic-gate * do any state-changes the "ioctl" calls for. If we couldn't allocate 2764*0Sstevel@tonic-gate * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so 2765*0Sstevel@tonic-gate * we just call "bufcall" to request that we be called back when we 2766*0Sstevel@tonic-gate * stand a better chance of allocating the data. 2767*0Sstevel@tonic-gate */ 2768*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2769*0Sstevel@tonic-gate datasize = ttycommon_ioctl(&za->za_ttycommon, wq, mp, &error); 2770*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2771*0Sstevel@tonic-gate if (za->za_ttycommon.t_flags & TS_SOFTCAR) 2772*0Sstevel@tonic-gate zssoftCAR[zs->zs_unit] = 1; 2773*0Sstevel@tonic-gate else 2774*0Sstevel@tonic-gate zssoftCAR[zs->zs_unit] = 0; 2775*0Sstevel@tonic-gate if (datasize != 0) { 2776*0Sstevel@tonic-gate if (za->za_wbufcid) 2777*0Sstevel@tonic-gate unbufcall(za->za_wbufcid); 2778*0Sstevel@tonic-gate za->za_wbufcid = bufcall(datasize, BPRI_HI, zsa_reioctl, za); 2779*0Sstevel@tonic-gate return; 2780*0Sstevel@tonic-gate } 2781*0Sstevel@tonic-gate 2782*0Sstevel@tonic-gate 2783*0Sstevel@tonic-gate if (error == 0) { 2784*0Sstevel@tonic-gate /* 2785*0Sstevel@tonic-gate * "ttycommon_ioctl" did most of the work; we just use the 2786*0Sstevel@tonic-gate * data it set up. 2787*0Sstevel@tonic-gate */ 2788*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 2789*0Sstevel@tonic-gate 2790*0Sstevel@tonic-gate case TCSETS: 2791*0Sstevel@tonic-gate case TCSETSW: 2792*0Sstevel@tonic-gate case TCSETSF: 2793*0Sstevel@tonic-gate case TCSETA: 2794*0Sstevel@tonic-gate case TCSETAW: 2795*0Sstevel@tonic-gate case TCSETAF: 2796*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2797*0Sstevel@tonic-gate zsa_program(za, 1); 2798*0Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(za); 2799*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2800*0Sstevel@tonic-gate break; 2801*0Sstevel@tonic-gate } 2802*0Sstevel@tonic-gate } else if (error < 0) { 2803*0Sstevel@tonic-gate /* 2804*0Sstevel@tonic-gate * "ttycommon_ioctl" didn't do anything; we process it here. 2805*0Sstevel@tonic-gate */ 2806*0Sstevel@tonic-gate error = 0; 2807*0Sstevel@tonic-gate 2808*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 2809*0Sstevel@tonic-gate 2810*0Sstevel@tonic-gate case TCSBRK: 2811*0Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 2812*0Sstevel@tonic-gate if (error != 0) 2813*0Sstevel@tonic-gate break; 2814*0Sstevel@tonic-gate 2815*0Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr == 0) { 2816*0Sstevel@tonic-gate /* 2817*0Sstevel@tonic-gate * The delay ensures that a 3 byte transmit 2818*0Sstevel@tonic-gate * fifo is empty. 2819*0Sstevel@tonic-gate */ 2820*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 2821*0Sstevel@tonic-gate delay(ztdelay(SPEED(za->za_ttycommon.t_cflag))); 2822*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 2823*0Sstevel@tonic-gate 2824*0Sstevel@tonic-gate /* 2825*0Sstevel@tonic-gate * Set the break bit, and arrange for 2826*0Sstevel@tonic-gate * "zsa_restart" to be called in 1/4 second; 2827*0Sstevel@tonic-gate * it will turn the break bit off, and call 2828*0Sstevel@tonic-gate * "zsa_start" to grab the next message. 2829*0Sstevel@tonic-gate */ 2830*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2831*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_BREAK); 2832*0Sstevel@tonic-gate if (!za->za_zsa_restart_id) { 2833*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2834*0Sstevel@tonic-gate za->za_zsa_restart_id = 2835*0Sstevel@tonic-gate timeout(zsa_restart, zs, hz / 4); 2836*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2837*0Sstevel@tonic-gate } 2838*0Sstevel@tonic-gate za->za_flags |= ZAS_BREAK; 2839*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2840*0Sstevel@tonic-gate } 2841*0Sstevel@tonic-gate break; 2842*0Sstevel@tonic-gate 2843*0Sstevel@tonic-gate case TIOCSBRK: 2844*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2845*0Sstevel@tonic-gate SCC_BIS(5, ZSWR5_BREAK); 2846*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2847*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 2848*0Sstevel@tonic-gate break; 2849*0Sstevel@tonic-gate 2850*0Sstevel@tonic-gate case TIOCCBRK: 2851*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2852*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK); 2853*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2854*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 2855*0Sstevel@tonic-gate break; 2856*0Sstevel@tonic-gate 2857*0Sstevel@tonic-gate case TIOCMSET: 2858*0Sstevel@tonic-gate case TIOCMBIS: 2859*0Sstevel@tonic-gate case TIOCMBIC: { 2860*0Sstevel@tonic-gate int mlines; 2861*0Sstevel@tonic-gate 2862*0Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) { 2863*0Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL); 2864*0Sstevel@tonic-gate break; 2865*0Sstevel@tonic-gate } 2866*0Sstevel@tonic-gate 2867*0Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 2868*0Sstevel@tonic-gate if (error != 0) 2869*0Sstevel@tonic-gate break; 2870*0Sstevel@tonic-gate 2871*0Sstevel@tonic-gate mlines = *(int *)mp->b_cont->b_rptr; 2872*0Sstevel@tonic-gate 2873*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2874*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 2875*0Sstevel@tonic-gate case TIOCMSET: 2876*0Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(mlines), DMSET); 2877*0Sstevel@tonic-gate break; 2878*0Sstevel@tonic-gate case TIOCMBIS: 2879*0Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(mlines), DMBIS); 2880*0Sstevel@tonic-gate break; 2881*0Sstevel@tonic-gate case TIOCMBIC: 2882*0Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(mlines), DMBIC); 2883*0Sstevel@tonic-gate break; 2884*0Sstevel@tonic-gate } 2885*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2886*0Sstevel@tonic-gate 2887*0Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 2888*0Sstevel@tonic-gate break; 2889*0Sstevel@tonic-gate } 2890*0Sstevel@tonic-gate 2891*0Sstevel@tonic-gate case TIOCMGET: 2892*0Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED); 2893*0Sstevel@tonic-gate if (tmp == NULL) { 2894*0Sstevel@tonic-gate error = EAGAIN; 2895*0Sstevel@tonic-gate break; 2896*0Sstevel@tonic-gate } 2897*0Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 2898*0Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0); 2899*0Sstevel@tonic-gate else 2900*0Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp); 2901*0Sstevel@tonic-gate 2902*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 2903*0Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr = 2904*0Sstevel@tonic-gate zstodm(zsmctl(zs, 0, DMGET)); 2905*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 2906*0Sstevel@tonic-gate /* 2907*0Sstevel@tonic-gate * qreply done below 2908*0Sstevel@tonic-gate */ 2909*0Sstevel@tonic-gate break; 2910*0Sstevel@tonic-gate 2911*0Sstevel@tonic-gate default: 2912*0Sstevel@tonic-gate /* 2913*0Sstevel@tonic-gate * If we don't understand it, it's an error. NAK it. 2914*0Sstevel@tonic-gate */ 2915*0Sstevel@tonic-gate error = EINVAL; 2916*0Sstevel@tonic-gate break; 2917*0Sstevel@tonic-gate } 2918*0Sstevel@tonic-gate } 2919*0Sstevel@tonic-gate 2920*0Sstevel@tonic-gate if (error != 0) { 2921*0Sstevel@tonic-gate iocp->ioc_error = error; 2922*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 2923*0Sstevel@tonic-gate } 2924*0Sstevel@tonic-gate 2925*0Sstevel@tonic-gate ZSA_QREPLY(wq, mp); 2926*0Sstevel@tonic-gate } 2927*0Sstevel@tonic-gate 2928*0Sstevel@tonic-gate 2929*0Sstevel@tonic-gate static int 2930*0Sstevel@tonic-gate dmtozs(int bits) 2931*0Sstevel@tonic-gate { 2932*0Sstevel@tonic-gate register int b = 0; 2933*0Sstevel@tonic-gate 2934*0Sstevel@tonic-gate if (bits & TIOCM_CAR) 2935*0Sstevel@tonic-gate b |= ZSRR0_CD; 2936*0Sstevel@tonic-gate if (bits & TIOCM_CTS) 2937*0Sstevel@tonic-gate b |= ZSRR0_CTS; 2938*0Sstevel@tonic-gate if (bits & TIOCM_RTS) 2939*0Sstevel@tonic-gate b |= ZSWR5_RTS; 2940*0Sstevel@tonic-gate if (bits & TIOCM_DTR) 2941*0Sstevel@tonic-gate b |= ZSWR5_DTR; 2942*0Sstevel@tonic-gate return (b); 2943*0Sstevel@tonic-gate } 2944*0Sstevel@tonic-gate 2945*0Sstevel@tonic-gate static int 2946*0Sstevel@tonic-gate zstodm(int bits) 2947*0Sstevel@tonic-gate { 2948*0Sstevel@tonic-gate register int b; 2949*0Sstevel@tonic-gate 2950*0Sstevel@tonic-gate b = 0; 2951*0Sstevel@tonic-gate if (bits & ZSRR0_CD) 2952*0Sstevel@tonic-gate b |= TIOCM_CAR; 2953*0Sstevel@tonic-gate if (bits & ZSRR0_CTS) 2954*0Sstevel@tonic-gate b |= TIOCM_CTS; 2955*0Sstevel@tonic-gate if (bits & ZSWR5_RTS) 2956*0Sstevel@tonic-gate b |= TIOCM_RTS; 2957*0Sstevel@tonic-gate if (bits & ZSWR5_DTR) 2958*0Sstevel@tonic-gate b |= TIOCM_DTR; 2959*0Sstevel@tonic-gate return (b); 2960*0Sstevel@tonic-gate } 2961*0Sstevel@tonic-gate 2962*0Sstevel@tonic-gate /* 2963*0Sstevel@tonic-gate * Assemble registers and flags necessary to program the port to our liking. 2964*0Sstevel@tonic-gate * For async operation, most of this is based on the values of 2965*0Sstevel@tonic-gate * the "c_iflag" and "c_cflag" fields supplied to us. 2966*0Sstevel@tonic-gate */ 2967*0Sstevel@tonic-gate static void 2968*0Sstevel@tonic-gate zsa_program(struct asyncline *za, int setibaud) 2969*0Sstevel@tonic-gate { 2970*0Sstevel@tonic-gate register struct zscom *zs = za->za_common; 2971*0Sstevel@tonic-gate register struct zs_prog *zspp; 2972*0Sstevel@tonic-gate register int wr3, wr4, wr5, wr15, speed, baudrate, flags = 0; 2973*0Sstevel@tonic-gate 2974*0Sstevel@tonic-gate if ((baudrate = SPEED(za->za_ttycommon.t_cflag)) == 0) { 2975*0Sstevel@tonic-gate /* 2976*0Sstevel@tonic-gate * Hang up line. 2977*0Sstevel@tonic-gate */ 2978*0Sstevel@tonic-gate (void) zsmctl(zs, ZS_OFF, DMSET); 2979*0Sstevel@tonic-gate return; 2980*0Sstevel@tonic-gate } 2981*0Sstevel@tonic-gate 2982*0Sstevel@tonic-gate /* 2983*0Sstevel@tonic-gate * set input speed same as output, as split speed not supported 2984*0Sstevel@tonic-gate */ 2985*0Sstevel@tonic-gate if (setibaud) { 2986*0Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~(CIBAUD); 2987*0Sstevel@tonic-gate if (baudrate > CBAUD) { 2988*0Sstevel@tonic-gate za->za_ttycommon.t_cflag |= CIBAUDEXT; 2989*0Sstevel@tonic-gate za->za_ttycommon.t_cflag |= 2990*0Sstevel@tonic-gate (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD); 2991*0Sstevel@tonic-gate } else { 2992*0Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~CIBAUDEXT; 2993*0Sstevel@tonic-gate za->za_ttycommon.t_cflag |= 2994*0Sstevel@tonic-gate ((baudrate << IBSHIFT) & CIBAUD); 2995*0Sstevel@tonic-gate } 2996*0Sstevel@tonic-gate } 2997*0Sstevel@tonic-gate 2998*0Sstevel@tonic-gate /* 2999*0Sstevel@tonic-gate * Do not allow the console/keyboard device to have its receiver 3000*0Sstevel@tonic-gate * disabled; doing that would mean you couldn't type an abort 3001*0Sstevel@tonic-gate * sequence. 3002*0Sstevel@tonic-gate */ 3003*0Sstevel@tonic-gate if ((za->za_dev == rconsdev) || (za->za_dev == kbddev) || 3004*0Sstevel@tonic-gate (za->za_dev == stdindev) || (za->za_ttycommon.t_cflag & CREAD)) 3005*0Sstevel@tonic-gate wr3 = ZSWR3_RX_ENABLE; 3006*0Sstevel@tonic-gate else 3007*0Sstevel@tonic-gate wr3 = 0; 3008*0Sstevel@tonic-gate wr4 = ZSWR4_X16_CLK; 3009*0Sstevel@tonic-gate wr5 = (zs->zs_wreg[5] & (ZSWR5_RTS|ZSWR5_DTR)) | ZSWR5_TX_ENABLE; 3010*0Sstevel@tonic-gate 3011*0Sstevel@tonic-gate if (zsb134_weird && baudrate == B134) { /* what a joke! */ 3012*0Sstevel@tonic-gate /* 3013*0Sstevel@tonic-gate * XXX - should B134 set all this crap in the compatibility 3014*0Sstevel@tonic-gate * module, leaving this stuff fairly clean? 3015*0Sstevel@tonic-gate */ 3016*0Sstevel@tonic-gate flags |= ZSP_PARITY_SPECIAL; 3017*0Sstevel@tonic-gate wr3 |= ZSWR3_RX_6; 3018*0Sstevel@tonic-gate wr4 |= ZSWR4_PARITY_ENABLE | ZSWR4_PARITY_EVEN; 3019*0Sstevel@tonic-gate wr4 |= ZSWR4_1_5_STOP; 3020*0Sstevel@tonic-gate wr5 |= ZSWR5_TX_6; 3021*0Sstevel@tonic-gate } else { 3022*0Sstevel@tonic-gate 3023*0Sstevel@tonic-gate switch (za->za_ttycommon.t_cflag & CSIZE) { 3024*0Sstevel@tonic-gate 3025*0Sstevel@tonic-gate case CS5: 3026*0Sstevel@tonic-gate wr3 |= ZSWR3_RX_5; 3027*0Sstevel@tonic-gate wr5 |= ZSWR5_TX_5; 3028*0Sstevel@tonic-gate break; 3029*0Sstevel@tonic-gate 3030*0Sstevel@tonic-gate case CS6: 3031*0Sstevel@tonic-gate wr3 |= ZSWR3_RX_6; 3032*0Sstevel@tonic-gate wr5 |= ZSWR5_TX_6; 3033*0Sstevel@tonic-gate break; 3034*0Sstevel@tonic-gate 3035*0Sstevel@tonic-gate case CS7: 3036*0Sstevel@tonic-gate wr3 |= ZSWR3_RX_7; 3037*0Sstevel@tonic-gate wr5 |= ZSWR5_TX_7; 3038*0Sstevel@tonic-gate break; 3039*0Sstevel@tonic-gate 3040*0Sstevel@tonic-gate case CS8: 3041*0Sstevel@tonic-gate wr3 |= ZSWR3_RX_8; 3042*0Sstevel@tonic-gate wr5 |= ZSWR5_TX_8; 3043*0Sstevel@tonic-gate break; 3044*0Sstevel@tonic-gate } 3045*0Sstevel@tonic-gate 3046*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARENB) { 3047*0Sstevel@tonic-gate /* 3048*0Sstevel@tonic-gate * The PARITY_SPECIAL bit causes a special rx 3049*0Sstevel@tonic-gate * interrupt on parity errors. Turn it on if 3050*0Sstevel@tonic-gate * we're checking the parity of characters. 3051*0Sstevel@tonic-gate */ 3052*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & INPCK) 3053*0Sstevel@tonic-gate flags |= ZSP_PARITY_SPECIAL; 3054*0Sstevel@tonic-gate wr4 |= ZSWR4_PARITY_ENABLE; 3055*0Sstevel@tonic-gate if (!(za->za_ttycommon.t_cflag & PARODD)) 3056*0Sstevel@tonic-gate wr4 |= ZSWR4_PARITY_EVEN; 3057*0Sstevel@tonic-gate } 3058*0Sstevel@tonic-gate wr4 |= (za->za_ttycommon.t_cflag & CSTOPB) ? 3059*0Sstevel@tonic-gate ZSWR4_2_STOP : ZSWR4_1_STOP; 3060*0Sstevel@tonic-gate } 3061*0Sstevel@tonic-gate 3062*0Sstevel@tonic-gate #if 0 3063*0Sstevel@tonic-gate /* 3064*0Sstevel@tonic-gate * The AUTO_CD_CTS flag enables the hardware flow control feature of 3065*0Sstevel@tonic-gate * the 8530, which allows the state of CTS and DCD to control the 3066*0Sstevel@tonic-gate * enabling of the transmitter and receiver, respectively. The 3067*0Sstevel@tonic-gate * receiver and transmitter still must have their enable bits set in 3068*0Sstevel@tonic-gate * WR3 and WR5, respectively, for CTS and DCD to be monitored this way. 3069*0Sstevel@tonic-gate * Hardware flow control can thus be implemented with no help from 3070*0Sstevel@tonic-gate * software. 3071*0Sstevel@tonic-gate */ 3072*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) 3073*0Sstevel@tonic-gate wr3 |= ZSWR3_AUTO_CD_CTS; 3074*0Sstevel@tonic-gate #endif 3075*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) 3076*0Sstevel@tonic-gate wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD | ZSR15_CTS; 3077*0Sstevel@tonic-gate else 3078*0Sstevel@tonic-gate wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD; 3079*0Sstevel@tonic-gate 3080*0Sstevel@tonic-gate speed = zs->zs_wreg[12] + (zs->zs_wreg[13] << 8); 3081*0Sstevel@tonic-gate 3082*0Sstevel@tonic-gate /* 3083*0Sstevel@tonic-gate * Here we assemble a set of changes to be passed to zs_program. 3084*0Sstevel@tonic-gate * Note: Write Register 15 must be set to enable BREAK and UNDERrun 3085*0Sstevel@tonic-gate * interrupts. It must also enable CD interrupts which, although 3086*0Sstevel@tonic-gate * not processed by the hardware interrupt handler, will be processed 3087*0Sstevel@tonic-gate * by zsa_process, indirectly resulting in a SIGHUP being delivered 3088*0Sstevel@tonic-gate * to the controlling process if CD drops. CTS interrupts must NOT 3089*0Sstevel@tonic-gate * be enabled. We don't use them at all, and they will hang IPC/IPX 3090*0Sstevel@tonic-gate * systems at boot time if synchronous modems that supply transmit 3091*0Sstevel@tonic-gate * clock are attached to any of their serial ports. 3092*0Sstevel@tonic-gate */ 3093*0Sstevel@tonic-gate if (((zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) && 3094*0Sstevel@tonic-gate !(flags & ZSP_PARITY_SPECIAL)) || 3095*0Sstevel@tonic-gate (!(zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) && 3096*0Sstevel@tonic-gate (flags & ZSP_PARITY_SPECIAL)) || 3097*0Sstevel@tonic-gate wr3 != zs->zs_wreg[3] || wr4 != zs->zs_wreg[4] || 3098*0Sstevel@tonic-gate wr5 != zs->zs_wreg[5] || wr15 != zs->zs_wreg[15] || 3099*0Sstevel@tonic-gate speed != zs_speeds[baudrate]) { 3100*0Sstevel@tonic-gate 3101*0Sstevel@tonic-gate za->za_flags |= ZAS_DRAINING; 3102*0Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit]; 3103*0Sstevel@tonic-gate zspp->zs = zs; 3104*0Sstevel@tonic-gate zspp->flags = (uchar_t)flags; 3105*0Sstevel@tonic-gate zspp->wr4 = (uchar_t)wr4; 3106*0Sstevel@tonic-gate zspp->wr11 = (uchar_t)(ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD); 3107*0Sstevel@tonic-gate 3108*0Sstevel@tonic-gate speed = zs_speeds[baudrate]; 3109*0Sstevel@tonic-gate zspp->wr12 = (uchar_t)(speed & 0xff); 3110*0Sstevel@tonic-gate zspp->wr13 = (uchar_t)((speed >> 8) & 0xff); 3111*0Sstevel@tonic-gate zspp->wr3 = (uchar_t)wr3; 3112*0Sstevel@tonic-gate zspp->wr5 = (uchar_t)wr5; 3113*0Sstevel@tonic-gate zspp->wr15 = (uchar_t)wr15; 3114*0Sstevel@tonic-gate 3115*0Sstevel@tonic-gate zs_program(zspp); 3116*0Sstevel@tonic-gate za->za_flags &= ~ZAS_DRAINING; 3117*0Sstevel@tonic-gate } 3118*0Sstevel@tonic-gate } 3119*0Sstevel@tonic-gate 3120*0Sstevel@tonic-gate /* 3121*0Sstevel@tonic-gate * Get the current speed of the console and turn it into something 3122*0Sstevel@tonic-gate * UNIX knows about - used to preserve console speed when UNIX comes up. 3123*0Sstevel@tonic-gate */ 3124*0Sstevel@tonic-gate int 3125*0Sstevel@tonic-gate zsgetspeed(dev_t dev) 3126*0Sstevel@tonic-gate { 3127*0Sstevel@tonic-gate register struct zscom *zs; 3128*0Sstevel@tonic-gate register int uspeed, zspeed; 3129*0Sstevel@tonic-gate register uchar_t rr; 3130*0Sstevel@tonic-gate 3131*0Sstevel@tonic-gate zs = &zscom[UNIT(dev)]; 3132*0Sstevel@tonic-gate SCC_READ(12, zspeed); 3133*0Sstevel@tonic-gate SCC_READ(13, rr); 3134*0Sstevel@tonic-gate zspeed |= rr << 8; 3135*0Sstevel@tonic-gate for (uspeed = 0; uspeed < NSPEED; uspeed++) 3136*0Sstevel@tonic-gate if (zs_speeds[uspeed] == zspeed) 3137*0Sstevel@tonic-gate return (uspeed); 3138*0Sstevel@tonic-gate /* 3139*0Sstevel@tonic-gate * 9600 baud if we can't figure it out 3140*0Sstevel@tonic-gate */ 3141*0Sstevel@tonic-gate return (ISPEED); 3142*0Sstevel@tonic-gate } 3143*0Sstevel@tonic-gate 3144*0Sstevel@tonic-gate /* 3145*0Sstevel@tonic-gate * callback routine when enough memory is available. 3146*0Sstevel@tonic-gate */ 3147*0Sstevel@tonic-gate static void 3148*0Sstevel@tonic-gate zsa_callback(void *arg) 3149*0Sstevel@tonic-gate { 3150*0Sstevel@tonic-gate struct zscom *zs = arg; 3151*0Sstevel@tonic-gate struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 3152*0Sstevel@tonic-gate int allocbcount = zsa_rstandby; 3153*0Sstevel@tonic-gate 3154*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 3155*0Sstevel@tonic-gate if (za->za_bufcid) { 3156*0Sstevel@tonic-gate za->za_bufcid = 0; 3157*0Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount); 3158*0Sstevel@tonic-gate } 3159*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 3160*0Sstevel@tonic-gate } 3161*0Sstevel@tonic-gate 3162*0Sstevel@tonic-gate /* 3163*0Sstevel@tonic-gate * Set the receiver flags 3164*0Sstevel@tonic-gate */ 3165*0Sstevel@tonic-gate static void 3166*0Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(struct asyncline *za) 3167*0Sstevel@tonic-gate { 3168*0Sstevel@tonic-gate register uint_t mask; 3169*0Sstevel@tonic-gate 3170*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~0xFF; 3171*0Sstevel@tonic-gate switch (za->za_ttycommon.t_cflag & CSIZE) { 3172*0Sstevel@tonic-gate case CS5: 3173*0Sstevel@tonic-gate mask = 0x1f; 3174*0Sstevel@tonic-gate break; 3175*0Sstevel@tonic-gate case CS6: 3176*0Sstevel@tonic-gate mask = 0x3f; 3177*0Sstevel@tonic-gate break; 3178*0Sstevel@tonic-gate case CS7: 3179*0Sstevel@tonic-gate mask = 0x7f; 3180*0Sstevel@tonic-gate break; 3181*0Sstevel@tonic-gate default: 3182*0Sstevel@tonic-gate mask = 0xff; 3183*0Sstevel@tonic-gate } 3184*0Sstevel@tonic-gate 3185*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~(0xFF << 16); 3186*0Sstevel@tonic-gate za->za_rcv_flags_mask |= mask << 16; 3187*0Sstevel@tonic-gate 3188*0Sstevel@tonic-gate if ((za->za_ttycommon.t_iflag & PARMRK) && 3189*0Sstevel@tonic-gate !(za->za_ttycommon.t_iflag & (IGNPAR|ISTRIP))) { 3190*0Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_ESC; 3191*0Sstevel@tonic-gate } else 3192*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_ESC; 3193*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IXON) { 3194*0Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_STOPC; 3195*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~0xFF; 3196*0Sstevel@tonic-gate za->za_rcv_flags_mask |= za->za_ttycommon.t_stopc; 3197*0Sstevel@tonic-gate } else 3198*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_STOPC; 3199*0Sstevel@tonic-gate } 3200*0Sstevel@tonic-gate 3201*0Sstevel@tonic-gate static int 3202*0Sstevel@tonic-gate zsa_suspend(struct zscom *zs) 3203*0Sstevel@tonic-gate { 3204*0Sstevel@tonic-gate struct asyncline *za; 3205*0Sstevel@tonic-gate queue_t *q; 3206*0Sstevel@tonic-gate mblk_t *bp = NULL; 3207*0Sstevel@tonic-gate timeout_id_t restart_id, kick_rcv_id; 3208*0Sstevel@tonic-gate struct zs_prog *zspp; 3209*0Sstevel@tonic-gate 3210*0Sstevel@tonic-gate za = (struct asyncline *)&zs->zs_priv_str; 3211*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 3212*0Sstevel@tonic-gate if (zs->zs_suspended) { 3213*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 3214*0Sstevel@tonic-gate return (DDI_SUCCESS); 3215*0Sstevel@tonic-gate } 3216*0Sstevel@tonic-gate zs->zs_suspended = 1; 3217*0Sstevel@tonic-gate 3218*0Sstevel@tonic-gate /* 3219*0Sstevel@tonic-gate * Turn off interrupts and get any bytes in receiver 3220*0Sstevel@tonic-gate */ 3221*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 3222*0Sstevel@tonic-gate SCC_BIC(1, ZSWR1_INIT); 3223*0Sstevel@tonic-gate ZSA_KICK_RCV; 3224*0Sstevel@tonic-gate restart_id = za->za_zsa_restart_id; 3225*0Sstevel@tonic-gate za->za_zsa_restart_id = 0; 3226*0Sstevel@tonic-gate kick_rcv_id = za->za_kick_rcv_id; 3227*0Sstevel@tonic-gate za->za_kick_rcv_id = 0; 3228*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 3229*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 3230*0Sstevel@tonic-gate 3231*0Sstevel@tonic-gate /* 3232*0Sstevel@tonic-gate * Cancel any timeouts 3233*0Sstevel@tonic-gate */ 3234*0Sstevel@tonic-gate if (restart_id) 3235*0Sstevel@tonic-gate (void) untimeout(restart_id); 3236*0Sstevel@tonic-gate if (kick_rcv_id) 3237*0Sstevel@tonic-gate (void) untimeout(kick_rcv_id); 3238*0Sstevel@tonic-gate 3239*0Sstevel@tonic-gate /* 3240*0Sstevel@tonic-gate * Since we have turned off interrupts, zsa_txint will not be called 3241*0Sstevel@tonic-gate * and no new chars will given to the chip. We just wait for the 3242*0Sstevel@tonic-gate * current character(s) to drain. 3243*0Sstevel@tonic-gate */ 3244*0Sstevel@tonic-gate delay(ztdelay(za->za_ttycommon.t_cflag & CBAUD)); 3245*0Sstevel@tonic-gate 3246*0Sstevel@tonic-gate /* 3247*0Sstevel@tonic-gate * Return remains of partially sent message to queue 3248*0Sstevel@tonic-gate */ 3249*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 3250*0Sstevel@tonic-gate if ((q = za->za_ttycommon.t_writeq) != NULL) { 3251*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 3252*0Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) { 3253*0Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 3254*0Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 3255*0Sstevel@tonic-gate bp = za->za_xmitblk; 3256*0Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur; 3257*0Sstevel@tonic-gate zs->zs_wr_cur = NULL; 3258*0Sstevel@tonic-gate zs->zs_wr_lim = NULL; 3259*0Sstevel@tonic-gate za->za_xmitblk = NULL; 3260*0Sstevel@tonic-gate } 3261*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 3262*0Sstevel@tonic-gate if (bp) 3263*0Sstevel@tonic-gate (void) putbq(q, bp); 3264*0Sstevel@tonic-gate } 3265*0Sstevel@tonic-gate 3266*0Sstevel@tonic-gate /* 3267*0Sstevel@tonic-gate * Stop any breaks in progress. 3268*0Sstevel@tonic-gate */ 3269*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 3270*0Sstevel@tonic-gate if (zs->zs_wreg[5] & ZSWR5_BREAK) { 3271*0Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK); 3272*0Sstevel@tonic-gate za->za_flags &= ~ZAS_BREAK; 3273*0Sstevel@tonic-gate } 3274*0Sstevel@tonic-gate 3275*0Sstevel@tonic-gate /* 3276*0Sstevel@tonic-gate * Now get a copy of current registers setting. 3277*0Sstevel@tonic-gate */ 3278*0Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit]; 3279*0Sstevel@tonic-gate zspp->zs = zs; 3280*0Sstevel@tonic-gate zspp->flags = 0; 3281*0Sstevel@tonic-gate zspp->wr3 = zs->zs_wreg[3]; 3282*0Sstevel@tonic-gate zspp->wr4 = zs->zs_wreg[4]; 3283*0Sstevel@tonic-gate zspp->wr5 = zs->zs_wreg[5]; 3284*0Sstevel@tonic-gate zspp->wr11 = zs->zs_wreg[11]; 3285*0Sstevel@tonic-gate zspp->wr12 = zs->zs_wreg[12]; 3286*0Sstevel@tonic-gate zspp->wr13 = zs->zs_wreg[13]; 3287*0Sstevel@tonic-gate zspp->wr15 = zs->zs_wreg[15]; 3288*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 3289*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 3290*0Sstevel@tonic-gate /* 3291*0Sstevel@tonic-gate * We do this on the off chance that zsa_close is waiting on a timed 3292*0Sstevel@tonic-gate * break to complete and nothing else. 3293*0Sstevel@tonic-gate */ 3294*0Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 3295*0Sstevel@tonic-gate return (DDI_SUCCESS); 3296*0Sstevel@tonic-gate } 3297*0Sstevel@tonic-gate 3298*0Sstevel@tonic-gate static int 3299*0Sstevel@tonic-gate zsa_resume(struct zscom *zs) 3300*0Sstevel@tonic-gate { 3301*0Sstevel@tonic-gate register struct asyncline *za; 3302*0Sstevel@tonic-gate struct zs_prog *zspp; 3303*0Sstevel@tonic-gate 3304*0Sstevel@tonic-gate za = (struct asyncline *)&zs->zs_priv_str; 3305*0Sstevel@tonic-gate mutex_enter(zs->zs_excl); 3306*0Sstevel@tonic-gate if (!(zs->zs_suspended)) { 3307*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 3308*0Sstevel@tonic-gate return (DDI_SUCCESS); 3309*0Sstevel@tonic-gate } 3310*0Sstevel@tonic-gate 3311*0Sstevel@tonic-gate /* 3312*0Sstevel@tonic-gate * Restore H/W state 3313*0Sstevel@tonic-gate */ 3314*0Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 3315*0Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit]; 3316*0Sstevel@tonic-gate zs_program(zspp); 3317*0Sstevel@tonic-gate 3318*0Sstevel@tonic-gate /* 3319*0Sstevel@tonic-gate * Enable all interrupts for this chip and delay to let chip settle 3320*0Sstevel@tonic-gate */ 3321*0Sstevel@tonic-gate SCC_WRITE(9, ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT); 3322*0Sstevel@tonic-gate DELAY(4000); 3323*0Sstevel@tonic-gate 3324*0Sstevel@tonic-gate /* 3325*0Sstevel@tonic-gate * Restart receiving and transmitting 3326*0Sstevel@tonic-gate */ 3327*0Sstevel@tonic-gate zs->zs_suspended = 0; 3328*0Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT; 3329*0Sstevel@tonic-gate za->za_ext = 1; 3330*0Sstevel@tonic-gate ZSSETSOFT(zs); 3331*0Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 3332*0Sstevel@tonic-gate mutex_exit(zs->zs_excl); 3333*0Sstevel@tonic-gate 3334*0Sstevel@tonic-gate return (DDI_SUCCESS); 3335*0Sstevel@tonic-gate } 3336*0Sstevel@tonic-gate 3337*0Sstevel@tonic-gate #ifdef ZSA_DEBUG 3338*0Sstevel@tonic-gate static void 3339*0Sstevel@tonic-gate zsa_print_info(struct zscom *zs) 3340*0Sstevel@tonic-gate { 3341*0Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 3342*0Sstevel@tonic-gate register queue_t *q = za->za_ttycommon.t_writeq; 3343*0Sstevel@tonic-gate 3344*0Sstevel@tonic-gate printf(" next q=%s\n", (RD(q))->q_next->q_qinfo->qi_minfo->mi_idname); 3345*0Sstevel@tonic-gate printf("unit=%d\n", zs->zs_unit); 3346*0Sstevel@tonic-gate printf("tflag:\n"); 3347*0Sstevel@tonic-gate if (za->za_ttycommon.t_flags & TS_SOFTCAR) printf(" t_fl:TS_SOFTCAR"); 3348*0Sstevel@tonic-gate if (za->za_ttycommon.t_flags & TS_XCLUDE) printf(" t_fl:TS_XCLUDE"); 3349*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IGNBRK) printf(" t_ifl:IGNBRK"); 3350*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & BRKINT) printf(" t_ifl:BRKINT"); 3351*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IGNPAR) printf(" t_ifl:IGNPAR"); 3352*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & PARMRK) printf(" t_ifl:PARMRK"); 3353*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & INPCK) printf(" t_ifl:INPCK"); 3354*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & ISTRIP) printf(" t_ifl:ISTRIP"); 3355*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & INLCR) printf(" t_ifl:INLCR"); 3356*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IGNCR) printf(" t_ifl:IGNCR"); 3357*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & ICRNL) printf(" t_ifl:ICRNL"); 3358*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IUCLC) printf(" t_ifl:IUCLC"); 3359*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IXON) printf(" t_ifl:IXON"); 3360*0Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IXOFF) printf(" t_ifl:IXOFF"); 3361*0Sstevel@tonic-gate 3362*0Sstevel@tonic-gate printf("\n"); 3363*0Sstevel@tonic-gate 3364*0Sstevel@tonic-gate 3365*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS5) printf(" t_cfl:CS5"); 3366*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS6) printf(" t_cfl:CS6"); 3367*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS7) printf(" t_cfl:CS7"); 3368*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS8) printf(" t_cfl:CS8"); 3369*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSTOPB) printf(" t_cfl:CSTOPB"); 3370*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CREAD) printf(" t_cfl:CREAD"); 3371*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARENB) printf(" t_cfl:PARENB"); 3372*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARODD) printf(" t_cfl:PARODD"); 3373*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & HUPCL) printf(" t_cfl:HUPCL"); 3374*0Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CLOCAL) printf(" t_cfl:CLOCAL"); 3375*0Sstevel@tonic-gate printf(" t_stopc=%x", za->za_ttycommon.t_stopc); 3376*0Sstevel@tonic-gate printf("\n"); 3377*0Sstevel@tonic-gate } 3378*0Sstevel@tonic-gate #endif 3379*0Sstevel@tonic-gate 3380*0Sstevel@tonic-gate /* 3381*0Sstevel@tonic-gate * Check for abort character sequence 3382*0Sstevel@tonic-gate */ 3383*0Sstevel@tonic-gate static boolean_t 3384*0Sstevel@tonic-gate abort_charseq_recognize(uchar_t ch) 3385*0Sstevel@tonic-gate { 3386*0Sstevel@tonic-gate static int state = 0; 3387*0Sstevel@tonic-gate #define CNTRL(c) ((c)&037) 3388*0Sstevel@tonic-gate static char sequence[] = { '\r', '~', CNTRL('b') }; 3389*0Sstevel@tonic-gate 3390*0Sstevel@tonic-gate if (ch == sequence[state]) { 3391*0Sstevel@tonic-gate if (++state >= sizeof (sequence)) { 3392*0Sstevel@tonic-gate state = 0; 3393*0Sstevel@tonic-gate return (B_TRUE); 3394*0Sstevel@tonic-gate } 3395*0Sstevel@tonic-gate } else { 3396*0Sstevel@tonic-gate state = (ch == sequence[0]) ? 1 : 0; 3397*0Sstevel@tonic-gate } 3398*0Sstevel@tonic-gate return (B_FALSE); 3399*0Sstevel@tonic-gate } 3400