10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*796Smathue * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Asynchronous protocol handler for Z8530 chips 310Sstevel@tonic-gate * Handles normal UNIX support for terminals & modems 320Sstevel@tonic-gate */ 330Sstevel@tonic-gate 340Sstevel@tonic-gate #include <sys/types.h> 350Sstevel@tonic-gate #include <sys/param.h> 360Sstevel@tonic-gate #include <sys/systm.h> 370Sstevel@tonic-gate #include <sys/sysmacros.h> 380Sstevel@tonic-gate #include <sys/signal.h> 390Sstevel@tonic-gate #include <sys/kmem.h> 400Sstevel@tonic-gate #include <sys/termios.h> 410Sstevel@tonic-gate #include <sys/stropts.h> 420Sstevel@tonic-gate #include <sys/stream.h> 430Sstevel@tonic-gate #include <sys/strsun.h> 440Sstevel@tonic-gate #include <sys/tty.h> 450Sstevel@tonic-gate #include <sys/ptyvar.h> 460Sstevel@tonic-gate #include <sys/cred.h> 470Sstevel@tonic-gate #include <sys/user.h> 480Sstevel@tonic-gate #include <sys/proc.h> 490Sstevel@tonic-gate #include <sys/file.h> 500Sstevel@tonic-gate #include <sys/uio.h> 510Sstevel@tonic-gate #include <sys/buf.h> 520Sstevel@tonic-gate #include <sys/mkdev.h> 530Sstevel@tonic-gate #include <sys/cmn_err.h> 540Sstevel@tonic-gate #include <sys/strtty.h> 550Sstevel@tonic-gate #include <sys/consdev.h> 560Sstevel@tonic-gate #include <sys/zsdev.h> 570Sstevel@tonic-gate #include <sys/ser_async.h> 580Sstevel@tonic-gate #include <sys/debug.h> 590Sstevel@tonic-gate #include <sys/kbio.h> 600Sstevel@tonic-gate #include <sys/conf.h> 610Sstevel@tonic-gate #include <sys/ddi.h> 620Sstevel@tonic-gate #include <sys/sunddi.h> 630Sstevel@tonic-gate #include <sys/promif.h> 640Sstevel@tonic-gate #include <sys/policy.h> 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * PPS (Pulse Per Second) support. 680Sstevel@tonic-gate */ 690Sstevel@tonic-gate extern void ddi_hardpps(struct timeval *, int); 700Sstevel@tonic-gate static struct ppsclockev ppsclockev; 710Sstevel@tonic-gate 720Sstevel@tonic-gate #ifdef PPSCLOCKLED 730Sstevel@tonic-gate /* XXX Use these to observe PPS latencies and jitter on a scope */ 740Sstevel@tonic-gate #define LED_ON 750Sstevel@tonic-gate #define LED_OFF 760Sstevel@tonic-gate #else 770Sstevel@tonic-gate #define LED_ON 780Sstevel@tonic-gate #define LED_OFF 790Sstevel@tonic-gate #endif 800Sstevel@tonic-gate 810Sstevel@tonic-gate #define ZSA_RCV_SIZE 64 820Sstevel@tonic-gate #define ZA_KICK_RCV_COUNT 3 830Sstevel@tonic-gate #define ZSA_GRACE_MIN_FLOW_CONTROL 5 840Sstevel@tonic-gate #define ZSA_GRACE_MAX_FLOW_CONTROL 20 850Sstevel@tonic-gate 860Sstevel@tonic-gate int zsasoftdtr = 0; /* if nonzero, softcarrier raises dtr at attach */ 870Sstevel@tonic-gate int zsb134_weird = 0; /* if set, old weird B134 behavior */ 880Sstevel@tonic-gate int g_zsticks = 0; /* if set, becomes the global zsticks value */ 890Sstevel@tonic-gate int g_nocluster = 0; /* if set, disables clustering of received data */ 900Sstevel@tonic-gate 910Sstevel@tonic-gate unsigned int zsa_rstandby = ZSA_MIN_RSTANDBY; 920Sstevel@tonic-gate unsigned int zsa_rdone = ZSA_RDONE_MIN; 930Sstevel@tonic-gate unsigned int zsa_grace_flow_control = ZSA_GRACE_MIN_FLOW_CONTROL; 940Sstevel@tonic-gate 950Sstevel@tonic-gate 960Sstevel@tonic-gate #define NSPEED 18 /* max # of speeds */ 970Sstevel@tonic-gate ushort_t zs_speeds[NSPEED] = { 980Sstevel@tonic-gate 0, 990Sstevel@tonic-gate ZSPEED(50), /* 1 */ 1000Sstevel@tonic-gate ZSPEED(75), /* 2 */ 1010Sstevel@tonic-gate ZSPEED(110), /* 3 */ 1020Sstevel@tonic-gate #ifdef lint 1030Sstevel@tonic-gate ZSPEED(134), /* 4 */ 1040Sstevel@tonic-gate #else 1050Sstevel@tonic-gate ZSPEED(269/2), /* XXX - This is sleazy */ 1060Sstevel@tonic-gate #endif 1070Sstevel@tonic-gate ZSPEED(150), /* 5 */ 1080Sstevel@tonic-gate ZSPEED(200), /* 6 */ 1090Sstevel@tonic-gate ZSPEED(300), /* 7 */ 1100Sstevel@tonic-gate ZSPEED(600), /* 8 */ 1110Sstevel@tonic-gate ZSPEED(1200), /* 9 */ 1120Sstevel@tonic-gate ZSPEED(1800), /* 10 */ 1130Sstevel@tonic-gate ZSPEED(2400), /* 11 */ 1140Sstevel@tonic-gate ZSPEED(4800), /* 12 */ 1150Sstevel@tonic-gate ZSPEED(9600), /* 13 */ 1160Sstevel@tonic-gate ZSPEED(19200), /* 14 */ 1170Sstevel@tonic-gate ZSPEED(38400), /* 15 */ 1180Sstevel@tonic-gate ZSPEED(57680), /* 16 */ 1190Sstevel@tonic-gate ZSPEED(76800) /* 17 */ 1200Sstevel@tonic-gate }; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate ushort_t zsticks[NSPEED] = { 1230Sstevel@tonic-gate 3, /* 0 */ 1240Sstevel@tonic-gate 3, /* 1 */ 1250Sstevel@tonic-gate 3, /* 2 */ 1260Sstevel@tonic-gate 3, /* 3 */ 1270Sstevel@tonic-gate 3, /* 4 */ 1280Sstevel@tonic-gate 3, /* 5 */ 1290Sstevel@tonic-gate 3, /* 6 */ 1300Sstevel@tonic-gate 3, /* 7 */ 1310Sstevel@tonic-gate 3, /* 8 */ 1320Sstevel@tonic-gate 3, /* 9 */ 1330Sstevel@tonic-gate 3, /* 10 */ 1340Sstevel@tonic-gate 3, /* 11 */ 1350Sstevel@tonic-gate 3, /* 12 */ 1360Sstevel@tonic-gate 3, /* 13 */ 1370Sstevel@tonic-gate 2, /* 14 */ 1380Sstevel@tonic-gate 1, /* 15 */ 1390Sstevel@tonic-gate 1, /* 16 */ 1400Sstevel@tonic-gate 1 /* 17 */ 1410Sstevel@tonic-gate }; 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate #define ztdelay(nsp) (zsdelay[(nsp)]*(hz/100)) 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate ushort_t zsdelay[NSPEED] = { 1460Sstevel@tonic-gate 0, 1470Sstevel@tonic-gate ZDELAY(50), /* 1 */ 1480Sstevel@tonic-gate ZDELAY(75), /* 2 */ 1490Sstevel@tonic-gate ZDELAY(110), /* 3 */ 1500Sstevel@tonic-gate #ifdef lint 1510Sstevel@tonic-gate ZDELAY(134), /* 4 */ 1520Sstevel@tonic-gate #else 1530Sstevel@tonic-gate ZDELAY(269/2), 1540Sstevel@tonic-gate #endif 1550Sstevel@tonic-gate ZDELAY(150), /* 5 */ 1560Sstevel@tonic-gate ZDELAY(200), /* 6 */ 1570Sstevel@tonic-gate ZDELAY(300), /* 7 */ 1580Sstevel@tonic-gate ZDELAY(600), /* 8 */ 1590Sstevel@tonic-gate ZDELAY(1200), /* 9 */ 1600Sstevel@tonic-gate ZDELAY(1800), /* 10 */ 1610Sstevel@tonic-gate ZDELAY(2400), /* 11 */ 1620Sstevel@tonic-gate ZDELAY(4800), /* 12 */ 1630Sstevel@tonic-gate ZDELAY(9600), /* 13 */ 1640Sstevel@tonic-gate ZDELAY(19200), /* 14 */ 1650Sstevel@tonic-gate ZDELAY(38400), /* 15 */ 1660Sstevel@tonic-gate ZDELAY(57600), /* 16 */ 1670Sstevel@tonic-gate ZDELAY(76800) /* 17 */ 1680Sstevel@tonic-gate }; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate ushort_t zslowat[NSPEED] = { 1710Sstevel@tonic-gate 3, /* 0 */ 1720Sstevel@tonic-gate 3, /* 1 */ 1730Sstevel@tonic-gate 3, /* 2 */ 1740Sstevel@tonic-gate 3, /* 3 */ 1750Sstevel@tonic-gate 3, /* 4 */ 1760Sstevel@tonic-gate 3, /* 5 */ 1770Sstevel@tonic-gate 3, /* 6 */ 1780Sstevel@tonic-gate 2, /* 7 */ 1790Sstevel@tonic-gate 2, /* 8 */ 1800Sstevel@tonic-gate 2, /* 9 */ 1810Sstevel@tonic-gate 2, /* 10 */ 1820Sstevel@tonic-gate 1, /* 11 */ 1830Sstevel@tonic-gate 1, /* 12 */ 1840Sstevel@tonic-gate 1, /* 13 */ 1850Sstevel@tonic-gate 1, /* 14 */ 1860Sstevel@tonic-gate 1, /* 15 */ 1870Sstevel@tonic-gate 1, /* 16 */ 1880Sstevel@tonic-gate 1 /* 17 */ 1890Sstevel@tonic-gate }; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate ushort_t zshiwat[NSPEED] = { 1920Sstevel@tonic-gate 0, /* 0 */ 1930Sstevel@tonic-gate 1, /* 1 */ 1940Sstevel@tonic-gate 1, /* 2 */ 1950Sstevel@tonic-gate 1, /* 3 */ 1960Sstevel@tonic-gate 1, /* 4 */ 1970Sstevel@tonic-gate 1, /* 5 */ 1980Sstevel@tonic-gate 1, /* 6 */ 1990Sstevel@tonic-gate 1, /* 7 */ 2000Sstevel@tonic-gate 1, /* 8 */ 2010Sstevel@tonic-gate 1, /* 9 */ 2020Sstevel@tonic-gate 1, /* 10 */ 2030Sstevel@tonic-gate 1, /* 11 */ 2040Sstevel@tonic-gate 1, /* 12 */ 2050Sstevel@tonic-gate 3, /* 13 */ 2060Sstevel@tonic-gate 3, /* 14 */ 2070Sstevel@tonic-gate 4, /* 15 */ 2080Sstevel@tonic-gate 4, /* 16 */ 2090Sstevel@tonic-gate 4 /* 17 */ 2100Sstevel@tonic-gate }; 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate #define SLAVIO_BUG /* this workaround required to fix bug 1102778 */ 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate #define SPEED(cflag) \ 2150Sstevel@tonic-gate ((cflag) & CBAUDEXT) ? \ 2160Sstevel@tonic-gate (((cflag) & 0x1) + CBAUD + 1) : ((cflag) & CBAUD) 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * Special macros to handle STREAMS operations. 2200Sstevel@tonic-gate * These are required to address memory leakage problems. 2210Sstevel@tonic-gate * WARNING : the macro do NOT call ZSSETSOFT 2220Sstevel@tonic-gate */ 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* 2250Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex. 2260Sstevel@tonic-gate */ 2270Sstevel@tonic-gate #define ZSA_GETBLOCK(zs, allocbcount) \ 2280Sstevel@tonic-gate { \ 2290Sstevel@tonic-gate register int n = zsa_rstandby; \ 2300Sstevel@tonic-gate while (--n >= 0 && allocbcount > 0) { \ 2310Sstevel@tonic-gate if (!za->za_rstandby[n]) { \ 2320Sstevel@tonic-gate if ((za->za_rstandby[n] = allocb(ZSA_RCV_SIZE, \ 2330Sstevel@tonic-gate BPRI_MED)) == NULL) { \ 2340Sstevel@tonic-gate if (za->za_bufcid == 0) { \ 2350Sstevel@tonic-gate za->za_bufcid = bufcall(ZSA_RCV_SIZE, \ 2360Sstevel@tonic-gate BPRI_MED, \ 2370Sstevel@tonic-gate zsa_callback, zs); \ 2380Sstevel@tonic-gate break; \ 2390Sstevel@tonic-gate } \ 2400Sstevel@tonic-gate } \ 2410Sstevel@tonic-gate allocbcount--; \ 2420Sstevel@tonic-gate } \ 2430Sstevel@tonic-gate } \ 2440Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { \ 2450Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); \ 2460Sstevel@tonic-gate if (!(zs->zs_wreg[5] & ZSWR5_RTS)) { \ 2470Sstevel@tonic-gate register int usedcnt = 0; \ 2480Sstevel@tonic-gate for (n = 0; n < zsa_rstandby; n++) \ 2490Sstevel@tonic-gate if (!za->za_rstandby[n]) \ 2500Sstevel@tonic-gate usedcnt++; \ 2510Sstevel@tonic-gate if ((ushort_t)usedcnt <= \ 2520Sstevel@tonic-gate zslowat[SPEED(za->za_ttycommon.t_cflag)]) \ 2530Sstevel@tonic-gate SCC_BIS(5, ZSWR5_RTS); \ 2540Sstevel@tonic-gate } \ 2550Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \ 2560Sstevel@tonic-gate } \ 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /* 2600Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex. 2610Sstevel@tonic-gate */ 2620Sstevel@tonic-gate #define ZSA_ALLOCB(mp) \ 2630Sstevel@tonic-gate { \ 2640Sstevel@tonic-gate register int n = zsa_rstandby; \ 2650Sstevel@tonic-gate while (--n >= 0) { \ 2660Sstevel@tonic-gate if ((mp = za->za_rstandby[n]) != NULL) { \ 2670Sstevel@tonic-gate za->za_rstandby[n] = NULL; \ 2680Sstevel@tonic-gate break; \ 2690Sstevel@tonic-gate } \ 2700Sstevel@tonic-gate } \ 2710Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { \ 2720Sstevel@tonic-gate if (!mp) { \ 2730Sstevel@tonic-gate if (zs->zs_wreg[5] & ZSWR5_RTS) \ 2740Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS); \ 2750Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d: message lost\n", \ 2760Sstevel@tonic-gate UNIT(za->za_dev)); \ 2770Sstevel@tonic-gate } else if (zs->zs_wreg[5] & ZSWR5_RTS) { \ 2780Sstevel@tonic-gate register int usedcnt = 0; \ 2790Sstevel@tonic-gate for (n = 0; n < zsa_rstandby; n++) \ 2800Sstevel@tonic-gate if (!za->za_rstandby[n]) \ 2810Sstevel@tonic-gate usedcnt++; \ 2820Sstevel@tonic-gate if ((ushort_t)usedcnt >= (zsa_rstandby - \ 2830Sstevel@tonic-gate zshiwat[SPEED(za->za_ttycommon.t_cflag)])) \ 2840Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS); \ 2850Sstevel@tonic-gate } \ 2860Sstevel@tonic-gate } \ 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * Should get the spin (zs_excl_hi) mutex. 2910Sstevel@tonic-gate */ 2920Sstevel@tonic-gate #define ZSA_QREPLY(q, mp) \ 2930Sstevel@tonic-gate { \ 2940Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); \ 2950Sstevel@tonic-gate ZSA_PUTQ(mp); \ 2960Sstevel@tonic-gate ZSSETSOFT(zs); \ 2970Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \ 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* 3010Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex. 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate #define ZSA_PUTQ(mp) \ 3040Sstevel@tonic-gate { \ 3050Sstevel@tonic-gate register int wptr, rptr; \ 3060Sstevel@tonic-gate wptr = za->za_rdone_wptr; \ 3070Sstevel@tonic-gate rptr = za->za_rdone_rptr; \ 3080Sstevel@tonic-gate za->za_rdone[wptr] = mp; \ 3090Sstevel@tonic-gate if ((wptr)+1 == zsa_rdone) { \ 3100Sstevel@tonic-gate za->za_rdone_wptr = wptr = 0; \ 3110Sstevel@tonic-gate } else \ 3120Sstevel@tonic-gate za->za_rdone_wptr = ++wptr; \ 3130Sstevel@tonic-gate if (wptr == rptr) { \ 3140Sstevel@tonic-gate SCC_BIC(1, ZSWR1_INIT); \ 3150Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d disabled: input buffer overflow", \ 3160Sstevel@tonic-gate UNIT(za->za_dev)); \ 3170Sstevel@tonic-gate } \ 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate /* 3210Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex. 3220Sstevel@tonic-gate */ 3230Sstevel@tonic-gate #define ZSA_KICK_RCV \ 3240Sstevel@tonic-gate { \ 3250Sstevel@tonic-gate register mblk_t *mp = za->za_rcvblk; \ 3260Sstevel@tonic-gate if (mp) { \ 3270Sstevel@tonic-gate if (zs->zs_rd_cur) { /* M_DATA */ \ 3280Sstevel@tonic-gate mp->b_wptr = zs->zs_rd_cur; \ 3290Sstevel@tonic-gate zs->zs_rd_cur = NULL; \ 3300Sstevel@tonic-gate zs->zs_rd_lim = NULL; \ 3310Sstevel@tonic-gate } \ 3320Sstevel@tonic-gate za->za_rcvblk = NULL; \ 3330Sstevel@tonic-gate ZSA_PUTQ(mp); \ 3340Sstevel@tonic-gate ZSSETSOFT(zs); \ 3350Sstevel@tonic-gate } \ 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate #define ZSA_SEEQ(mp) \ 3390Sstevel@tonic-gate { \ 3400Sstevel@tonic-gate if (za->za_rdone_rptr != za->za_rdone_wptr) { \ 3410Sstevel@tonic-gate mp = za->za_rdone[za->za_rdone_rptr]; \ 3420Sstevel@tonic-gate } else { \ 3430Sstevel@tonic-gate mp = NULL; \ 3440Sstevel@tonic-gate } \ 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate /* 3490Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex. 3500Sstevel@tonic-gate */ 3510Sstevel@tonic-gate #define ZSA_GETQ(mp) \ 3520Sstevel@tonic-gate { \ 3530Sstevel@tonic-gate if (za->za_rdone_rptr != za->za_rdone_wptr) { \ 3540Sstevel@tonic-gate mp = za->za_rdone[za->za_rdone_rptr]; \ 3550Sstevel@tonic-gate za->za_rdone[za->za_rdone_rptr++] = NULL; \ 3560Sstevel@tonic-gate if (za->za_rdone_rptr == zsa_rdone) \ 3570Sstevel@tonic-gate za->za_rdone_rptr = 0; \ 3580Sstevel@tonic-gate } else { \ 3590Sstevel@tonic-gate mp = NULL; \ 3600Sstevel@tonic-gate } \ 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate /* 3640Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex. 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate #define ZSA_FLUSHQ \ 3670Sstevel@tonic-gate { \ 3680Sstevel@tonic-gate register mblk_t *tmp; \ 3690Sstevel@tonic-gate for (;;) { \ 3700Sstevel@tonic-gate ZSA_GETQ(tmp); \ 3710Sstevel@tonic-gate if (!(tmp)) \ 3720Sstevel@tonic-gate break; \ 3730Sstevel@tonic-gate freemsg(tmp); \ 3740Sstevel@tonic-gate } \ 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate /* 3790Sstevel@tonic-gate * Logging definitions 3800Sstevel@tonic-gate */ 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate #ifdef ZSA_DEBUG 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate #ifdef ZS_DEBUG_ALL 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate extern char zs_h_log[]; 3870Sstevel@tonic-gate extern int zs_h_log_n; 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate #define zsa_h_log_clear 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate #define zsa_h_log_add(c) \ 3920Sstevel@tonic-gate { \ 3930Sstevel@tonic-gate if (zs_h_log_n >= ZS_H_LOG_MAX) \ 3940Sstevel@tonic-gate zs_h_log_n = 0; \ 3950Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = 'A' + zs->zs_unit; \ 3960Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = c; \ 3970Sstevel@tonic-gate zs_h_log[zs_h_log_n] = '\0'; \ 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate #else /* ZS_DEBUG_ALL */ 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate #define ZSA_H_LOG_MAX 0x4000 4030Sstevel@tonic-gate char zsa_h_log[40][ZSA_H_LOG_MAX +10]; 4040Sstevel@tonic-gate int zsa_h_log_n[40]; 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate #define zsa_h_log_add(c) \ 4070Sstevel@tonic-gate { \ 4080Sstevel@tonic-gate if (zsa_h_log_n[zs->zs_unit] >= ZSA_H_LOG_MAX) \ 4090Sstevel@tonic-gate zsa_h_log_n[zs->zs_unit] = 0; \ 4100Sstevel@tonic-gate zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]++] = c; \ 4110Sstevel@tonic-gate zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]] = '\0'; \ 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate #define zsa_h_log_clear \ 4150Sstevel@tonic-gate { \ 4160Sstevel@tonic-gate register char *p; \ 4170Sstevel@tonic-gate for (p = &zsa_h_log[zs->zs_unit][ZSA_H_LOG_MAX]; \ 4180Sstevel@tonic-gate p >= &zsa_h_log[zs->zs_unit][0]; /* null */) \ 4190Sstevel@tonic-gate *p-- = '\0'; \ 4200Sstevel@tonic-gate zsa_h_log_n[zs->zs_unit] = 0; \ 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate #endif /* ZS_DEBUG_ALL */ 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate #define ZSA_R0_LOG(r0) \ 4260Sstevel@tonic-gate { \ 4270Sstevel@tonic-gate if (r0 & ZSRR0_RX_READY) zsa_h_log_add('R'); \ 4280Sstevel@tonic-gate if (r0 & ZSRR0_TIMER) zsa_h_log_add('Z'); \ 4290Sstevel@tonic-gate if (r0 & ZSRR0_TX_READY) zsa_h_log_add('T'); \ 4300Sstevel@tonic-gate if (r0 & ZSRR0_CD) zsa_h_log_add('D'); \ 4310Sstevel@tonic-gate if (r0 & ZSRR0_SYNC) zsa_h_log_add('S'); \ 4320Sstevel@tonic-gate if (r0 & ZSRR0_CTS) zsa_h_log_add('C'); \ 4330Sstevel@tonic-gate if (r0 & ZSRR0_TXUNDER) zsa_h_log_add('U'); \ 4340Sstevel@tonic-gate if (r0 & ZSRR0_BREAK) zsa_h_log_add('B'); \ 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate #else /* ZSA_DEBUG */ 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate #define zsa_h_log_clear 4400Sstevel@tonic-gate #define zsa_h_log_add(c) 4410Sstevel@tonic-gate #define ZSA_R0_LOG(r0) 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate #endif /* ZSA_DEBUG */ 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate static int zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 4480Sstevel@tonic-gate static int zsa_close(queue_t *q, int flag); 4490Sstevel@tonic-gate static void zsa_wput(queue_t *q, mblk_t *mp); 4500Sstevel@tonic-gate static void zsa_rsrv(queue_t *q); 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate static struct module_info asyncm_info = { 4530Sstevel@tonic-gate 0, 4540Sstevel@tonic-gate "zs", 4550Sstevel@tonic-gate 0, 4560Sstevel@tonic-gate INFPSZ, 4570Sstevel@tonic-gate 2048, 4580Sstevel@tonic-gate 128 4590Sstevel@tonic-gate }; 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate static struct qinit async_rinit = { 4620Sstevel@tonic-gate putq, 4630Sstevel@tonic-gate (int (*)())zsa_rsrv, 4640Sstevel@tonic-gate zsa_open, 4650Sstevel@tonic-gate zsa_close, 4660Sstevel@tonic-gate NULL, 4670Sstevel@tonic-gate &asyncm_info, 4680Sstevel@tonic-gate NULL 4690Sstevel@tonic-gate }; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate static struct qinit async_winit = { 4720Sstevel@tonic-gate (int (*)())zsa_wput, 4730Sstevel@tonic-gate NULL, 4740Sstevel@tonic-gate NULL, 4750Sstevel@tonic-gate NULL, 4760Sstevel@tonic-gate NULL, 4770Sstevel@tonic-gate &asyncm_info, 4780Sstevel@tonic-gate NULL 4790Sstevel@tonic-gate }; 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate struct streamtab asynctab = { 4820Sstevel@tonic-gate &async_rinit, 4830Sstevel@tonic-gate &async_winit, 4840Sstevel@tonic-gate NULL, 4850Sstevel@tonic-gate NULL, 4860Sstevel@tonic-gate }; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate /* 4890Sstevel@tonic-gate * The async interrupt entry points. 4900Sstevel@tonic-gate */ 4910Sstevel@tonic-gate static void zsa_txint(struct zscom *zs); 4920Sstevel@tonic-gate static void zsa_xsint(struct zscom *zs); 4930Sstevel@tonic-gate static void zsa_rxint(struct zscom *zs); 4940Sstevel@tonic-gate static void zsa_srint(struct zscom *zs); 4950Sstevel@tonic-gate static int zsa_softint(struct zscom *zs); 4960Sstevel@tonic-gate static int zsa_suspend(struct zscom *zs); 4970Sstevel@tonic-gate static int zsa_resume(struct zscom *zs); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate static void 5000Sstevel@tonic-gate zsa_null(struct zscom *zs) 5010Sstevel@tonic-gate { 5020Sstevel@tonic-gate /* LINTED */ 5030Sstevel@tonic-gate register short c; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 5060Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 5070Sstevel@tonic-gate c = SCC_READDATA(); 5080Sstevel@tonic-gate ZSDELAY(); 5090Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 5100Sstevel@tonic-gate } 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate /*ARGSUSED*/ 5130Sstevel@tonic-gate static int 5140Sstevel@tonic-gate zsa_null_int(struct zscom *zs) 5150Sstevel@tonic-gate { 5160Sstevel@tonic-gate return (0); 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate struct zsops zsops_null_async = { 5200Sstevel@tonic-gate zsa_null, 5210Sstevel@tonic-gate zsa_null, 5220Sstevel@tonic-gate zsa_null, 5230Sstevel@tonic-gate zsa_null, 5240Sstevel@tonic-gate zsa_null_int, 5250Sstevel@tonic-gate zsa_null_int, 5260Sstevel@tonic-gate zsa_null_int 5270Sstevel@tonic-gate }; 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate struct zsops zsops_async = { 5300Sstevel@tonic-gate zsa_txint, 5310Sstevel@tonic-gate zsa_xsint, 5320Sstevel@tonic-gate zsa_rxint, 5330Sstevel@tonic-gate zsa_srint, 5340Sstevel@tonic-gate zsa_softint, 5350Sstevel@tonic-gate zsa_suspend, 5360Sstevel@tonic-gate zsa_resume 5370Sstevel@tonic-gate }; 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate static int dmtozs(int bits); 5400Sstevel@tonic-gate static int zstodm(int bits); 5410Sstevel@tonic-gate static void zsa_restart(void *); 5420Sstevel@tonic-gate static void zsa_reioctl(void *); 5430Sstevel@tonic-gate static void zsa_ioctl(struct asyncline *za, queue_t *q, mblk_t *mp); 5440Sstevel@tonic-gate static void zsa_program(struct asyncline *za, int setibaud); 5450Sstevel@tonic-gate static void zsa_start(struct zscom *zs); 5460Sstevel@tonic-gate static void zsa_kick_rcv(void *); 5470Sstevel@tonic-gate static void zsa_callback(void *); 5480Sstevel@tonic-gate static void zsa_set_za_rcv_flags_mask(struct asyncline *za); 5490Sstevel@tonic-gate int zsgetspeed(dev_t dev); 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate static boolean_t abort_charseq_recognize(uchar_t ch); 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate /* ARGSUSED */ 5540Sstevel@tonic-gate int 5550Sstevel@tonic-gate zsc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 5560Sstevel@tonic-gate void **result) 5570Sstevel@tonic-gate { 5580Sstevel@tonic-gate register dev_t dev = (dev_t)arg; 5590Sstevel@tonic-gate register int unit, error; 5600Sstevel@tonic-gate register struct zscom *zs; 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate if ((unit = UNIT(dev)) >= nzs) 5630Sstevel@tonic-gate return (DDI_FAILURE); 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate switch (infocmd) { 5660Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 5670Sstevel@tonic-gate zs = &zscom[unit]; 5680Sstevel@tonic-gate *result = zs->zs_dip; 5690Sstevel@tonic-gate error = DDI_SUCCESS; 5700Sstevel@tonic-gate break; 5710Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 572*796Smathue *result = (void *)(uintptr_t)(unit / 2); 5730Sstevel@tonic-gate error = DDI_SUCCESS; 5740Sstevel@tonic-gate break; 5750Sstevel@tonic-gate default: 5760Sstevel@tonic-gate error = DDI_FAILURE; 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate return (error); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate /* 5820Sstevel@tonic-gate * The Asynchronous Driver. 5830Sstevel@tonic-gate */ 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate /* 5860Sstevel@tonic-gate * Determine if the zsminor device is in use as either a stdin or stdout 5870Sstevel@tonic-gate * device, so we can be careful about how we initialize the DUART, if 5880Sstevel@tonic-gate * it is, in fact, in use. 5890Sstevel@tonic-gate * 5900Sstevel@tonic-gate * Since this is expensive, we do it once and store away the answers, 5910Sstevel@tonic-gate * since this gets called a number of times per phyical zs device. 5920Sstevel@tonic-gate * Perhaps, this should be in a loadable module, so it can get thrown 5930Sstevel@tonic-gate * away after all the zs devices are attached? 5940Sstevel@tonic-gate */ 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* 5970Sstevel@tonic-gate * To determine if a given unit is being used by the PROM, 5980Sstevel@tonic-gate * we need to map stdin/stdout devices as known to the PROM 5990Sstevel@tonic-gate * to zs internal minor device numbers: 6000Sstevel@tonic-gate * 6010Sstevel@tonic-gate * PROM (real device) zs minor device 6020Sstevel@tonic-gate * 6030Sstevel@tonic-gate * "zs", 0, "a" 0 ttya 6040Sstevel@tonic-gate * "zs", 0, "b" 1 ttyb 6050Sstevel@tonic-gate * "zs", 1, "a" 2 keyboard 6060Sstevel@tonic-gate * "zs", 1, "b" 3 mouse 6070Sstevel@tonic-gate * "zs", 2, "a" 4 ttyc 6080Sstevel@tonic-gate * "zs", 2, "b" 5 ttyd 6090Sstevel@tonic-gate * 6100Sstevel@tonic-gate * The following value mapping lines assume that insource 6110Sstevel@tonic-gate * and outsink map as "screen, a, b, c, d, ...", and that 6120Sstevel@tonic-gate * zs minors are "a, b, kbd, mouse, c, d, ...". 6130Sstevel@tonic-gate */ 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate static int zsa_inuse; /* Strictly for debugging */ 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate int 6180Sstevel@tonic-gate zsa_channel_is_active_in_rom(dev_info_t *dev, int zsminor) 6190Sstevel@tonic-gate { 6200Sstevel@tonic-gate char pathname[OBP_MAXPATHLEN]; 6210Sstevel@tonic-gate char default_pathname[OBP_MAXPATHLEN]; 6220Sstevel@tonic-gate char *stdioname; 6230Sstevel@tonic-gate char minordata[3]; 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate /* 6260Sstevel@tonic-gate * Basically, get my name and compare it to stdio devnames 6270Sstevel@tonic-gate * and if we get a match, then the device is in use as either 6280Sstevel@tonic-gate * stdin or stdout device (console tip line or keyboard device). 6290Sstevel@tonic-gate * 6300Sstevel@tonic-gate * We get two forms of the pathname, one complete with the 6310Sstevel@tonic-gate * the channel number, and if the channel is 'a', then 6320Sstevel@tonic-gate * we also deal with the user's ability to default to 6330Sstevel@tonic-gate * channel 'a', by omitting the channel number option. 6340Sstevel@tonic-gate * We then compare these pathnames to both the stdin and 6350Sstevel@tonic-gate * stdout pathnames. If any of these match, then the channel 6360Sstevel@tonic-gate * is in use. 6370Sstevel@tonic-gate */ 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate (void) ddi_pathname(dev, pathname); /* device pathname */ 6400Sstevel@tonic-gate default_pathname[0] = (char)0; /* default pathname if channel 'a' */ 6410Sstevel@tonic-gate if ((zsminor & 1) == 0) 6420Sstevel@tonic-gate (void) strcpy(default_pathname, pathname); 6430Sstevel@tonic-gate minordata[0] = ':'; 6440Sstevel@tonic-gate minordata[1] = (char)('a' + (zsminor & 1)); 6450Sstevel@tonic-gate minordata[2] = (char)0; 6460Sstevel@tonic-gate (void) strcat(pathname, minordata); 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate stdioname = prom_stdinpath(); 6490Sstevel@tonic-gate if (strcmp(pathname, stdioname) == 0) { 6500Sstevel@tonic-gate zsa_inuse |= (1 << zsminor); 6510Sstevel@tonic-gate return (1); 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate if (strcmp(default_pathname, stdioname) == 0) { 6540Sstevel@tonic-gate zsa_inuse |= (1 << zsminor); 6550Sstevel@tonic-gate return (1); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate stdioname = prom_stdoutpath(); 6590Sstevel@tonic-gate if (strcmp(pathname, stdioname) == 0) { 6600Sstevel@tonic-gate zsa_inuse |= (1 << zsminor); 6610Sstevel@tonic-gate return (1); 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate if (strcmp(default_pathname, stdioname) == 0) { 6640Sstevel@tonic-gate zsa_inuse |= (1 << zsminor); 6650Sstevel@tonic-gate return (1); 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate return (0); 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate /* 6720Sstevel@tonic-gate * Initialize zs 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate void 6750Sstevel@tonic-gate zsa_init(struct zscom *zs) 6760Sstevel@tonic-gate { 6770Sstevel@tonic-gate /* 6780Sstevel@tonic-gate * This routine is called near the end of the zs module's attach 6790Sstevel@tonic-gate * process. It initializes the TTY protocol-private data for this 6800Sstevel@tonic-gate * channel that needs to be in place before interrupts are enabled. 6810Sstevel@tonic-gate */ 6820Sstevel@tonic-gate mutex_enter(zs->zs_excl); 6830Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * Raise modem control lines on serial ports associated 6870Sstevel@tonic-gate * with the console and (optionally) softcarrier lines. 6880Sstevel@tonic-gate * Drop modem control lines on all others so that modems 6890Sstevel@tonic-gate * will not answer and portselectors will skip these 6900Sstevel@tonic-gate * lines until they are opened by a getty. 6910Sstevel@tonic-gate */ 6920Sstevel@tonic-gate if (zsa_channel_is_active_in_rom(zs->zs_dip, zs->zs_unit)) 6930Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); /* raise dtr */ 6940Sstevel@tonic-gate else if (zsasoftdtr && (zssoftCAR[zs->zs_unit])) 6950Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); /* raise dtr */ 6960Sstevel@tonic-gate else 6970Sstevel@tonic-gate (void) zsmctl(zs, ZS_OFF, DMSET); /* drop dtr */ 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate if (zsa_rstandby > ZSA_MAX_RSTANDBY) 7000Sstevel@tonic-gate zsa_rstandby = ZSA_MAX_RSTANDBY; 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate if (zsa_rdone > ZSA_RDONE_MAX) 7030Sstevel@tonic-gate zsa_rdone = ZSA_RDONE_MAX; 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate if (zsa_grace_flow_control > ZSA_GRACE_MAX_FLOW_CONTROL) 7060Sstevel@tonic-gate zsa_grace_flow_control = ZSA_GRACE_MAX_FLOW_CONTROL; 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 7090Sstevel@tonic-gate mutex_exit(zs->zs_excl); 7100Sstevel@tonic-gate } 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate /* 7140Sstevel@tonic-gate * Open routine. 7150Sstevel@tonic-gate */ 7160Sstevel@tonic-gate /*ARGSUSED*/ 7170Sstevel@tonic-gate static int 7180Sstevel@tonic-gate zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 7190Sstevel@tonic-gate { 7200Sstevel@tonic-gate register struct zscom *zs; 7210Sstevel@tonic-gate register struct asyncline *za; 7220Sstevel@tonic-gate register int speed, unit; 7230Sstevel@tonic-gate struct termios *termiosp; 7240Sstevel@tonic-gate int len; 7250Sstevel@tonic-gate register int allocbcount = zsa_rstandby; 7260Sstevel@tonic-gate boolean_t set_zsoptinit = B_FALSE; 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate unit = UNIT(*dev); 7290Sstevel@tonic-gate if (unit >= nzs) 7300Sstevel@tonic-gate return (ENXIO); /* unit not configured */ 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* zscom is allocated by zsattach, and thus cannot be NULL here */ 7330Sstevel@tonic-gate zs = &zscom[unit]; 7340Sstevel@tonic-gate if (zs->zs_ops == NULL) { 7350Sstevel@tonic-gate return (ENXIO); /* device not found by autoconfig */ 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate mutex_enter(zs->zs_ocexcl); 7390Sstevel@tonic-gate mutex_enter(zs->zs_excl); 7400Sstevel@tonic-gate again: 7410Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) && 7420Sstevel@tonic-gate (zs->zs_ops != &zsops_async)) { 7430Sstevel@tonic-gate mutex_exit(zs->zs_excl); 7440Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 7450Sstevel@tonic-gate return (EBUSY); /* another protocol got here first */ 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate za = (struct asyncline *)&zs->zs_priv_str; 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate if (zs->zs_suspended) { 7510Sstevel@tonic-gate mutex_exit(zs->zs_excl); 7520Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 7530Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1); 7540Sstevel@tonic-gate mutex_enter(zs->zs_ocexcl); 7550Sstevel@tonic-gate mutex_enter(zs->zs_excl); 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate /* Mark device as busy (for power management) */ 7590Sstevel@tonic-gate (void) pm_busy_component(zs->zs_dip, unit%2+1); 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate if (zs->zs_ops == &zsops_null) { 7620Sstevel@tonic-gate bzero(za, sizeof (zs->zs_priv_str)); 7630Sstevel@tonic-gate za->za_common = zs; 7640Sstevel@tonic-gate if (zssoftCAR[zs->zs_unit]) 7650Sstevel@tonic-gate za->za_ttycommon.t_flags |= TS_SOFTCAR; 7660Sstevel@tonic-gate zsopinit(zs, &zsops_async); 7670Sstevel@tonic-gate set_zsoptinit = B_TRUE; 7680Sstevel@tonic-gate za->za_rdone_wptr = 0; 7690Sstevel@tonic-gate za->za_rdone_rptr = 0; 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate zs->zs_priv = (caddr_t)za; 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate /* 7750Sstevel@tonic-gate * Block waiting for carrier to come up, 7760Sstevel@tonic-gate * unless this is a no-delay open. 7770Sstevel@tonic-gate */ 7780Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 7790Sstevel@tonic-gate if (!(za->za_flags & ZAS_ISOPEN)) { 7800Sstevel@tonic-gate /* 7810Sstevel@tonic-gate * Get the default termios settings (cflag). 7820Sstevel@tonic-gate * These are stored as a property in the 7830Sstevel@tonic-gate * "options" node. 7840Sstevel@tonic-gate */ 7850Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 7860Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, 7870Sstevel@tonic-gate ddi_root_node(), 0, "ttymodes", 7880Sstevel@tonic-gate (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS && 7890Sstevel@tonic-gate len == sizeof (struct termios)) { 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate za->za_ttycommon.t_cflag = termiosp->c_cflag; 7920Sstevel@tonic-gate kmem_free(termiosp, len); 7930Sstevel@tonic-gate } else { 7940Sstevel@tonic-gate /* 7950Sstevel@tonic-gate * Gack! Whine about it. 7960Sstevel@tonic-gate */ 7970Sstevel@tonic-gate cmn_err(CE_WARN, 7980Sstevel@tonic-gate "zs: Couldn't get ttymodes property!"); 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 8010Sstevel@tonic-gate if ((*dev == rconsdev) || (*dev == kbddev) || 8020Sstevel@tonic-gate (*dev == stdindev)) { 8030Sstevel@tonic-gate speed = zsgetspeed(*dev); 8040Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~(CBAUD); 8050Sstevel@tonic-gate if (speed > CBAUD) { 8060Sstevel@tonic-gate za->za_ttycommon.t_cflag |= CBAUDEXT; 8070Sstevel@tonic-gate za->za_ttycommon.t_cflag |= 8080Sstevel@tonic-gate ((speed - CBAUD - 1) & CBAUD); 8090Sstevel@tonic-gate } else { 8100Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~CBAUDEXT; 8110Sstevel@tonic-gate za->za_ttycommon.t_cflag |= (speed & CBAUD); 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate za->za_overrun = 0; 8150Sstevel@tonic-gate za->za_ttycommon.t_iflag = 0; 8160Sstevel@tonic-gate za->za_ttycommon.t_iocpending = NULL; 8170Sstevel@tonic-gate za->za_ttycommon.t_size.ws_row = 0; 8180Sstevel@tonic-gate za->za_ttycommon.t_size.ws_col = 0; 8190Sstevel@tonic-gate za->za_ttycommon.t_size.ws_xpixel = 0; 8200Sstevel@tonic-gate za->za_ttycommon.t_size.ws_ypixel = 0; 8210Sstevel@tonic-gate za->za_dev = *dev; 8220Sstevel@tonic-gate za->za_wbufcid = 0; 8230Sstevel@tonic-gate zsa_program(za, za->za_ttycommon.t_cflag & (CIBAUDEXT|CIBAUD)); 8240Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(za); 8250Sstevel@tonic-gate } else if ((za->za_ttycommon.t_flags & TS_XCLUDE) && 8260Sstevel@tonic-gate secpolicy_excl_open(cr) != 0) { 8270Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 8280Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 8290Sstevel@tonic-gate zsopinit(zs, &zsops_null); 8300Sstevel@tonic-gate mutex_exit(zs->zs_excl); 8310Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 8320Sstevel@tonic-gate return (EBUSY); 8330Sstevel@tonic-gate } else if ((*dev & OUTLINE) && !(za->za_flags & ZAS_OUT)) { 8340Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 8350Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 8360Sstevel@tonic-gate zsopinit(zs, &zsops_null); 8370Sstevel@tonic-gate mutex_exit(zs->zs_excl); 8380Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 8390Sstevel@tonic-gate return (EBUSY); 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate if (*dev & OUTLINE) 8430Sstevel@tonic-gate za->za_flags |= ZAS_OUT; 8440Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* 8470Sstevel@tonic-gate * Check carrier. 8480Sstevel@tonic-gate */ 8490Sstevel@tonic-gate if ((za->za_ttycommon.t_flags & TS_SOFTCAR) || 8500Sstevel@tonic-gate (zsmctl(zs, 0, DMGET) & ZSRR0_CD)) 8510Sstevel@tonic-gate za->za_flags |= ZAS_CARR_ON; 8520Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 8530Sstevel@tonic-gate 8540Sstevel@tonic-gate /* 8550Sstevel@tonic-gate * If FNDELAY and FNONBLOCK are clear, block until carrier up. 8560Sstevel@tonic-gate * Quit on interrupt. 8570Sstevel@tonic-gate */ 8580Sstevel@tonic-gate if (!(flag & (FNDELAY|FNONBLOCK)) && 8590Sstevel@tonic-gate !(za->za_ttycommon.t_cflag & CLOCAL)) { 8600Sstevel@tonic-gate if (!(za->za_flags & (ZAS_CARR_ON|ZAS_OUT)) || 8610Sstevel@tonic-gate ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE))) { 8620Sstevel@tonic-gate za->za_flags |= ZAS_WOPEN; 8630Sstevel@tonic-gate mutex_exit(zs->zs_excl); 8640Sstevel@tonic-gate if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_ocexcl) == 0) { 8650Sstevel@tonic-gate mutex_enter(zs->zs_excl); 8660Sstevel@tonic-gate if (zs->zs_suspended) { 8670Sstevel@tonic-gate mutex_exit(zs->zs_excl); 8680Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 8690Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 8700Sstevel@tonic-gate 0, 1); 8710Sstevel@tonic-gate mutex_enter(zs->zs_ocexcl); 8720Sstevel@tonic-gate mutex_enter(zs->zs_excl); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate za->za_flags &= ~ZAS_WOPEN; 8750Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 8760Sstevel@tonic-gate zsopinit(zs, &zsops_null); 8770Sstevel@tonic-gate mutex_exit(zs->zs_excl); 8780Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 8790Sstevel@tonic-gate return (EINTR); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate mutex_enter(zs->zs_excl); 8820Sstevel@tonic-gate za->za_flags &= ~ZAS_WOPEN; 8830Sstevel@tonic-gate if ((zs->zs_ops == &zsops_null) || 8840Sstevel@tonic-gate (zs->zs_ops == &zsops_async)) 8850Sstevel@tonic-gate goto again; 8860Sstevel@tonic-gate else { 8870Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 8880Sstevel@tonic-gate zsopinit(zs, &zsops_null); 8890Sstevel@tonic-gate mutex_exit(zs->zs_excl); 8900Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 8910Sstevel@tonic-gate return (EBUSY); 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate } else if ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE)) { 8950Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN)) 8960Sstevel@tonic-gate zsopinit(zs, &zsops_null); 8970Sstevel@tonic-gate mutex_exit(zs->zs_excl); 8980Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 8990Sstevel@tonic-gate return (EBUSY); 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate za->za_ttycommon.t_readq = rq; 9030Sstevel@tonic-gate za->za_ttycommon.t_writeq = WR(rq); 9040Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = (caddr_t)za; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate za->za_flags |= ZAS_ISOPEN; 9070Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount); 9080Sstevel@tonic-gate qprocson(rq); 9090Sstevel@tonic-gate mutex_exit(zs->zs_excl); 9100Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl); 9110Sstevel@tonic-gate return (0); 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate static void 9150Sstevel@tonic-gate zs_progress_check(void *arg) 9160Sstevel@tonic-gate { 9170Sstevel@tonic-gate struct asyncline *za = arg; 9180Sstevel@tonic-gate struct zscom *zs = za->za_common; 9190Sstevel@tonic-gate mblk_t *bp; 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate /* 9220Sstevel@tonic-gate * We define "progress" as either waiting on a timed break or delay, or 9230Sstevel@tonic-gate * having had at least one transmitter interrupt. If none of these are 9240Sstevel@tonic-gate * true, then just terminate the output and wake up that close thread. 9250Sstevel@tonic-gate */ 9260Sstevel@tonic-gate mutex_enter(zs->zs_excl); 9270Sstevel@tonic-gate if (!(zs->zs_flags & ZS_PROGRESS) && 9280Sstevel@tonic-gate !(za->za_flags & (ZAS_BREAK|ZAS_DELAY))) { 9290Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 9300Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 9310Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 9320Sstevel@tonic-gate zs->zs_wr_cur = NULL; 9330Sstevel@tonic-gate zs->zs_wr_lim = NULL; 9340Sstevel@tonic-gate bp = za->za_xmitblk; 9350Sstevel@tonic-gate za->za_xmitblk = NULL; 9360Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 9370Sstevel@tonic-gate zs->zs_timer = 0; 9380Sstevel@tonic-gate mutex_exit(zs->zs_excl); 9390Sstevel@tonic-gate if (bp != NULL) 9400Sstevel@tonic-gate freeb(bp); 9410Sstevel@tonic-gate /* 9420Sstevel@tonic-gate * Since this timer is running, we know that we're in exit(2). 9430Sstevel@tonic-gate * That means that the user can't possibly be waiting on any 9440Sstevel@tonic-gate * valid ioctl(2) completion anymore, and we should just flush 9450Sstevel@tonic-gate * everything. 9460Sstevel@tonic-gate */ 9470Sstevel@tonic-gate flushq(za->za_ttycommon.t_writeq, FLUSHALL); 9480Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 9490Sstevel@tonic-gate } else { 9500Sstevel@tonic-gate zs->zs_flags &= ~ZS_PROGRESS; 9510Sstevel@tonic-gate zs->zs_timer = timeout(zs_progress_check, za, 9520Sstevel@tonic-gate drv_usectohz(zs_drain_check)); 9530Sstevel@tonic-gate mutex_exit(zs->zs_excl); 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate } 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate /* 9580Sstevel@tonic-gate * Close routine. 9590Sstevel@tonic-gate * 9600Sstevel@tonic-gate * Important locking note: the zs_ocexcl lock is not held at all in this 9610Sstevel@tonic-gate * routine. This is intentional. That lock is used to coordinate multiple 9620Sstevel@tonic-gate * simultaneous opens on a stream, and there's no such thing as multiple 9630Sstevel@tonic-gate * simultaneous closes on a stream. 9640Sstevel@tonic-gate */ 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate /*ARGSUSED*/ 9670Sstevel@tonic-gate static int 9680Sstevel@tonic-gate zsa_close(queue_t *q, int flag) 9690Sstevel@tonic-gate { 9700Sstevel@tonic-gate struct asyncline *za; 9710Sstevel@tonic-gate struct zscom *zs; 9720Sstevel@tonic-gate int i; 9730Sstevel@tonic-gate mblk_t *bp; 9740Sstevel@tonic-gate timeout_id_t za_zsa_restart_id, za_kick_rcv_id; 9750Sstevel@tonic-gate bufcall_id_t za_bufcid, za_wbufcid; 9760Sstevel@tonic-gate int tmp; 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate za = q->q_ptr; 9790Sstevel@tonic-gate ASSERT(za != NULL); 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate zs = za->za_common; 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate mutex_enter(zs->zs_excl); 9840Sstevel@tonic-gate zs->zs_flags |= ZS_CLOSING; 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate /* 9870Sstevel@tonic-gate * There are two flavors of break -- timed (M_BREAK or TCSBRK) and 9880Sstevel@tonic-gate * untimed (TIOCSBRK). For the timed case, these are enqueued on our 9890Sstevel@tonic-gate * write queue and there's a timer running, so we don't have to worry 9900Sstevel@tonic-gate * about them. For the untimed case, though, the user obviously made a 9910Sstevel@tonic-gate * mistake, because these are handled immediately. We'll terminate the 9920Sstevel@tonic-gate * break now and honor his implicit request by discarding the rest of 9930Sstevel@tonic-gate * the data. 9940Sstevel@tonic-gate */ 9950Sstevel@tonic-gate if (!(za->za_flags & ZAS_BREAK) && (zs->zs_wreg[5] & ZSWR5_BREAK)) 9960Sstevel@tonic-gate goto nodrain; 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate /* 9990Sstevel@tonic-gate * If the user told us not to delay the close ("non-blocking"), then 10000Sstevel@tonic-gate * don't bother trying to drain. 10010Sstevel@tonic-gate * 10020Sstevel@tonic-gate * If the user did M_STOP (ASYNC_STOPPED), there's no hope of ever 10030Sstevel@tonic-gate * getting an M_START (since these messages aren't enqueued), and the 10040Sstevel@tonic-gate * only other way to clear the stop condition is by loss of DCD, which 10050Sstevel@tonic-gate * would discard the queue data. Thus, we drop the output data if 10060Sstevel@tonic-gate * ASYNC_STOPPED is set. 10070Sstevel@tonic-gate */ 10080Sstevel@tonic-gate if ((flag & (FNDELAY|FNONBLOCK)) || (za->za_flags & ZAS_STOPPED)) 10090Sstevel@tonic-gate goto nodrain; 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate /* 10120Sstevel@tonic-gate * If there's any pending output, then we have to try to drain it. 10130Sstevel@tonic-gate * There are two main cases to be handled: 10140Sstevel@tonic-gate * - called by close(2): need to drain until done or until 10150Sstevel@tonic-gate * a signal is received. No timeout. 10160Sstevel@tonic-gate * - called by exit(2): need to drain while making progress 10170Sstevel@tonic-gate * or until a timeout occurs. No signals. 10180Sstevel@tonic-gate * 10190Sstevel@tonic-gate * If we can't rely on receiving a signal to get us out of a hung 10200Sstevel@tonic-gate * session, then we have to use a timer. In this case, we set a timer 10210Sstevel@tonic-gate * to check for progress in sending the output data -- all that we ask 10220Sstevel@tonic-gate * (at each interval) is that there's been some progress made. Since 10230Sstevel@tonic-gate * the interrupt routine grabs buffers from the write queue, we can't 10240Sstevel@tonic-gate * trust changes in zs_wr_cur. Instead, we use a progress flag. 10250Sstevel@tonic-gate * 10260Sstevel@tonic-gate * Note that loss of carrier will cause the output queue to be flushed, 10270Sstevel@tonic-gate * and we'll wake up again and finish normally. 10280Sstevel@tonic-gate */ 10290Sstevel@tonic-gate if (!ddi_can_receive_sig() && zs_drain_check != 0) { 10300Sstevel@tonic-gate zs->zs_flags &= ~ZS_PROGRESS; 10310Sstevel@tonic-gate zs->zs_timer = timeout(zs_progress_check, za, 10320Sstevel@tonic-gate drv_usectohz(zs_drain_check)); 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate while (zs->zs_wr_cur != NULL || 10360Sstevel@tonic-gate za->za_ttycommon.t_writeq->q_first != NULL || 10370Sstevel@tonic-gate (za->za_flags & (ZAS_BUSY|ZAS_DELAY|ZAS_BREAK))) { 10380Sstevel@tonic-gate if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_excl) == 0) 10390Sstevel@tonic-gate break; 10400Sstevel@tonic-gate } 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate if (zs->zs_timer != 0) { 10430Sstevel@tonic-gate (void) untimeout(zs->zs_timer); 10440Sstevel@tonic-gate zs->zs_timer = 0; 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate 10470Sstevel@tonic-gate nodrain: 10480Sstevel@tonic-gate /* 10490Sstevel@tonic-gate * If break is in progress, stop it. 10500Sstevel@tonic-gate */ 10510Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 10520Sstevel@tonic-gate if (zs->zs_wreg[5] & ZSWR5_BREAK) { 10530Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK); 10540Sstevel@tonic-gate za->za_flags &= ~ZAS_BREAK; 10550Sstevel@tonic-gate } 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate za_wbufcid = za->za_wbufcid; 10580Sstevel@tonic-gate za_bufcid = za->za_bufcid; 10590Sstevel@tonic-gate za_zsa_restart_id = za->za_zsa_restart_id; 10600Sstevel@tonic-gate za_kick_rcv_id = za->za_kick_rcv_id; 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate za->za_wbufcid = za->za_bufcid = 0; 10630Sstevel@tonic-gate za->za_zsa_restart_id = za->za_kick_rcv_id = 0; 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate /* 10660Sstevel@tonic-gate * If line has HUPCL set or is incompletely opened, 10670Sstevel@tonic-gate * and it is not the console or the keyboard, 10680Sstevel@tonic-gate * fix up the modem lines. 10690Sstevel@tonic-gate */ 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate zsopinit(zs, &zsops_null_async); 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate /* 10740Sstevel@tonic-gate * Nobody, zsh or zs can now open this port until 10750Sstevel@tonic-gate * zsopinit(zs, &zsops_null); 10760Sstevel@tonic-gate * 10770Sstevel@tonic-gate */ 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate if ((za->za_dev != rconsdev) && (za->za_dev != kbddev) && 10800Sstevel@tonic-gate (za->za_dev != stdindev) && 10810Sstevel@tonic-gate (((za->za_flags & (ZAS_WOPEN|ZAS_ISOPEN)) != ZAS_ISOPEN) || 10820Sstevel@tonic-gate (za->za_ttycommon.t_cflag & HUPCL))) { 10830Sstevel@tonic-gate /* 10840Sstevel@tonic-gate * If DTR is being held high by softcarrier, 10850Sstevel@tonic-gate * set up the ZS_ON set; if not, hang up. 10860Sstevel@tonic-gate */ 10870Sstevel@tonic-gate if (zsasoftdtr && (za->za_ttycommon.t_flags & TS_SOFTCAR)) 10880Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); 10890Sstevel@tonic-gate else 10900Sstevel@tonic-gate (void) zsmctl(zs, ZS_OFF, DMSET); 10910Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 10920Sstevel@tonic-gate /* 10930Sstevel@tonic-gate * Don't let an interrupt in the middle of close 10940Sstevel@tonic-gate * bounce us back to the top; just continue 10950Sstevel@tonic-gate * closing as if nothing had happened. 10960Sstevel@tonic-gate */ 10970Sstevel@tonic-gate tmp = cv_timedwait_sig(&zs->zs_flags_cv, zs->zs_excl, 10980Sstevel@tonic-gate ddi_get_lbolt() + drv_usectohz(10000)); 10990Sstevel@tonic-gate if (zs->zs_suspended) { 11000Sstevel@tonic-gate mutex_exit(zs->zs_excl); 11010Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1); 11020Sstevel@tonic-gate mutex_enter(zs->zs_excl); 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate if (tmp == 0) 11050Sstevel@tonic-gate goto out; 11060Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 11070Sstevel@tonic-gate } 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate /* 11100Sstevel@tonic-gate * If nobody's now using it, turn off receiver interrupts. 11110Sstevel@tonic-gate */ 11120Sstevel@tonic-gate if ((za->za_flags & (ZAS_ISOPEN|ZAS_WOPEN)) == 0) 11130Sstevel@tonic-gate SCC_BIC(1, ZSWR1_RIE); 11140Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate out: 11170Sstevel@tonic-gate /* 11180Sstevel@tonic-gate * Clear out device state. 11190Sstevel@tonic-gate */ 11200Sstevel@tonic-gate ttycommon_close(&za->za_ttycommon); 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate za->za_ttycommon.t_readq = NULL; 11230Sstevel@tonic-gate za->za_ttycommon.t_writeq = NULL; 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 11260Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 11270Sstevel@tonic-gate zs->zs_wr_cur = NULL; 11280Sstevel@tonic-gate zs->zs_wr_lim = NULL; 11290Sstevel@tonic-gate bp = za->za_xmitblk; 11300Sstevel@tonic-gate za->za_xmitblk = NULL; 11310Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 11320Sstevel@tonic-gate if (bp) 11330Sstevel@tonic-gate freemsg(bp); 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 11360Sstevel@tonic-gate zs->zs_rd_cur = NULL; 11370Sstevel@tonic-gate zs->zs_rd_lim = NULL; 11380Sstevel@tonic-gate bp = za->za_rcvblk; 11390Sstevel@tonic-gate za->za_rcvblk = NULL; 11400Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 11410Sstevel@tonic-gate if (bp) 11420Sstevel@tonic-gate freemsg(bp); 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate for (i = 0; i < zsa_rstandby; i++) { 11450Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 11460Sstevel@tonic-gate bp = za->za_rstandby[i]; 11470Sstevel@tonic-gate za->za_rstandby[i] = NULL; 11480Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 11490Sstevel@tonic-gate if (bp) 11500Sstevel@tonic-gate freemsg(bp); 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate if (za->za_soft_active || za->za_kick_active) { 11540Sstevel@tonic-gate zs->zs_flags |= ZS_CLOSED; 11550Sstevel@tonic-gate while (za->za_soft_active || za->za_kick_active) 11560Sstevel@tonic-gate cv_wait(&zs->zs_flags_cv, zs->zs_excl); 11570Sstevel@tonic-gate } 11580Sstevel@tonic-gate if (zs->zs_suspended) { 11590Sstevel@tonic-gate mutex_exit(zs->zs_excl); 11600Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1); 11610Sstevel@tonic-gate mutex_enter(zs->zs_excl); 11620Sstevel@tonic-gate } 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate ZSA_FLUSHQ; 11650Sstevel@tonic-gate bzero(za, sizeof (struct asyncline)); 11660Sstevel@tonic-gate qprocsoff(q); 11670Sstevel@tonic-gate mutex_exit(zs->zs_excl); 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate /* 11700Sstevel@tonic-gate * Cancel outstanding "bufcall" request. 11710Sstevel@tonic-gate */ 11720Sstevel@tonic-gate if (za_wbufcid) 11730Sstevel@tonic-gate unbufcall(za_wbufcid); 11740Sstevel@tonic-gate if (za_bufcid) 11750Sstevel@tonic-gate unbufcall(za_bufcid); 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate /* 11780Sstevel@tonic-gate * Cancel outstanding timeout. 11790Sstevel@tonic-gate */ 11800Sstevel@tonic-gate if (za_zsa_restart_id) 11810Sstevel@tonic-gate (void) untimeout(za_zsa_restart_id); 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate if (za_kick_rcv_id) 11840Sstevel@tonic-gate (void) untimeout(za_kick_rcv_id); 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL; 11870Sstevel@tonic-gate zsopinit(zs, &zsops_null); 11880Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate /* Mark device as available for power management */ 11910Sstevel@tonic-gate (void) pm_idle_component(zs->zs_dip, zs->zs_unit%2+1); 11920Sstevel@tonic-gate return (0); 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate /* 11960Sstevel@tonic-gate * Put procedure for write queue. 11970Sstevel@tonic-gate * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here; 11980Sstevel@tonic-gate * set the flow control character for M_STOPI and M_STARTI messages; 11990Sstevel@tonic-gate * queue up M_BREAK, M_DELAY, and M_DATA messages for processing 12000Sstevel@tonic-gate * by the start routine, and then call the start routine; discard 12010Sstevel@tonic-gate * everything else. Note that this driver does not incorporate any 12020Sstevel@tonic-gate * mechanism to negotiate to handle the canonicalization process. 12030Sstevel@tonic-gate * It expects that these functions are handled in upper module(s), 12040Sstevel@tonic-gate * as we do in ldterm. 12050Sstevel@tonic-gate */ 12060Sstevel@tonic-gate static void 12070Sstevel@tonic-gate zsa_wput(queue_t *q, mblk_t *mp) 12080Sstevel@tonic-gate { 12090Sstevel@tonic-gate register struct asyncline *za; 12100Sstevel@tonic-gate register struct zscom *zs; 12110Sstevel@tonic-gate register struct copyresp *resp; 12120Sstevel@tonic-gate register mblk_t *bp = NULL; 12130Sstevel@tonic-gate int error; 12140Sstevel@tonic-gate struct iocblk *iocp; 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate za = (struct asyncline *)q->q_ptr; 12170Sstevel@tonic-gate zs = za->za_common; 12180Sstevel@tonic-gate if (zs->zs_flags & ZS_NEEDSOFT) { 12190Sstevel@tonic-gate zs->zs_flags &= ~ZS_NEEDSOFT; 12200Sstevel@tonic-gate (void) zsa_softint(zs); 12210Sstevel@tonic-gate } 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate switch (mp->b_datap->db_type) { 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate case M_STOP: 12260Sstevel@tonic-gate /* 12270Sstevel@tonic-gate * Since we don't do real DMA, we can just let the 12280Sstevel@tonic-gate * chip coast to a stop after applying the brakes. 12290Sstevel@tonic-gate */ 12300Sstevel@tonic-gate mutex_enter(zs->zs_excl); 12310Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 12320Sstevel@tonic-gate za->za_flags |= ZAS_STOPPED; 12330Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) { 12340Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 12350Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 12360Sstevel@tonic-gate bp = za->za_xmitblk; 12370Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur; 12380Sstevel@tonic-gate zs->zs_wr_cur = NULL; 12390Sstevel@tonic-gate zs->zs_wr_lim = NULL; 12400Sstevel@tonic-gate za->za_xmitblk = NULL; 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 12430Sstevel@tonic-gate if (bp) 12440Sstevel@tonic-gate (void) putbq(q, bp); 12450Sstevel@tonic-gate freemsg(mp); 12460Sstevel@tonic-gate mutex_exit(zs->zs_excl); 12470Sstevel@tonic-gate break; 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate case M_START: 12500Sstevel@tonic-gate mutex_enter(zs->zs_excl); 12510Sstevel@tonic-gate if (za->za_flags & ZAS_STOPPED) { 12520Sstevel@tonic-gate za->za_flags &= ~ZAS_STOPPED; 12530Sstevel@tonic-gate /* 12540Sstevel@tonic-gate * If an output operation is in progress, 12550Sstevel@tonic-gate * resume it. Otherwise, prod the start 12560Sstevel@tonic-gate * routine. 12570Sstevel@tonic-gate */ 12580Sstevel@tonic-gate zsa_start(zs); 12590Sstevel@tonic-gate } 12600Sstevel@tonic-gate freemsg(mp); 12610Sstevel@tonic-gate mutex_exit(zs->zs_excl); 12620Sstevel@tonic-gate break; 12630Sstevel@tonic-gate 12640Sstevel@tonic-gate case M_IOCTL: 12650Sstevel@tonic-gate mutex_enter(zs->zs_excl); 12660Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate switch (iocp->ioc_cmd) { 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate case TIOCGPPS: 12710Sstevel@tonic-gate /* 12720Sstevel@tonic-gate * Get PPS state. 12730Sstevel@tonic-gate */ 12740Sstevel@tonic-gate if (mp->b_cont != NULL) 12750Sstevel@tonic-gate freemsg(mp->b_cont); 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate mp->b_cont = allocb(sizeof (int), BPRI_HI); 12780Sstevel@tonic-gate if (mp->b_cont == NULL) { 12790Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 12800Sstevel@tonic-gate iocp->ioc_error = ENOMEM; 12810Sstevel@tonic-gate ZSA_QREPLY(q, mp); 12820Sstevel@tonic-gate break; 12830Sstevel@tonic-gate } 12840Sstevel@tonic-gate if (za->za_pps) 12850Sstevel@tonic-gate *(int *)mp->b_cont->b_wptr = 1; 12860Sstevel@tonic-gate else 12870Sstevel@tonic-gate *(int *)mp->b_cont->b_wptr = 0; 12880Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (int); 12890Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 12900Sstevel@tonic-gate iocp->ioc_count = sizeof (int); 12910Sstevel@tonic-gate ZSA_QREPLY(q, mp); 12920Sstevel@tonic-gate break; 12930Sstevel@tonic-gate 12940Sstevel@tonic-gate case TIOCSPPS: 12950Sstevel@tonic-gate /* 12960Sstevel@tonic-gate * Set PPS state. 12970Sstevel@tonic-gate */ 12980Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 12990Sstevel@tonic-gate if (error != 0) { 13000Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 13010Sstevel@tonic-gate iocp->ioc_error = error; 13020Sstevel@tonic-gate ZSA_QREPLY(q, mp); 13030Sstevel@tonic-gate break; 13040Sstevel@tonic-gate } 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate za->za_pps = (*(int *)mp->b_cont->b_rptr != 0); 13070Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 13080Sstevel@tonic-gate ZSA_QREPLY(q, mp); 13090Sstevel@tonic-gate break; 13100Sstevel@tonic-gate 13110Sstevel@tonic-gate case TIOCGPPSEV: 13120Sstevel@tonic-gate { 13130Sstevel@tonic-gate /* 13140Sstevel@tonic-gate * Get PPS event data. 13150Sstevel@tonic-gate */ 13160Sstevel@tonic-gate void *buf; 13170Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 13180Sstevel@tonic-gate struct ppsclockev32 p32; 13190Sstevel@tonic-gate #endif 13200Sstevel@tonic-gate 13210Sstevel@tonic-gate if (mp->b_cont != NULL) { 13220Sstevel@tonic-gate freemsg(mp->b_cont); 13230Sstevel@tonic-gate mp->b_cont = NULL; 13240Sstevel@tonic-gate } 13250Sstevel@tonic-gate if (za->za_pps == NULL) { 13260Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 13270Sstevel@tonic-gate iocp->ioc_error = ENXIO; 13280Sstevel@tonic-gate ZSA_QREPLY(q, mp); 13290Sstevel@tonic-gate break; 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 13330Sstevel@tonic-gate if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) { 13340Sstevel@tonic-gate TIMEVAL_TO_TIMEVAL32(&p32.tv, &ppsclockev.tv); 13350Sstevel@tonic-gate p32.serial = ppsclockev.serial; 13360Sstevel@tonic-gate buf = &p32; 13370Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ppsclockev32); 13380Sstevel@tonic-gate } else 13390Sstevel@tonic-gate #endif 13400Sstevel@tonic-gate { 13410Sstevel@tonic-gate buf = &ppsclockev; 13420Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ppsclockev); 13430Sstevel@tonic-gate } 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate if ((bp = allocb(iocp->ioc_count, BPRI_HI)) == NULL) { 13460Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 13470Sstevel@tonic-gate iocp->ioc_error = ENOMEM; 13480Sstevel@tonic-gate ZSA_QREPLY(q, mp); 13490Sstevel@tonic-gate break; 13500Sstevel@tonic-gate } 13510Sstevel@tonic-gate mp->b_cont = bp; 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate bcopy(buf, bp->b_wptr, iocp->ioc_count); 13540Sstevel@tonic-gate bp->b_wptr += iocp->ioc_count; 13550Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 13560Sstevel@tonic-gate ZSA_QREPLY(q, mp); 13570Sstevel@tonic-gate break; 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate case TCSETSW: 13610Sstevel@tonic-gate case TCSETSF: 13620Sstevel@tonic-gate case TCSETAW: 13630Sstevel@tonic-gate case TCSETAF: 13640Sstevel@tonic-gate case TCSBRK: 13650Sstevel@tonic-gate /* 13660Sstevel@tonic-gate * The changes do not take effect until all 13670Sstevel@tonic-gate * output queued before them is drained. 13680Sstevel@tonic-gate * Put this message on the queue, so that 13690Sstevel@tonic-gate * "zsa_start" will see it when it's done 13700Sstevel@tonic-gate * with the output before it. Poke the 13710Sstevel@tonic-gate * start routine, just in case. 13720Sstevel@tonic-gate */ 13730Sstevel@tonic-gate (void) putq(q, mp); 13740Sstevel@tonic-gate zsa_start(zs); 13750Sstevel@tonic-gate break; 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate default: 13780Sstevel@tonic-gate /* 13790Sstevel@tonic-gate * Do it now. 13800Sstevel@tonic-gate */ 13810Sstevel@tonic-gate zsa_ioctl(za, q, mp); 13820Sstevel@tonic-gate break; 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate mutex_exit(zs->zs_excl); 13850Sstevel@tonic-gate break; 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate case M_IOCDATA: 13890Sstevel@tonic-gate 13900Sstevel@tonic-gate mutex_enter(zs->zs_excl); 13910Sstevel@tonic-gate resp = (struct copyresp *)mp->b_rptr; 13920Sstevel@tonic-gate if (resp->cp_rval) { 13930Sstevel@tonic-gate /* 13940Sstevel@tonic-gate * Just free message on failure. 13950Sstevel@tonic-gate */ 13960Sstevel@tonic-gate freemsg(mp); 13970Sstevel@tonic-gate mutex_exit(zs->zs_excl); 13980Sstevel@tonic-gate break; 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate switch (resp->cp_cmd) { 14010Sstevel@tonic-gate 14020Sstevel@tonic-gate case TIOCMSET: 14030Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 14040Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr), 14050Sstevel@tonic-gate DMSET); 14060Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 14070Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 14080Sstevel@tonic-gate ZSA_QREPLY(q, mp); 14090Sstevel@tonic-gate break; 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate case TIOCMBIS: 14120Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 14130Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr), 14140Sstevel@tonic-gate DMBIS); 14150Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 14160Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 14170Sstevel@tonic-gate ZSA_QREPLY(q, mp); 14180Sstevel@tonic-gate break; 14190Sstevel@tonic-gate 14200Sstevel@tonic-gate case TIOCMBIC: 14210Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 14220Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr), 14230Sstevel@tonic-gate DMBIC); 14240Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 14250Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 14260Sstevel@tonic-gate ZSA_QREPLY(q, mp); 14270Sstevel@tonic-gate break; 14280Sstevel@tonic-gate 14290Sstevel@tonic-gate case TIOCMGET: 14300Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 14310Sstevel@tonic-gate ZSA_QREPLY(q, mp); 14320Sstevel@tonic-gate break; 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate default: 14350Sstevel@tonic-gate freemsg(mp); 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate } 14380Sstevel@tonic-gate mutex_exit(zs->zs_excl); 14390Sstevel@tonic-gate break; 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate 14420Sstevel@tonic-gate case M_FLUSH: 14430Sstevel@tonic-gate mutex_enter(zs->zs_excl); 14440Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate /* 14470Sstevel@tonic-gate * Abort any output in progress. 14480Sstevel@tonic-gate */ 14490Sstevel@tonic-gate if (za->za_flags & ZAS_BUSY) { 14500Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 14510Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 14520Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 14530Sstevel@tonic-gate zs->zs_wr_cur = NULL; 14540Sstevel@tonic-gate zs->zs_wr_lim = NULL; 14550Sstevel@tonic-gate bp = za->za_xmitblk; 14560Sstevel@tonic-gate za->za_xmitblk = NULL; 14570Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 14580Sstevel@tonic-gate if (bp) 14590Sstevel@tonic-gate freemsg(bp); 14600Sstevel@tonic-gate } 14610Sstevel@tonic-gate /* 14620Sstevel@tonic-gate * Flush our write queue. 14630Sstevel@tonic-gate */ 14640Sstevel@tonic-gate flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */ 14650Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; /* it has been flushed */ 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 14680Sstevel@tonic-gate /* 14690Sstevel@tonic-gate * Flush any data in the temporary receive buffer 14700Sstevel@tonic-gate */ 14710Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 14720Sstevel@tonic-gate if ((za->za_ttycommon.t_flags & TS_SOFTCAR) || 14730Sstevel@tonic-gate (SCC_READ0() & ZSRR0_CD)) { 14740Sstevel@tonic-gate ZSA_KICK_RCV; 14750Sstevel@tonic-gate } else { 14760Sstevel@tonic-gate ZSA_KICK_RCV; 14770Sstevel@tonic-gate if (!(SCC_READ0() & ZSRR0_RX_READY)) { 14780Sstevel@tonic-gate /* 14790Sstevel@tonic-gate * settle time for 1 character shift 14800Sstevel@tonic-gate */ 14810Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 14820Sstevel@tonic-gate mutex_exit(zs->zs_excl); 14830Sstevel@tonic-gate delay(ztdelay( 14840Sstevel@tonic-gate SPEED(za->za_ttycommon.t_cflag))/3 + 1); 14850Sstevel@tonic-gate mutex_enter(zs->zs_excl); 14860Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 14870Sstevel@tonic-gate if (!(SCC_READ0() & ZSRR0_CD)) 14880Sstevel@tonic-gate ZSA_KICK_RCV; 14890Sstevel@tonic-gate } 14900Sstevel@tonic-gate while ((SCC_READ0() & 14910Sstevel@tonic-gate (ZSRR0_CD|ZSRR0_RX_READY)) == ZSRR0_RX_READY) { 14920Sstevel@tonic-gate /* 14930Sstevel@tonic-gate * Empty Receiver 14940Sstevel@tonic-gate */ 14950Sstevel@tonic-gate (void) SCC_READDATA(); 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate } 14980Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 14990Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 15000Sstevel@tonic-gate ZSA_QREPLY(q, mp); 15010Sstevel@tonic-gate /* 15020Sstevel@tonic-gate * give the read queues a crack at it 15030Sstevel@tonic-gate */ 15040Sstevel@tonic-gate } else 15050Sstevel@tonic-gate freemsg(mp); 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate /* 15080Sstevel@tonic-gate * We must make sure we process messages that survive the 15090Sstevel@tonic-gate * write-side flush. Without this call, the close protocol 15100Sstevel@tonic-gate * with ldterm can hang forever. (ldterm will have sent us a 15110Sstevel@tonic-gate * TCSBRK ioctl that it expects a response to.) 15120Sstevel@tonic-gate */ 15130Sstevel@tonic-gate zsa_start(zs); 15140Sstevel@tonic-gate mutex_exit(zs->zs_excl); 15150Sstevel@tonic-gate break; 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate case M_BREAK: 15180Sstevel@tonic-gate case M_DELAY: 15190Sstevel@tonic-gate case M_DATA: 15200Sstevel@tonic-gate mutex_enter(zs->zs_excl); 15210Sstevel@tonic-gate /* 15220Sstevel@tonic-gate * Queue the message up to be transmitted, 15230Sstevel@tonic-gate * and poke the start routine. 15240Sstevel@tonic-gate */ 15250Sstevel@tonic-gate (void) putq(q, mp); 15260Sstevel@tonic-gate zsa_start(zs); 15270Sstevel@tonic-gate mutex_exit(zs->zs_excl); 15280Sstevel@tonic-gate break; 15290Sstevel@tonic-gate 15300Sstevel@tonic-gate case M_STOPI: 15310Sstevel@tonic-gate mutex_enter(zs->zs_excl); 15320Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 15330Sstevel@tonic-gate za->za_flowc = za->za_ttycommon.t_stopc; 15340Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) { 15350Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 15360Sstevel@tonic-gate bp = za->za_xmitblk; 15370Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur; 15380Sstevel@tonic-gate zs->zs_wr_cur = NULL; 15390Sstevel@tonic-gate zs->zs_wr_lim = NULL; 15400Sstevel@tonic-gate za->za_xmitblk = NULL; 15410Sstevel@tonic-gate } 15420Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 15430Sstevel@tonic-gate if (bp) 15440Sstevel@tonic-gate (void) putbq(q, bp); 15450Sstevel@tonic-gate else 15460Sstevel@tonic-gate zsa_start(zs); /* poke the start routine */ 15470Sstevel@tonic-gate freemsg(mp); 15480Sstevel@tonic-gate mutex_exit(zs->zs_excl); 15490Sstevel@tonic-gate break; 15500Sstevel@tonic-gate 15510Sstevel@tonic-gate case M_STARTI: 15520Sstevel@tonic-gate mutex_enter(zs->zs_excl); 15530Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 15540Sstevel@tonic-gate za->za_flowc = za->za_ttycommon.t_startc; 15550Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) { 15560Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 15570Sstevel@tonic-gate bp = za->za_xmitblk; 15580Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur; 15590Sstevel@tonic-gate zs->zs_wr_cur = NULL; 15600Sstevel@tonic-gate zs->zs_wr_lim = NULL; 15610Sstevel@tonic-gate za->za_xmitblk = NULL; 15620Sstevel@tonic-gate } 15630Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 15640Sstevel@tonic-gate if (bp) 15650Sstevel@tonic-gate (void) putbq(q, bp); 15660Sstevel@tonic-gate else 15670Sstevel@tonic-gate zsa_start(zs); /* poke the start routine */ 15680Sstevel@tonic-gate freemsg(mp); 15690Sstevel@tonic-gate mutex_exit(zs->zs_excl); 15700Sstevel@tonic-gate break; 15710Sstevel@tonic-gate 15720Sstevel@tonic-gate case M_CTL: 15730Sstevel@tonic-gate if (MBLKL(mp) >= sizeof (struct iocblk) && 15740Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) { 15750Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd = MC_HAS_POSIX; 15760Sstevel@tonic-gate qreply(q, mp); 15770Sstevel@tonic-gate } else { 15780Sstevel@tonic-gate /* 15790Sstevel@tonic-gate * These MC_SERVICE type messages are used by upper 15800Sstevel@tonic-gate * modules to tell this driver to send input up 15810Sstevel@tonic-gate * immediately, or that it can wait for normal 15820Sstevel@tonic-gate * processing that may or may not be done. Sun 15830Sstevel@tonic-gate * requires these for the mouse module. 15840Sstevel@tonic-gate */ 15850Sstevel@tonic-gate mutex_enter(zs->zs_excl); 15860Sstevel@tonic-gate switch (*mp->b_rptr) { 15870Sstevel@tonic-gate 15880Sstevel@tonic-gate case MC_SERVICEIMM: 15890Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 15900Sstevel@tonic-gate za->za_flags |= ZAS_SERVICEIMM; 15910Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 15920Sstevel@tonic-gate break; 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate case MC_SERVICEDEF: 15950Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 15960Sstevel@tonic-gate za->za_flags &= ~ZAS_SERVICEIMM; 15970Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 15980Sstevel@tonic-gate break; 15990Sstevel@tonic-gate } 16000Sstevel@tonic-gate freemsg(mp); 16010Sstevel@tonic-gate mutex_exit(zs->zs_excl); 16020Sstevel@tonic-gate } 16030Sstevel@tonic-gate break; 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate default: 16060Sstevel@tonic-gate /* 16070Sstevel@tonic-gate * "No, I don't want a subscription to Chain Store Age, 16080Sstevel@tonic-gate * thank you anyway." 16090Sstevel@tonic-gate */ 16100Sstevel@tonic-gate freemsg(mp); 16110Sstevel@tonic-gate break; 16120Sstevel@tonic-gate } 16130Sstevel@tonic-gate } 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate /* 16160Sstevel@tonic-gate * zs read service procedure 16170Sstevel@tonic-gate */ 16180Sstevel@tonic-gate static void 16190Sstevel@tonic-gate zsa_rsrv(queue_t *q) 16200Sstevel@tonic-gate { 16210Sstevel@tonic-gate struct asyncline *za; 16220Sstevel@tonic-gate struct zscom *zs; 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate if (((za = (struct asyncline *)q->q_ptr) != NULL) && 16250Sstevel@tonic-gate (za->za_ttycommon.t_cflag & CRTSXOFF)) { 16260Sstevel@tonic-gate zs = za->za_common; 16270Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 16280Sstevel@tonic-gate ZSSETSOFT(zs); 16290Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 16300Sstevel@tonic-gate } 16310Sstevel@tonic-gate } 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate /* 16340Sstevel@tonic-gate * Transmitter interrupt service routine. 16350Sstevel@tonic-gate * If there's more data to transmit in the current pseudo-DMA block, 16360Sstevel@tonic-gate * and the transmitter is ready, send the next character if output 16370Sstevel@tonic-gate * is not stopped or draining. 16380Sstevel@tonic-gate * Otherwise, queue up a soft interrupt. 16390Sstevel@tonic-gate */ 16400Sstevel@tonic-gate static void 16410Sstevel@tonic-gate zsa_txint(struct zscom *zs) 16420Sstevel@tonic-gate { 16430Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 16440Sstevel@tonic-gate register uchar_t *wr_cur; 16450Sstevel@tonic-gate register uchar_t s0; 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate s0 = SCC_READ0(); 16480Sstevel@tonic-gate 16490Sstevel@tonic-gate if ((wr_cur = zs->zs_wr_cur) != NULL) { 16500Sstevel@tonic-gate if (wr_cur < zs->zs_wr_lim) { 16510Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) && 16520Sstevel@tonic-gate !(s0 & ZSRR0_CTS)) { 16530Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 16540Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_RETRANSMIT; 16550Sstevel@tonic-gate return; 16560Sstevel@tonic-gate } 16570Sstevel@tonic-gate SCC_WRITEDATA(*wr_cur++); 16580Sstevel@tonic-gate #ifdef ZSA_DEBUG 16590Sstevel@tonic-gate za->za_wr++; 16600Sstevel@tonic-gate #endif 16610Sstevel@tonic-gate zs->zs_wr_cur = wr_cur; 16620Sstevel@tonic-gate zs->zs_flags |= ZS_PROGRESS; 16630Sstevel@tonic-gate return; 16640Sstevel@tonic-gate } else { 16650Sstevel@tonic-gate zs->zs_wr_cur = NULL; 16660Sstevel@tonic-gate zs->zs_wr_lim = NULL; 16670Sstevel@tonic-gate /* 16680Sstevel@tonic-gate * Use the rcv_flags_mask as it is set and 16690Sstevel@tonic-gate * test while holding the zs_excl_hi mutex 16700Sstevel@tonic-gate */ 16710Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT; 16720Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 16730Sstevel@tonic-gate ZSSETSOFT(zs); 16740Sstevel@tonic-gate return; 16750Sstevel@tonic-gate } 16760Sstevel@tonic-gate } 16770Sstevel@tonic-gate 16780Sstevel@tonic-gate if (za->za_flowc != '\0' && (!(za->za_flags & ZAS_DRAINING))) { 16790Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) && 16800Sstevel@tonic-gate !(s0 & ZSRR0_CTS)) { 16810Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 16820Sstevel@tonic-gate return; 16830Sstevel@tonic-gate } 16840Sstevel@tonic-gate SCC_WRITEDATA(za->za_flowc); 16850Sstevel@tonic-gate za->za_flowc = '\0'; 16860Sstevel@tonic-gate return; 16870Sstevel@tonic-gate } 16880Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 16890Sstevel@tonic-gate /* 16900Sstevel@tonic-gate * Set DO_TRANSMIT bit so that the soft interrupt can 16910Sstevel@tonic-gate * test it and unset the ZAS_BUSY in za_flags while holding 16920Sstevel@tonic-gate * the mutex zs_excl and zs_excl_hi 16930Sstevel@tonic-gate */ 16940Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT; 16950Sstevel@tonic-gate ZSSETSOFT(zs); 16960Sstevel@tonic-gate } 16970Sstevel@tonic-gate 16980Sstevel@tonic-gate /* 16990Sstevel@tonic-gate * External/Status interrupt. 17000Sstevel@tonic-gate */ 17010Sstevel@tonic-gate static void 17020Sstevel@tonic-gate zsa_xsint(struct zscom *zs) 17030Sstevel@tonic-gate { 17040Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 17050Sstevel@tonic-gate register uchar_t s0, x0; 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate s0 = SCC_READ0(); 17080Sstevel@tonic-gate ZSA_R0_LOG(s0); 17090Sstevel@tonic-gate x0 = s0 ^ za->za_rr0; 17100Sstevel@tonic-gate za->za_rr0 = s0; 17110Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 17120Sstevel@tonic-gate 17130Sstevel@tonic-gate /* 17140Sstevel@tonic-gate * PPS (Pulse Per Second) support. 17150Sstevel@tonic-gate */ 17160Sstevel@tonic-gate if (za->za_pps && (x0 & ZSRR0_CD) && (s0 & ZSRR0_CD)) { 17170Sstevel@tonic-gate /* 17180Sstevel@tonic-gate * This code captures a timestamp at the designated 17190Sstevel@tonic-gate * transition of the PPS signal (CD asserted). The 17200Sstevel@tonic-gate * code provides a pointer to the timestamp, as well 17210Sstevel@tonic-gate * as the hardware counter value at the capture. 17220Sstevel@tonic-gate * 17230Sstevel@tonic-gate * Note: the kernel has nano based time values while 17240Sstevel@tonic-gate * NTP requires micro based, an in-line fast algorithm 17250Sstevel@tonic-gate * to convert nsec to usec is used here -- see hrt2ts() 17260Sstevel@tonic-gate * in common/os/timers.c for a full description. 17270Sstevel@tonic-gate */ 17280Sstevel@tonic-gate struct timeval *tvp = &ppsclockev.tv; 17290Sstevel@tonic-gate timespec_t ts; 17300Sstevel@tonic-gate int nsec, usec; 17310Sstevel@tonic-gate 17320Sstevel@tonic-gate LED_OFF; 17330Sstevel@tonic-gate gethrestime(&ts); 17340Sstevel@tonic-gate LED_ON; 17350Sstevel@tonic-gate nsec = ts.tv_nsec; 17360Sstevel@tonic-gate usec = nsec + (nsec >> 2); 17370Sstevel@tonic-gate usec = nsec + (usec >> 1); 17380Sstevel@tonic-gate usec = nsec + (usec >> 2); 17390Sstevel@tonic-gate usec = nsec + (usec >> 4); 17400Sstevel@tonic-gate usec = nsec - (usec >> 3); 17410Sstevel@tonic-gate usec = nsec + (usec >> 2); 17420Sstevel@tonic-gate usec = nsec + (usec >> 3); 17430Sstevel@tonic-gate usec = nsec + (usec >> 4); 17440Sstevel@tonic-gate usec = nsec + (usec >> 1); 17450Sstevel@tonic-gate usec = nsec + (usec >> 6); 17460Sstevel@tonic-gate tvp->tv_usec = usec >> 10; 17470Sstevel@tonic-gate tvp->tv_sec = ts.tv_sec; 17480Sstevel@tonic-gate 17490Sstevel@tonic-gate ++ppsclockev.serial; 17500Sstevel@tonic-gate 17510Sstevel@tonic-gate /* 17520Sstevel@tonic-gate * Because the kernel keeps a high-resolution time, pass the 17530Sstevel@tonic-gate * current highres timestamp in tvp and zero in usec. 17540Sstevel@tonic-gate */ 17550Sstevel@tonic-gate ddi_hardpps(tvp, 0); 17560Sstevel@tonic-gate } 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate ZSA_KICK_RCV; 17590Sstevel@tonic-gate 17600Sstevel@tonic-gate if ((x0 & ZSRR0_BREAK) && (s0 & ZSRR0_BREAK) == 0) { 17610Sstevel@tonic-gate #ifdef SLAVIO_BUG 17620Sstevel@tonic-gate /* 17630Sstevel@tonic-gate * ZSRR0_BREAK turned off. This means that the break sequence 17640Sstevel@tonic-gate * has completed (i.e., the stop bit finally arrived). 17650Sstevel@tonic-gate */ 17660Sstevel@tonic-gate if ((s0 & ZSRR0_RX_READY) == 0) { 17670Sstevel@tonic-gate /* 17680Sstevel@tonic-gate * SLAVIO will generate a separate STATUS change 17690Sstevel@tonic-gate * interrupt when the break sequence completes. 17700Sstevel@tonic-gate * SCC will combine both, taking the higher priority 17710Sstevel@tonic-gate * one, the receive. Should still see the ext/stat. 17720Sstevel@tonic-gate * bit in REG3 on SCC. If no ext/stat, it must be 17730Sstevel@tonic-gate * a SLAVIO. 17740Sstevel@tonic-gate */ 17750Sstevel@tonic-gate za->za_breakoff = 1; 17760Sstevel@tonic-gate } else { 17770Sstevel@tonic-gate /* 17780Sstevel@tonic-gate * The NUL character in the receiver is part of the 17790Sstevel@tonic-gate * break sequence; it is discarded. 17800Sstevel@tonic-gate */ 17810Sstevel@tonic-gate (void) SCC_READDATA(); /* swallow null */ 17820Sstevel@tonic-gate } 17830Sstevel@tonic-gate #else /* SLAVIO_BUG */ 17840Sstevel@tonic-gate /* 17850Sstevel@tonic-gate * ZSRR0_BREAK turned off. This means that the break sequence 17860Sstevel@tonic-gate * has completed (i.e., the stop bit finally arrived). The NUL 17870Sstevel@tonic-gate * character in the receiver is part of the break sequence; 17880Sstevel@tonic-gate * it is discarded. 17890Sstevel@tonic-gate */ 17900Sstevel@tonic-gate (void) SCC_READDATA(); /* swallow null */ 17910Sstevel@tonic-gate #endif /* SLAVIO_BUG */ 17920Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 17930Sstevel@tonic-gate 17940Sstevel@tonic-gate /* 17950Sstevel@tonic-gate * Note: this will cause an abort if a break occurs on 17960Sstevel@tonic-gate * the "keyboard device", regardless of whether the 17970Sstevel@tonic-gate * "keyboard device" is a real keyboard or just a 17980Sstevel@tonic-gate * terminal on a serial line. This permits you to 17990Sstevel@tonic-gate * abort a workstation by unplugging the keyboard, 18000Sstevel@tonic-gate * even if the normal abort key sequence isn't working. 18010Sstevel@tonic-gate */ 18020Sstevel@tonic-gate if ((za->za_dev == kbddev) || 18030Sstevel@tonic-gate ((za->za_dev == rconsdev) || (za->za_dev == stdindev)) && 18040Sstevel@tonic-gate (abort_enable != KIOCABORTALTERNATE)) { 18050Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 18060Sstevel@tonic-gate /* 18070Sstevel@tonic-gate * We just broke into the monitor or debugger, 18080Sstevel@tonic-gate * ignore the break in this case so whatever 18090Sstevel@tonic-gate * random program that was running doesn't get 18100Sstevel@tonic-gate * a SIGINT. 18110Sstevel@tonic-gate */ 18120Sstevel@tonic-gate return; 18130Sstevel@tonic-gate } 18140Sstevel@tonic-gate za->za_break = 1; 18150Sstevel@tonic-gate } 18160Sstevel@tonic-gate 18170Sstevel@tonic-gate /* 18180Sstevel@tonic-gate * If hardware flow control is enabled, (re)start output 18190Sstevel@tonic-gate * when CTS is reasserted. 18200Sstevel@tonic-gate */ 18210Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) && 18220Sstevel@tonic-gate (x0 & ZSRR0_CTS) && (s0 & ZSRR0_CTS) && 18230Sstevel@tonic-gate (za->za_rcv_flags_mask & DO_RETRANSMIT)) 18240Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT; 18250Sstevel@tonic-gate 18260Sstevel@tonic-gate za->za_ext = 1; 18270Sstevel@tonic-gate ZSSETSOFT(zs); 18280Sstevel@tonic-gate } 18290Sstevel@tonic-gate 18300Sstevel@tonic-gate /* 18310Sstevel@tonic-gate * Receive Interrupt 18320Sstevel@tonic-gate */ 18330Sstevel@tonic-gate static void 18340Sstevel@tonic-gate zsa_rxint(struct zscom *zs) 18350Sstevel@tonic-gate { 18360Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 18370Sstevel@tonic-gate register uchar_t c; 18380Sstevel@tonic-gate register uchar_t *rd_cur = zs->zs_rd_cur; 18390Sstevel@tonic-gate register uchar_t *rd_lim = zs->zs_rd_lim; 18400Sstevel@tonic-gate register mblk_t *bp; 18410Sstevel@tonic-gate register uint_t fm = za->za_rcv_flags_mask; 18420Sstevel@tonic-gate 18430Sstevel@tonic-gate 18440Sstevel@tonic-gate #ifdef ZSA_DEBUG 18450Sstevel@tonic-gate za->za_rd++; 18460Sstevel@tonic-gate #endif 18470Sstevel@tonic-gate c = (fm >> 16) & (SCC_READDATA()); 18480Sstevel@tonic-gate 18490Sstevel@tonic-gate /* 18500Sstevel@tonic-gate * Check for character break sequence 18510Sstevel@tonic-gate */ 18520Sstevel@tonic-gate if ((abort_enable == KIOCABORTALTERNATE) && (za->za_dev == rconsdev)) { 18530Sstevel@tonic-gate if (abort_charseq_recognize(c)) 18540Sstevel@tonic-gate abort_sequence_enter((char *)NULL); 18550Sstevel@tonic-gate } 18560Sstevel@tonic-gate 18570Sstevel@tonic-gate if (!rd_cur) { 18580Sstevel@tonic-gate #ifdef SLAVIO_BUG 18590Sstevel@tonic-gate /* 18600Sstevel@tonic-gate * SLAVIO generates FE for the start of break and 18610Sstevel@tonic-gate * during break when parity is set. End of break is 18620Sstevel@tonic-gate * detected when the first character is received. 18630Sstevel@tonic-gate * This character is always garbage and is thrown away. 18640Sstevel@tonic-gate */ 18650Sstevel@tonic-gate if (za->za_slav_break) { 18660Sstevel@tonic-gate za->za_slav_break = 0; 18670Sstevel@tonic-gate za->za_rr0 |= ZSRR0_BREAK; 18680Sstevel@tonic-gate zsa_xsint(zs); 18690Sstevel@tonic-gate return; 18700Sstevel@tonic-gate } 18710Sstevel@tonic-gate #endif /* SLAVIO_BUG */ 18720Sstevel@tonic-gate 18730Sstevel@tonic-gate if (c == 0 && (za->za_rr0 & ZSRR0_BREAK)) { 18740Sstevel@tonic-gate /* 18750Sstevel@tonic-gate * A break sequence was under way, and a NUL character 18760Sstevel@tonic-gate * was received. Discard the NUL character, as it is 18770Sstevel@tonic-gate * part of the break sequence; if ZSRR0_BREAK turned 18780Sstevel@tonic-gate * off, indicating that the break sequence has com- 18790Sstevel@tonic-gate * pleted, call "zsa_xsint" to properly handle the 18800Sstevel@tonic-gate * error. It would appear that External/Status 18810Sstevel@tonic-gate * interrupts get lost occasionally, so this ensures 18820Sstevel@tonic-gate * that one is delivered. 18830Sstevel@tonic-gate */ 18840Sstevel@tonic-gate c = SCC_READ0(); 18850Sstevel@tonic-gate if (!(c & ZSRR0_BREAK)) 18860Sstevel@tonic-gate zsa_xsint(zs); 18870Sstevel@tonic-gate return; 18880Sstevel@tonic-gate } 18890Sstevel@tonic-gate 18900Sstevel@tonic-gate #ifdef SLAVIO_BUG 18910Sstevel@tonic-gate if (c == 0 && za->za_breakoff) { 18920Sstevel@tonic-gate /* 18930Sstevel@tonic-gate * A break sequence completed, but SLAVIO generates 18940Sstevel@tonic-gate * the NULL character interrupt late, so we throw the 18950Sstevel@tonic-gate * NULL away now. 18960Sstevel@tonic-gate */ 18970Sstevel@tonic-gate return; 18980Sstevel@tonic-gate } 18990Sstevel@tonic-gate 19000Sstevel@tonic-gate /* 19010Sstevel@tonic-gate * make sure it gets cleared. 19020Sstevel@tonic-gate */ 19030Sstevel@tonic-gate za->za_breakoff = 0; 19040Sstevel@tonic-gate #endif /* SLAVIO_BUG */ 19050Sstevel@tonic-gate 19060Sstevel@tonic-gate ZSA_KICK_RCV; /* We can have M_BREAK msg */ 19070Sstevel@tonic-gate ZSA_ALLOCB(bp); 19080Sstevel@tonic-gate if (!bp) { 19090Sstevel@tonic-gate za->za_sw_overrun++; 19100Sstevel@tonic-gate ZSSETSOFT(zs); 19110Sstevel@tonic-gate return; 19120Sstevel@tonic-gate } 19130Sstevel@tonic-gate za->za_rcvblk = bp; 19140Sstevel@tonic-gate zs->zs_rd_cur = rd_cur = bp->b_wptr; 19150Sstevel@tonic-gate zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim; 19160Sstevel@tonic-gate if (za->za_kick_rcv_id == 0) 19170Sstevel@tonic-gate ZSSETSOFT(zs); 19180Sstevel@tonic-gate } 19190Sstevel@tonic-gate if (c == 0377 && (fm & DO_ESC)) { 19200Sstevel@tonic-gate if (rd_lim < rd_cur + 2) { 19210Sstevel@tonic-gate ZSA_ALLOCB(bp); 19220Sstevel@tonic-gate ZSA_KICK_RCV; 19230Sstevel@tonic-gate if (!bp) { 19240Sstevel@tonic-gate za->za_sw_overrun++; 19250Sstevel@tonic-gate return; 19260Sstevel@tonic-gate } 19270Sstevel@tonic-gate za->za_rcvblk = bp; 19280Sstevel@tonic-gate zs->zs_rd_cur = rd_cur = bp->b_wptr; 19290Sstevel@tonic-gate zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim; 19300Sstevel@tonic-gate } 19310Sstevel@tonic-gate *rd_cur++ = c; 19320Sstevel@tonic-gate } 19330Sstevel@tonic-gate 19340Sstevel@tonic-gate 19350Sstevel@tonic-gate *rd_cur++ = c; 19360Sstevel@tonic-gate zs->zs_rd_cur = rd_cur; 19370Sstevel@tonic-gate 19380Sstevel@tonic-gate if (rd_cur == rd_lim) { 19390Sstevel@tonic-gate ZSA_KICK_RCV; 19400Sstevel@tonic-gate } else if ((fm & DO_STOPC) && (c == (fm & 0xff))) { 19410Sstevel@tonic-gate za->za_do_kick_rcv_in_softint = 1; 19420Sstevel@tonic-gate ZSSETSOFT(zs); 19430Sstevel@tonic-gate } 19440Sstevel@tonic-gate 19450Sstevel@tonic-gate if ((za->za_flags & ZAS_SERVICEIMM) || g_nocluster) { 19460Sstevel@tonic-gate /* 19470Sstevel@tonic-gate * Send the data up immediately 19480Sstevel@tonic-gate */ 19490Sstevel@tonic-gate ZSA_KICK_RCV; 19500Sstevel@tonic-gate } 19510Sstevel@tonic-gate } 19520Sstevel@tonic-gate 19530Sstevel@tonic-gate /* 19540Sstevel@tonic-gate * Special receive condition interrupt handler. 19550Sstevel@tonic-gate */ 19560Sstevel@tonic-gate static void 19570Sstevel@tonic-gate zsa_srint(struct zscom *zs) 19580Sstevel@tonic-gate { 19590Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 19600Sstevel@tonic-gate register short s1; 19610Sstevel@tonic-gate register uchar_t c; 19620Sstevel@tonic-gate register uchar_t c1; 19630Sstevel@tonic-gate register mblk_t *bp = za->za_rcvblk; 19640Sstevel@tonic-gate register uchar_t *rd_cur = zs->zs_rd_cur; 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate SCC_READ(1, s1); 19670Sstevel@tonic-gate if (s1 & (ZSRR1_FE | ZSRR1_PE | ZSRR1_DO)) { 19680Sstevel@tonic-gate c = SCC_READDATA(); /* swallow bad character */ 19690Sstevel@tonic-gate } 19700Sstevel@tonic-gate #ifdef SLAVIO_BUG 19710Sstevel@tonic-gate /* 19720Sstevel@tonic-gate * SLAVIO does not handle breaks properly when parity is enabled. 19730Sstevel@tonic-gate * 19740Sstevel@tonic-gate * In general, if a null character is received when a framing 19750Sstevel@tonic-gate * error occurs then it is a break condition and not a real 19760Sstevel@tonic-gate * framing error. The null character must be limited to the 19770Sstevel@tonic-gate * number of bits including the parity bit. For example, a 6 19780Sstevel@tonic-gate * bit character with parity would be null if the lower 7 bits 19790Sstevel@tonic-gate * read from the receive fifo were 0. (The higher order bits are 19800Sstevel@tonic-gate * padded with 1 and/or the stop bits.) The only exception to this 19810Sstevel@tonic-gate * general rule would be an 8 bit null character with parity being 19820Sstevel@tonic-gate * a 1 in the parity bit and a framing error. This exception 19830Sstevel@tonic-gate * can be determined by examining the parity error bit in RREG 1. 19840Sstevel@tonic-gate * 19850Sstevel@tonic-gate * A null character, even parity, 8 bits, no parity error, 19860Sstevel@tonic-gate * (0 0000 0000) with framing error is a break condition. 19870Sstevel@tonic-gate * 19880Sstevel@tonic-gate * A null character, even parity, 8 bits, parity error, 19890Sstevel@tonic-gate * (1 0000 0000) with framing error is a framing error. 19900Sstevel@tonic-gate * 19910Sstevel@tonic-gate * A null character, odd parity, 8 bits, parity error 19920Sstevel@tonic-gate * (0 0000 0000) with framing error is a break condition. 19930Sstevel@tonic-gate * 19940Sstevel@tonic-gate * A null character, odd parity, 8 bits, no parity error, 19950Sstevel@tonic-gate * (1 0000 0000) with framing error is a framing error. 19960Sstevel@tonic-gate */ 19970Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARENB) { 19980Sstevel@tonic-gate switch (za->za_ttycommon.t_cflag & CSIZE) { 19990Sstevel@tonic-gate 20000Sstevel@tonic-gate case CS5: 20010Sstevel@tonic-gate c1 = c & 0x3f; 20020Sstevel@tonic-gate break; 20030Sstevel@tonic-gate 20040Sstevel@tonic-gate case CS6: 20050Sstevel@tonic-gate c1 = c & 0x7f; 20060Sstevel@tonic-gate break; 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate case CS7: 20090Sstevel@tonic-gate c1 = c & 0xff; 20100Sstevel@tonic-gate break; 20110Sstevel@tonic-gate 20120Sstevel@tonic-gate case CS8: 20130Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & PARODD) && 20140Sstevel@tonic-gate !(s1 & ZSRR1_PE)) 20150Sstevel@tonic-gate c1 = 0xff; 20160Sstevel@tonic-gate else if (!(za->za_ttycommon.t_cflag & PARODD) && 20170Sstevel@tonic-gate (s1 & ZSRR1_PE)) 20180Sstevel@tonic-gate c1 = 0xff; 20190Sstevel@tonic-gate else 20200Sstevel@tonic-gate c1 = c; 20210Sstevel@tonic-gate break; 20220Sstevel@tonic-gate } 20230Sstevel@tonic-gate 20240Sstevel@tonic-gate /* 20250Sstevel@tonic-gate * We fake start of break condition. 20260Sstevel@tonic-gate */ 20270Sstevel@tonic-gate if ((s1 & ZSRR1_FE) && c1 == 0) { 20280Sstevel@tonic-gate za->za_slav_break = 1; 20290Sstevel@tonic-gate return; 20300Sstevel@tonic-gate } 20310Sstevel@tonic-gate } 20320Sstevel@tonic-gate #endif /* SLAVIO_BUG */ 20330Sstevel@tonic-gate 20340Sstevel@tonic-gate if (s1 & ZSRR1_PE) { 20350Sstevel@tonic-gate 20360Sstevel@tonic-gate /* 20370Sstevel@tonic-gate * Mark the parity error so zsa_process will 20380Sstevel@tonic-gate * notice it and send it up in an M_BREAK 20390Sstevel@tonic-gate * message; ldterm will do the actual parity error 20400Sstevel@tonic-gate * processing 20410Sstevel@tonic-gate */ 20420Sstevel@tonic-gate 20430Sstevel@tonic-gate if (bp && zs->zs_rd_cur) { /* M_DATA msg */ 20440Sstevel@tonic-gate ZSA_KICK_RCV; 20450Sstevel@tonic-gate bp = NULL; 20460Sstevel@tonic-gate } 20470Sstevel@tonic-gate if (!bp) 20480Sstevel@tonic-gate ZSA_ALLOCB(bp); 20490Sstevel@tonic-gate if (!bp) { 20500Sstevel@tonic-gate za->za_sw_overrun++; 20510Sstevel@tonic-gate ZSSETSOFT(zs); 20520Sstevel@tonic-gate } else { 20530Sstevel@tonic-gate za->za_rcvblk = bp; 20540Sstevel@tonic-gate zs->zs_rd_cur = rd_cur = bp->b_wptr; 20550Sstevel@tonic-gate zs->zs_rd_lim = bp->b_datap->db_lim; 20560Sstevel@tonic-gate *rd_cur++ = c; 20570Sstevel@tonic-gate zs->zs_rd_cur = rd_cur; 20580Sstevel@tonic-gate bp->b_datap->db_type = M_BREAK; 20590Sstevel@tonic-gate if (bp->b_datap->db_lim <= rd_cur) 20600Sstevel@tonic-gate ZSA_KICK_RCV; 20610Sstevel@tonic-gate za->za_do_kick_rcv_in_softint = 1; 20620Sstevel@tonic-gate ZSSETSOFT(zs); 20630Sstevel@tonic-gate 20640Sstevel@tonic-gate } 20650Sstevel@tonic-gate } 20660Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 20670Sstevel@tonic-gate if (s1 & ZSRR1_DO) { 20680Sstevel@tonic-gate za->za_hw_overrun++; 20690Sstevel@tonic-gate ZSSETSOFT(zs); 20700Sstevel@tonic-gate } 20710Sstevel@tonic-gate } 20720Sstevel@tonic-gate 20730Sstevel@tonic-gate /* 20740Sstevel@tonic-gate * Process software interrupts (or poll) 20750Sstevel@tonic-gate * Crucial points: 20760Sstevel@tonic-gate * 3. BUG - breaks are handled "out-of-band" - their relative position 20770Sstevel@tonic-gate * among input events is lost, as well as multiple breaks together. 20780Sstevel@tonic-gate * This is probably not a problem in practice. 20790Sstevel@tonic-gate */ 20800Sstevel@tonic-gate static int 20810Sstevel@tonic-gate zsa_softint(struct zscom *zs) 20820Sstevel@tonic-gate { 20830Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 20840Sstevel@tonic-gate register uchar_t r0; 20850Sstevel@tonic-gate register uchar_t za_kick_active; 20860Sstevel@tonic-gate register int m_error; 20870Sstevel@tonic-gate register int allocbcount = 0; 20880Sstevel@tonic-gate register int do_ttycommon_qfull = 0; 20890Sstevel@tonic-gate boolean_t hangup = B_FALSE, unhangup = B_FALSE; 20900Sstevel@tonic-gate boolean_t m_break = B_FALSE, wakeup = B_FALSE; 20910Sstevel@tonic-gate register queue_t *q; 20920Sstevel@tonic-gate register mblk_t *bp; 20930Sstevel@tonic-gate register mblk_t *head = NULL, *tail = NULL; 20940Sstevel@tonic-gate 20950Sstevel@tonic-gate mutex_enter(zs->zs_excl); 20960Sstevel@tonic-gate if (zs->zs_suspended || (zs->zs_flags & ZS_CLOSED)) { 20970Sstevel@tonic-gate mutex_exit(zs->zs_excl); 20980Sstevel@tonic-gate return (0); 20990Sstevel@tonic-gate } 21000Sstevel@tonic-gate q = za->za_ttycommon.t_readq; 21010Sstevel@tonic-gate if (za->za_flags & ZAS_WOPEN && !q) { 21020Sstevel@tonic-gate if (za->za_ext) { 21030Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 21040Sstevel@tonic-gate r0 = SCC_READ0(); 21050Sstevel@tonic-gate za->za_ext = 0; 21060Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 21070Sstevel@tonic-gate /* 21080Sstevel@tonic-gate * carrier up? 21090Sstevel@tonic-gate */ 21100Sstevel@tonic-gate if ((r0 & ZSRR0_CD) || 21110Sstevel@tonic-gate (za->za_ttycommon.t_flags & TS_SOFTCAR)) { 21120Sstevel@tonic-gate /* 21130Sstevel@tonic-gate * carrier present 21140Sstevel@tonic-gate */ 21150Sstevel@tonic-gate if ((za->za_flags & ZAS_CARR_ON) == 0) { 21160Sstevel@tonic-gate za->za_flags |= ZAS_CARR_ON; 21170Sstevel@tonic-gate mutex_exit(zs->zs_excl); 21180Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 21190Sstevel@tonic-gate return (0); 21200Sstevel@tonic-gate } 21210Sstevel@tonic-gate } 21220Sstevel@tonic-gate } 21230Sstevel@tonic-gate mutex_exit(zs->zs_excl); 21240Sstevel@tonic-gate return (0); 21250Sstevel@tonic-gate } 21260Sstevel@tonic-gate q = za->za_ttycommon.t_readq; 21270Sstevel@tonic-gate if (!q) { 21280Sstevel@tonic-gate mutex_exit(zs->zs_excl); 21290Sstevel@tonic-gate return (0); 21300Sstevel@tonic-gate } 21310Sstevel@tonic-gate 21320Sstevel@tonic-gate m_error = za->za_m_error; 21330Sstevel@tonic-gate za->za_m_error = 0; 21340Sstevel@tonic-gate 21350Sstevel@tonic-gate if (za->za_do_kick_rcv_in_softint) { 21360Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 21370Sstevel@tonic-gate ZSA_KICK_RCV; 21380Sstevel@tonic-gate za->za_do_kick_rcv_in_softint = 0; 21390Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 21400Sstevel@tonic-gate } 21410Sstevel@tonic-gate 21420Sstevel@tonic-gate za_kick_active = za->za_kick_active; 21430Sstevel@tonic-gate 21440Sstevel@tonic-gate while (!za_kick_active) { 21450Sstevel@tonic-gate ZSA_SEEQ(bp); 21460Sstevel@tonic-gate if (!bp) 21470Sstevel@tonic-gate break; 21480Sstevel@tonic-gate 21490Sstevel@tonic-gate allocbcount++; 21500Sstevel@tonic-gate 21510Sstevel@tonic-gate if (bp->b_datap->db_type <= QPCTL) { 21520Sstevel@tonic-gate if (!(canputnext(q))) { 21530Sstevel@tonic-gate if (za->za_grace_flow_control >= 21540Sstevel@tonic-gate zsa_grace_flow_control) { 21550Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { 21560Sstevel@tonic-gate allocbcount--; 21570Sstevel@tonic-gate break; 21580Sstevel@tonic-gate } 21590Sstevel@tonic-gate ZSA_GETQ(bp); 21600Sstevel@tonic-gate freemsg(bp); 21610Sstevel@tonic-gate do_ttycommon_qfull = 1; 21620Sstevel@tonic-gate continue; 21630Sstevel@tonic-gate } else 21640Sstevel@tonic-gate za->za_grace_flow_control++; 21650Sstevel@tonic-gate } else 21660Sstevel@tonic-gate za->za_grace_flow_control = 0; 21670Sstevel@tonic-gate } 21680Sstevel@tonic-gate ZSA_GETQ(bp); 21690Sstevel@tonic-gate if (!head) { 21700Sstevel@tonic-gate head = bp; 21710Sstevel@tonic-gate } else { 21720Sstevel@tonic-gate if (!tail) 21730Sstevel@tonic-gate tail = head; 21740Sstevel@tonic-gate tail->b_next = bp; 21750Sstevel@tonic-gate tail = bp; 21760Sstevel@tonic-gate } 21770Sstevel@tonic-gate } 21780Sstevel@tonic-gate 21790Sstevel@tonic-gate if (allocbcount) 21800Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount); 21810Sstevel@tonic-gate 21820Sstevel@tonic-gate if (za->za_ext) { 21830Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 21840Sstevel@tonic-gate r0 = SCC_READ0(); 21850Sstevel@tonic-gate za->za_ext = 0; 21860Sstevel@tonic-gate /* 21870Sstevel@tonic-gate * carrier up? 21880Sstevel@tonic-gate */ 21890Sstevel@tonic-gate if ((r0 & ZSRR0_CD) || 21900Sstevel@tonic-gate (za->za_ttycommon.t_flags & TS_SOFTCAR)) { 21910Sstevel@tonic-gate /* 21920Sstevel@tonic-gate * carrier present 21930Sstevel@tonic-gate */ 21940Sstevel@tonic-gate if ((za->za_flags & ZAS_CARR_ON) == 0) { 21950Sstevel@tonic-gate za->za_flags |= ZAS_CARR_ON; 21960Sstevel@tonic-gate unhangup = B_TRUE; 21970Sstevel@tonic-gate wakeup = B_TRUE; 21980Sstevel@tonic-gate } 21990Sstevel@tonic-gate } else { 22000Sstevel@tonic-gate if ((za->za_flags & ZAS_CARR_ON) && 22010Sstevel@tonic-gate !(za->za_ttycommon.t_cflag & CLOCAL)) { 22020Sstevel@tonic-gate /* 22030Sstevel@tonic-gate * Carrier went away. 22040Sstevel@tonic-gate * Drop DTR, abort any output in progress, 22050Sstevel@tonic-gate * indicate that output is not stopped, and 22060Sstevel@tonic-gate * send a hangup notification upstream. 22070Sstevel@tonic-gate */ 22080Sstevel@tonic-gate (void) zsmctl(zs, ZSWR5_DTR, DMBIC); 22090Sstevel@tonic-gate if ((za->za_flags & ZAS_BUSY) && 22100Sstevel@tonic-gate (zs->zs_wr_cur != NULL)) { 22110Sstevel@tonic-gate zs->zs_wr_cur = NULL; 22120Sstevel@tonic-gate zs->zs_wr_lim = NULL; 22130Sstevel@tonic-gate } 22140Sstevel@tonic-gate hangup = B_TRUE; 22150Sstevel@tonic-gate wakeup = B_TRUE; 22160Sstevel@tonic-gate za->za_flags &= ~(ZAS_STOPPED | ZAS_CARR_ON | 22170Sstevel@tonic-gate ZAS_BUSY); 22180Sstevel@tonic-gate za->za_rcv_flags_mask &= ~(DO_TRANSMIT | 22190Sstevel@tonic-gate DO_RETRANSMIT); 22200Sstevel@tonic-gate } 22210Sstevel@tonic-gate } 22220Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 22230Sstevel@tonic-gate if (hangup && (bp = za->za_xmitblk) != NULL) { 22240Sstevel@tonic-gate za->za_xmitblk = NULL; 22250Sstevel@tonic-gate freeb(bp); 22260Sstevel@tonic-gate } 22270Sstevel@tonic-gate } 22280Sstevel@tonic-gate 22290Sstevel@tonic-gate if (za->za_break != 0) { 22300Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 22310Sstevel@tonic-gate r0 = SCC_READ0(); 22320Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 22330Sstevel@tonic-gate if ((r0 & ZSRR0_BREAK) == 0) { 22340Sstevel@tonic-gate za->za_break = 0; 22350Sstevel@tonic-gate m_break = B_TRUE; 22360Sstevel@tonic-gate } 22370Sstevel@tonic-gate } 22380Sstevel@tonic-gate 22390Sstevel@tonic-gate /* 22400Sstevel@tonic-gate * If a transmission has finished, indicate that it's 22410Sstevel@tonic-gate * finished, and start that line up again. 22420Sstevel@tonic-gate */ 22430Sstevel@tonic-gate 22440Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 22450Sstevel@tonic-gate if (za->za_rcv_flags_mask & DO_TRANSMIT) { 22460Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_TRANSMIT; 22470Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 22480Sstevel@tonic-gate 22490Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) && 22500Sstevel@tonic-gate (za->za_rcv_flags_mask & DO_RETRANSMIT) && 22510Sstevel@tonic-gate zs->zs_wr_cur) 22520Sstevel@tonic-gate bp = NULL; 22530Sstevel@tonic-gate else { 22540Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 22550Sstevel@tonic-gate bp = za->za_xmitblk; 22560Sstevel@tonic-gate za->za_xmitblk = 0; 22570Sstevel@tonic-gate } 22580Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 22590Sstevel@tonic-gate if (bp) 22600Sstevel@tonic-gate freemsg(bp); 22610Sstevel@tonic-gate zsa_start(zs); 22620Sstevel@tonic-gate /* if we didn't start anything, then notify waiters */ 22630Sstevel@tonic-gate if (!(za->za_flags & ZAS_BUSY)) 22640Sstevel@tonic-gate wakeup = B_TRUE; 22650Sstevel@tonic-gate } else { 22660Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 22670Sstevel@tonic-gate } 22680Sstevel@tonic-gate 22690Sstevel@tonic-gate 22700Sstevel@tonic-gate /* 22710Sstevel@tonic-gate * A note about these overrun bits: all they do is *tell* someone 22720Sstevel@tonic-gate * about an error- They do not track multiple errors. In fact, 22730Sstevel@tonic-gate * you could consider them latched register bits if you like. 22740Sstevel@tonic-gate * We are only interested in printing the error message once for 22750Sstevel@tonic-gate * any cluster of overrun errrors. 22760Sstevel@tonic-gate */ 22770Sstevel@tonic-gate if ((!za->za_kick_rcv_id) && (zs->zs_rd_cur || za_kick_active)) { 22780Sstevel@tonic-gate if (g_zsticks) 22790Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs, g_zsticks); 22800Sstevel@tonic-gate else 22810Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs, 22820Sstevel@tonic-gate zsticks[SPEED(za->za_ttycommon.t_cflag)]); 22830Sstevel@tonic-gate za->za_kick_rcv_count = ZA_KICK_RCV_COUNT; 22840Sstevel@tonic-gate } 22850Sstevel@tonic-gate za->za_soft_active = 1; 22860Sstevel@tonic-gate mutex_exit(zs->zs_excl); 22870Sstevel@tonic-gate 22880Sstevel@tonic-gate if (!hangup && do_ttycommon_qfull) { 22890Sstevel@tonic-gate ttycommon_qfull(&za->za_ttycommon, q); 22900Sstevel@tonic-gate mutex_enter(zs->zs_excl); 22910Sstevel@tonic-gate zsa_start(zs); 22920Sstevel@tonic-gate mutex_exit(zs->zs_excl); 22930Sstevel@tonic-gate } 22940Sstevel@tonic-gate 22950Sstevel@tonic-gate if (za->za_hw_overrun > 10) { 22960Sstevel@tonic-gate cmn_err(CE_NOTE, "zs%d: silo overflow\n", UNIT(za->za_dev)); 22970Sstevel@tonic-gate za->za_hw_overrun = 0; 22980Sstevel@tonic-gate } 22990Sstevel@tonic-gate 23000Sstevel@tonic-gate if (za->za_sw_overrun > 10) { 23010Sstevel@tonic-gate cmn_err(CE_NOTE, "zs%d:ring buffer overflow\n", 23020Sstevel@tonic-gate UNIT(za->za_dev)); 23030Sstevel@tonic-gate za->za_sw_overrun = 0; 23040Sstevel@tonic-gate } 23050Sstevel@tonic-gate 23060Sstevel@tonic-gate if (unhangup) 23070Sstevel@tonic-gate (void) putnextctl(q, M_UNHANGUP); 23080Sstevel@tonic-gate 23090Sstevel@tonic-gate if (m_break) 23100Sstevel@tonic-gate (void) putnextctl(q, M_BREAK); 23110Sstevel@tonic-gate 23120Sstevel@tonic-gate while (head) { 23130Sstevel@tonic-gate if (!tail) { 23140Sstevel@tonic-gate putnext(q, head); 23150Sstevel@tonic-gate break; 23160Sstevel@tonic-gate } 23170Sstevel@tonic-gate bp = head; 23180Sstevel@tonic-gate head = head->b_next; 23190Sstevel@tonic-gate bp->b_next = NULL; 23200Sstevel@tonic-gate putnext(q, bp); 23210Sstevel@tonic-gate } 23220Sstevel@tonic-gate 23230Sstevel@tonic-gate if (hangup) { 23240Sstevel@tonic-gate int flushflag; 23250Sstevel@tonic-gate 23260Sstevel@tonic-gate /* 23270Sstevel@tonic-gate * If we're in the midst of close, then flush everything. Don't 23280Sstevel@tonic-gate * leave stale ioctls lying about. 23290Sstevel@tonic-gate */ 23300Sstevel@tonic-gate flushflag = (zs->zs_flags & ZS_CLOSING) ? FLUSHALL : FLUSHDATA; 23310Sstevel@tonic-gate flushq(za->za_ttycommon.t_writeq, flushflag); 23320Sstevel@tonic-gate (void) putnextctl(q, M_HANGUP); 23330Sstevel@tonic-gate } 23340Sstevel@tonic-gate 23350Sstevel@tonic-gate if (m_error) 23360Sstevel@tonic-gate (void) putnextctl1(q, M_ERROR, m_error); 23370Sstevel@tonic-gate 23380Sstevel@tonic-gate za->za_soft_active = 0; 23390Sstevel@tonic-gate 23400Sstevel@tonic-gate if (wakeup || (zs->zs_flags & ZS_CLOSED)) 23410Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 23420Sstevel@tonic-gate 23430Sstevel@tonic-gate return (0); 23440Sstevel@tonic-gate } 23450Sstevel@tonic-gate 23460Sstevel@tonic-gate /* 23470Sstevel@tonic-gate * Start output on a line, unless it's busy, frozen, or otherwise. 23480Sstevel@tonic-gate */ 23490Sstevel@tonic-gate static void 23500Sstevel@tonic-gate zsa_start(struct zscom *zs) 23510Sstevel@tonic-gate { 23520Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 23530Sstevel@tonic-gate register int cc; 23540Sstevel@tonic-gate register queue_t *q; 23550Sstevel@tonic-gate register mblk_t *bp; 23560Sstevel@tonic-gate uchar_t *rptr, *wptr; 23570Sstevel@tonic-gate 23580Sstevel@tonic-gate /* 23590Sstevel@tonic-gate * If the chip is busy (i.e., we're waiting for a break timeout 23600Sstevel@tonic-gate * to expire, or for the current transmission to finish, or for 23610Sstevel@tonic-gate * output to finish draining from chip), don't grab anything new. 23620Sstevel@tonic-gate */ 23630Sstevel@tonic-gate if ((za->za_flags & (ZAS_BREAK|ZAS_BUSY|ZAS_DRAINING)) || 23640Sstevel@tonic-gate zs->zs_suspended) 23650Sstevel@tonic-gate return; 23660Sstevel@tonic-gate 23670Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) { 23680Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 23690Sstevel@tonic-gate if (za->za_rcv_flags_mask & DO_RETRANSMIT) { 23700Sstevel@tonic-gate rptr = zs->zs_wr_cur; 23710Sstevel@tonic-gate wptr = zs->zs_wr_lim; 23720Sstevel@tonic-gate goto zsa_start_retransmit; 23730Sstevel@tonic-gate 23740Sstevel@tonic-gate } 23750Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 23760Sstevel@tonic-gate } 23770Sstevel@tonic-gate 23780Sstevel@tonic-gate /* 23790Sstevel@tonic-gate * If we have a flow-control character to transmit, do it now. 23800Sstevel@tonic-gate */ 23810Sstevel@tonic-gate if (za->za_flowc != '\0') { 23820Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 23830Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) { 23840Sstevel@tonic-gate if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) != 23850Sstevel@tonic-gate (ZSRR0_CTS|ZSRR0_TX_READY)) { 23860Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 23870Sstevel@tonic-gate return; 23880Sstevel@tonic-gate } 23890Sstevel@tonic-gate } else if (!(SCC_READ0() & ZSRR0_TX_READY)) { 23900Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 23910Sstevel@tonic-gate return; 23920Sstevel@tonic-gate } 23930Sstevel@tonic-gate 23940Sstevel@tonic-gate ZSDELAY(); 23950Sstevel@tonic-gate SCC_WRITEDATA(za->za_flowc); 23960Sstevel@tonic-gate za->za_flowc = '\0'; 23970Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 23980Sstevel@tonic-gate return; 23990Sstevel@tonic-gate } 24000Sstevel@tonic-gate 24010Sstevel@tonic-gate /* 24020Sstevel@tonic-gate * If we're waiting for a delay timeout to expire, don't grab 24030Sstevel@tonic-gate * anything new. 24040Sstevel@tonic-gate */ 24050Sstevel@tonic-gate if (za->za_flags & ZAS_DELAY) 24060Sstevel@tonic-gate return; 24070Sstevel@tonic-gate 24080Sstevel@tonic-gate if ((q = za->za_ttycommon.t_writeq) == NULL) 24090Sstevel@tonic-gate return; /* not attached to a stream */ 24100Sstevel@tonic-gate 24110Sstevel@tonic-gate zsa_start_again: 24120Sstevel@tonic-gate for (;;) { 24130Sstevel@tonic-gate if ((bp = getq(q)) == NULL) 24140Sstevel@tonic-gate return; /* no data to transmit */ 24150Sstevel@tonic-gate 24160Sstevel@tonic-gate /* 24170Sstevel@tonic-gate * We have a message block to work on. 24180Sstevel@tonic-gate * Check whether it's a break, a delay, or an ioctl (the latter 24190Sstevel@tonic-gate * occurs if the ioctl in question was waiting for the output 24200Sstevel@tonic-gate * to drain). If it's one of those, process it immediately. 24210Sstevel@tonic-gate */ 24220Sstevel@tonic-gate switch (bp->b_datap->db_type) { 24230Sstevel@tonic-gate 24240Sstevel@tonic-gate case M_BREAK: 24250Sstevel@tonic-gate /* 24260Sstevel@tonic-gate * Set the break bit, and arrange for "zsa_restart" 24270Sstevel@tonic-gate * to be called in 1/4 second; it will turn the 24280Sstevel@tonic-gate * break bit off, and call "zsa_start" to grab 24290Sstevel@tonic-gate * the next message. 24300Sstevel@tonic-gate */ 24310Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 24320Sstevel@tonic-gate SCC_BIS(5, ZSWR5_BREAK); 24330Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 24340Sstevel@tonic-gate if (!za->za_zsa_restart_id) { 24350Sstevel@tonic-gate za->za_zsa_restart_id = 24360Sstevel@tonic-gate timeout(zsa_restart, zs, hz/4); 24370Sstevel@tonic-gate } 24380Sstevel@tonic-gate za->za_flags |= ZAS_BREAK; 24390Sstevel@tonic-gate freemsg(bp); 24400Sstevel@tonic-gate return; /* wait for this to finish */ 24410Sstevel@tonic-gate 24420Sstevel@tonic-gate case M_DELAY: 24430Sstevel@tonic-gate /* 24440Sstevel@tonic-gate * Arrange for "zsa_restart" to be called when the 24450Sstevel@tonic-gate * delay expires; it will turn MTS_DELAY off, 24460Sstevel@tonic-gate * and call "zsa_start" to grab the next message. 24470Sstevel@tonic-gate */ 24480Sstevel@tonic-gate if (! za->za_zsa_restart_id) { 24490Sstevel@tonic-gate za->za_zsa_restart_id = timeout(zsa_restart, 24500Sstevel@tonic-gate zs, 24510Sstevel@tonic-gate (int)(*(unsigned char *)bp->b_rptr + 6)); 24520Sstevel@tonic-gate } 24530Sstevel@tonic-gate za->za_flags |= ZAS_DELAY; 24540Sstevel@tonic-gate freemsg(bp); 24550Sstevel@tonic-gate return; /* wait for this to finish */ 24560Sstevel@tonic-gate 24570Sstevel@tonic-gate case M_IOCTL: 24580Sstevel@tonic-gate /* 24590Sstevel@tonic-gate * This ioctl was waiting for the output ahead of 24600Sstevel@tonic-gate * it to drain; obviously, it has. Do it, and 24610Sstevel@tonic-gate * then grab the next message after it. 24620Sstevel@tonic-gate */ 24630Sstevel@tonic-gate zsa_ioctl(za, q, bp); 24640Sstevel@tonic-gate continue; 24650Sstevel@tonic-gate default: /* M_DATA */ 24660Sstevel@tonic-gate goto zsa_start_transmit; 24670Sstevel@tonic-gate } 24680Sstevel@tonic-gate 24690Sstevel@tonic-gate } 24700Sstevel@tonic-gate zsa_start_transmit: 24710Sstevel@tonic-gate /* 24720Sstevel@tonic-gate * We have data to transmit. If output is stopped, put 24730Sstevel@tonic-gate * it back and try again later. 24740Sstevel@tonic-gate */ 24750Sstevel@tonic-gate if (za->za_flags & ZAS_STOPPED) { 24760Sstevel@tonic-gate (void) putbq(q, bp); 24770Sstevel@tonic-gate return; 24780Sstevel@tonic-gate } 24790Sstevel@tonic-gate 24800Sstevel@tonic-gate za->za_xmitblk = bp; 24810Sstevel@tonic-gate rptr = bp->b_rptr; 24820Sstevel@tonic-gate wptr = bp->b_wptr; 24830Sstevel@tonic-gate cc = wptr - rptr; 24840Sstevel@tonic-gate bp = bp->b_cont; 24850Sstevel@tonic-gate if (bp != NULL) { 24860Sstevel@tonic-gate za->za_xmitblk->b_cont = NULL; 24870Sstevel@tonic-gate (void) putbq(q, bp); /* not done with this message yet */ 24880Sstevel@tonic-gate } 24890Sstevel@tonic-gate 24900Sstevel@tonic-gate if (rptr >= wptr) { 24910Sstevel@tonic-gate freeb(za->za_xmitblk); 24920Sstevel@tonic-gate za->za_xmitblk = NULL; 24930Sstevel@tonic-gate goto zsa_start_again; 24940Sstevel@tonic-gate } 24950Sstevel@tonic-gate 24960Sstevel@tonic-gate /* 24970Sstevel@tonic-gate * In 5-bit mode, the high order bits are used 24980Sstevel@tonic-gate * to indicate character sizes less than five, 24990Sstevel@tonic-gate * so we need to explicitly mask before transmitting 25000Sstevel@tonic-gate */ 25010Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CSIZE) == CS5) { 25020Sstevel@tonic-gate register unsigned char *p = rptr; 25030Sstevel@tonic-gate register int cnt = cc; 25040Sstevel@tonic-gate 25050Sstevel@tonic-gate while (cnt--) 25060Sstevel@tonic-gate *p++ &= (unsigned char) 0x1f; 25070Sstevel@tonic-gate } 25080Sstevel@tonic-gate 25090Sstevel@tonic-gate /* 25100Sstevel@tonic-gate * Set up this block for pseudo-DMA. 25110Sstevel@tonic-gate */ 25120Sstevel@tonic-gate 25130Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 25140Sstevel@tonic-gate zs->zs_wr_cur = rptr; 25150Sstevel@tonic-gate zs->zs_wr_lim = wptr; 25160Sstevel@tonic-gate 25170Sstevel@tonic-gate zsa_start_retransmit: 25180Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_TRANSMIT; 25190Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) { 25200Sstevel@tonic-gate if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) != 25210Sstevel@tonic-gate (ZSRR0_CTS|ZSRR0_TX_READY)) { 25220Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_RETRANSMIT; 25230Sstevel@tonic-gate za->za_flags |= ZAS_BUSY; 25240Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 25250Sstevel@tonic-gate return; 25260Sstevel@tonic-gate } 25270Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 25280Sstevel@tonic-gate } else if (!(SCC_READ0() & ZSRR0_TX_READY)) { 25290Sstevel@tonic-gate za->za_flags |= ZAS_BUSY; 25300Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 25310Sstevel@tonic-gate return; 25320Sstevel@tonic-gate } 25330Sstevel@tonic-gate /* 25340Sstevel@tonic-gate * If the transmitter is ready, shove the first 25350Sstevel@tonic-gate * character out. 25360Sstevel@tonic-gate */ 25370Sstevel@tonic-gate ZSDELAY(); 25380Sstevel@tonic-gate SCC_WRITEDATA(*rptr++); 25390Sstevel@tonic-gate #ifdef ZSA_DEBUG 25400Sstevel@tonic-gate za->za_wr++; 25410Sstevel@tonic-gate #endif 25420Sstevel@tonic-gate zs->zs_wr_cur = rptr; 25430Sstevel@tonic-gate za->za_flags |= ZAS_BUSY; 25440Sstevel@tonic-gate zs->zs_flags |= ZS_PROGRESS; 25450Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 25460Sstevel@tonic-gate } 25470Sstevel@tonic-gate 25480Sstevel@tonic-gate /* 25490Sstevel@tonic-gate * Restart output on a line after a delay or break timer expired. 25500Sstevel@tonic-gate */ 25510Sstevel@tonic-gate static void 25520Sstevel@tonic-gate zsa_restart(void *arg) 25530Sstevel@tonic-gate { 25540Sstevel@tonic-gate struct zscom *zs = arg; 25550Sstevel@tonic-gate struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 25560Sstevel@tonic-gate 25570Sstevel@tonic-gate /* 25580Sstevel@tonic-gate * If break timer expired, turn off the break bit. 25590Sstevel@tonic-gate */ 25600Sstevel@tonic-gate mutex_enter(zs->zs_excl); 25610Sstevel@tonic-gate if (!za->za_zsa_restart_id) { 25620Sstevel@tonic-gate mutex_exit(zs->zs_excl); 25630Sstevel@tonic-gate return; 25640Sstevel@tonic-gate } 25650Sstevel@tonic-gate za->za_zsa_restart_id = 0; 25660Sstevel@tonic-gate if (za->za_flags & ZAS_BREAK) { 25670Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 25680Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK); 25690Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 25700Sstevel@tonic-gate } 25710Sstevel@tonic-gate za->za_flags &= ~(ZAS_DELAY|ZAS_BREAK); 25720Sstevel@tonic-gate if (za->za_ttycommon.t_writeq != NULL) 25730Sstevel@tonic-gate zsa_start(zs); 25740Sstevel@tonic-gate mutex_exit(zs->zs_excl); 25750Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 25760Sstevel@tonic-gate } 25770Sstevel@tonic-gate 25780Sstevel@tonic-gate /* 25790Sstevel@tonic-gate * See if the receiver has any data after zs_tick delay 25800Sstevel@tonic-gate */ 25810Sstevel@tonic-gate static void 25820Sstevel@tonic-gate zsa_kick_rcv(void *arg) 25830Sstevel@tonic-gate { 25840Sstevel@tonic-gate struct zscom *zs = arg; 25850Sstevel@tonic-gate struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 25860Sstevel@tonic-gate queue_t *q; 25870Sstevel@tonic-gate int tmp; 25880Sstevel@tonic-gate mblk_t *mp; 25890Sstevel@tonic-gate uchar_t za_soft_active, za_kick_active; 25900Sstevel@tonic-gate int allocbcount = 0; 25910Sstevel@tonic-gate int do_ttycommon_qfull = 0; 25920Sstevel@tonic-gate mblk_t *head = NULL, *tail = NULL; 25930Sstevel@tonic-gate 25940Sstevel@tonic-gate mutex_enter(zs->zs_excl); 25950Sstevel@tonic-gate if (za->za_kick_rcv_id == 0 || (zs->zs_flags & ZS_CLOSED)) { 25960Sstevel@tonic-gate mutex_exit(zs->zs_excl); 25970Sstevel@tonic-gate return; 25980Sstevel@tonic-gate } 25990Sstevel@tonic-gate za_soft_active = za->za_soft_active; 26000Sstevel@tonic-gate za_kick_active = za->za_kick_active; 26010Sstevel@tonic-gate q = za->za_ttycommon.t_readq; 26020Sstevel@tonic-gate if (!q) { 26030Sstevel@tonic-gate mutex_exit(zs->zs_excl); 26040Sstevel@tonic-gate return; 26050Sstevel@tonic-gate } 26060Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 26070Sstevel@tonic-gate if (zs->zs_rd_cur) { 26080Sstevel@tonic-gate ZSA_KICK_RCV; 26090Sstevel@tonic-gate za->za_kick_rcv_count = tmp = ZA_KICK_RCV_COUNT; 26100Sstevel@tonic-gate } else 26110Sstevel@tonic-gate tmp = --za->za_kick_rcv_count; 26120Sstevel@tonic-gate if (tmp > 0 || za_soft_active || za_kick_active) { 26130Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 26140Sstevel@tonic-gate if (g_zsticks) 26150Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv, 26160Sstevel@tonic-gate zs, g_zsticks); 26170Sstevel@tonic-gate else 26180Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv, 26190Sstevel@tonic-gate zs, zsticks[SPEED(za->za_ttycommon.t_cflag)]); 26200Sstevel@tonic-gate if (za_soft_active || za_kick_active) { 26210Sstevel@tonic-gate mutex_exit(zs->zs_excl); 26220Sstevel@tonic-gate return; 26230Sstevel@tonic-gate } 26240Sstevel@tonic-gate } else { 26250Sstevel@tonic-gate za->za_kick_rcv_id = 0; 26260Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 26270Sstevel@tonic-gate } 26280Sstevel@tonic-gate 26290Sstevel@tonic-gate 26300Sstevel@tonic-gate for (;;) { 26310Sstevel@tonic-gate ZSA_SEEQ(mp); 26320Sstevel@tonic-gate if (!mp) 26330Sstevel@tonic-gate break; 26340Sstevel@tonic-gate 26350Sstevel@tonic-gate allocbcount++; 26360Sstevel@tonic-gate 26370Sstevel@tonic-gate if (mp->b_datap->db_type <= QPCTL) { 26380Sstevel@tonic-gate if (!(canputnext(q))) { 26390Sstevel@tonic-gate if (za->za_grace_flow_control >= 26400Sstevel@tonic-gate zsa_grace_flow_control) { 26410Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { 26420Sstevel@tonic-gate allocbcount--; 26430Sstevel@tonic-gate break; 26440Sstevel@tonic-gate } 26450Sstevel@tonic-gate ZSA_GETQ(mp); 26460Sstevel@tonic-gate freemsg(mp); 26470Sstevel@tonic-gate do_ttycommon_qfull = 1; 26480Sstevel@tonic-gate continue; 26490Sstevel@tonic-gate } else 26500Sstevel@tonic-gate za->za_grace_flow_control++; 26510Sstevel@tonic-gate } else 26520Sstevel@tonic-gate za->za_grace_flow_control = 0; 26530Sstevel@tonic-gate } 26540Sstevel@tonic-gate ZSA_GETQ(mp); 26550Sstevel@tonic-gate if (!head) { 26560Sstevel@tonic-gate head = mp; 26570Sstevel@tonic-gate } else { 26580Sstevel@tonic-gate if (!tail) 26590Sstevel@tonic-gate tail = head; 26600Sstevel@tonic-gate tail->b_next = mp; 26610Sstevel@tonic-gate tail = mp; 26620Sstevel@tonic-gate } 26630Sstevel@tonic-gate } 26640Sstevel@tonic-gate 26650Sstevel@tonic-gate if (allocbcount) 26660Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount); 26670Sstevel@tonic-gate 26680Sstevel@tonic-gate za->za_kick_active = 1; 26690Sstevel@tonic-gate mutex_exit(zs->zs_excl); 26700Sstevel@tonic-gate 26710Sstevel@tonic-gate if (do_ttycommon_qfull) { 26720Sstevel@tonic-gate ttycommon_qfull(&za->za_ttycommon, q); 26730Sstevel@tonic-gate mutex_enter(zs->zs_excl); 26740Sstevel@tonic-gate zsa_start(zs); 26750Sstevel@tonic-gate mutex_exit(zs->zs_excl); 26760Sstevel@tonic-gate } 26770Sstevel@tonic-gate 26780Sstevel@tonic-gate while (head) { 26790Sstevel@tonic-gate if (!tail) { 26800Sstevel@tonic-gate putnext(q, head); 26810Sstevel@tonic-gate break; 26820Sstevel@tonic-gate } 26830Sstevel@tonic-gate mp = head; 26840Sstevel@tonic-gate head = head->b_next; 26850Sstevel@tonic-gate mp->b_next = NULL; 26860Sstevel@tonic-gate putnext(q, mp); 26870Sstevel@tonic-gate 26880Sstevel@tonic-gate } 26890Sstevel@tonic-gate za->za_kick_active = 0; 26900Sstevel@tonic-gate 26910Sstevel@tonic-gate if (zs->zs_flags & ZS_CLOSED) 26920Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 26930Sstevel@tonic-gate } 26940Sstevel@tonic-gate 26950Sstevel@tonic-gate /* 26960Sstevel@tonic-gate * Retry an "ioctl", now that "bufcall" claims we may be able to allocate 26970Sstevel@tonic-gate * the buffer we need. 26980Sstevel@tonic-gate */ 26990Sstevel@tonic-gate static void 27000Sstevel@tonic-gate zsa_reioctl(void *arg) 27010Sstevel@tonic-gate { 27020Sstevel@tonic-gate struct asyncline *za = arg; 27030Sstevel@tonic-gate struct zscom *zs = za->za_common; 27040Sstevel@tonic-gate queue_t *q; 27050Sstevel@tonic-gate mblk_t *mp; 27060Sstevel@tonic-gate 27070Sstevel@tonic-gate /* 27080Sstevel@tonic-gate * The bufcall is no longer pending. 27090Sstevel@tonic-gate */ 27100Sstevel@tonic-gate mutex_enter(zs->zs_excl); 27110Sstevel@tonic-gate if (!za->za_wbufcid) { 27120Sstevel@tonic-gate mutex_exit(zs->zs_excl); 27130Sstevel@tonic-gate return; 27140Sstevel@tonic-gate } 27150Sstevel@tonic-gate za->za_wbufcid = 0; 27160Sstevel@tonic-gate if ((q = za->za_ttycommon.t_writeq) == NULL) { 27170Sstevel@tonic-gate mutex_exit(zs->zs_excl); 27180Sstevel@tonic-gate return; 27190Sstevel@tonic-gate } 27200Sstevel@tonic-gate if ((mp = za->za_ttycommon.t_iocpending) != NULL) { 27210Sstevel@tonic-gate /* 27220Sstevel@tonic-gate * not pending any more 27230Sstevel@tonic-gate */ 27240Sstevel@tonic-gate za->za_ttycommon.t_iocpending = NULL; 27250Sstevel@tonic-gate zsa_ioctl(za, q, mp); 27260Sstevel@tonic-gate } 27270Sstevel@tonic-gate mutex_exit(zs->zs_excl); 27280Sstevel@tonic-gate } 27290Sstevel@tonic-gate 27300Sstevel@tonic-gate /* 27310Sstevel@tonic-gate * Process an "ioctl" message sent down to us. 27320Sstevel@tonic-gate * Note that we don't need to get any locks until we are ready to access 27330Sstevel@tonic-gate * the hardware. Nothing we access until then is going to be altered 27340Sstevel@tonic-gate * outside of the STREAMS framework, so we should be safe. 27350Sstevel@tonic-gate */ 27360Sstevel@tonic-gate static void 27370Sstevel@tonic-gate zsa_ioctl(struct asyncline *za, queue_t *wq, mblk_t *mp) 27380Sstevel@tonic-gate { 27390Sstevel@tonic-gate register struct zscom *zs = za->za_common; 27400Sstevel@tonic-gate register struct iocblk *iocp; 27410Sstevel@tonic-gate register unsigned datasize; 27420Sstevel@tonic-gate int error; 27430Sstevel@tonic-gate register mblk_t *tmp; 27440Sstevel@tonic-gate 27450Sstevel@tonic-gate if (za->za_ttycommon.t_iocpending != NULL) { 27460Sstevel@tonic-gate /* 27470Sstevel@tonic-gate * We were holding an "ioctl" response pending the 27480Sstevel@tonic-gate * availability of an "mblk" to hold data to be passed up; 27490Sstevel@tonic-gate * another "ioctl" came through, which means that "ioctl" 27500Sstevel@tonic-gate * must have timed out or been aborted. 27510Sstevel@tonic-gate */ 27520Sstevel@tonic-gate freemsg(za->za_ttycommon.t_iocpending); 27530Sstevel@tonic-gate za->za_ttycommon.t_iocpending = NULL; 27540Sstevel@tonic-gate } 27550Sstevel@tonic-gate 27560Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 27570Sstevel@tonic-gate 27580Sstevel@tonic-gate /* 27590Sstevel@tonic-gate * The only way in which "ttycommon_ioctl" can fail is if the "ioctl" 27600Sstevel@tonic-gate * requires a response containing data to be returned to the user, 27610Sstevel@tonic-gate * and no mblk could be allocated for the data. 27620Sstevel@tonic-gate * No such "ioctl" alters our state. Thus, we always go ahead and 27630Sstevel@tonic-gate * do any state-changes the "ioctl" calls for. If we couldn't allocate 27640Sstevel@tonic-gate * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so 27650Sstevel@tonic-gate * we just call "bufcall" to request that we be called back when we 27660Sstevel@tonic-gate * stand a better chance of allocating the data. 27670Sstevel@tonic-gate */ 27680Sstevel@tonic-gate mutex_exit(zs->zs_excl); 27690Sstevel@tonic-gate datasize = ttycommon_ioctl(&za->za_ttycommon, wq, mp, &error); 27700Sstevel@tonic-gate mutex_enter(zs->zs_excl); 27710Sstevel@tonic-gate if (za->za_ttycommon.t_flags & TS_SOFTCAR) 27720Sstevel@tonic-gate zssoftCAR[zs->zs_unit] = 1; 27730Sstevel@tonic-gate else 27740Sstevel@tonic-gate zssoftCAR[zs->zs_unit] = 0; 27750Sstevel@tonic-gate if (datasize != 0) { 27760Sstevel@tonic-gate if (za->za_wbufcid) 27770Sstevel@tonic-gate unbufcall(za->za_wbufcid); 27780Sstevel@tonic-gate za->za_wbufcid = bufcall(datasize, BPRI_HI, zsa_reioctl, za); 27790Sstevel@tonic-gate return; 27800Sstevel@tonic-gate } 27810Sstevel@tonic-gate 27820Sstevel@tonic-gate 27830Sstevel@tonic-gate if (error == 0) { 27840Sstevel@tonic-gate /* 27850Sstevel@tonic-gate * "ttycommon_ioctl" did most of the work; we just use the 27860Sstevel@tonic-gate * data it set up. 27870Sstevel@tonic-gate */ 27880Sstevel@tonic-gate switch (iocp->ioc_cmd) { 27890Sstevel@tonic-gate 27900Sstevel@tonic-gate case TCSETS: 27910Sstevel@tonic-gate case TCSETSW: 27920Sstevel@tonic-gate case TCSETSF: 27930Sstevel@tonic-gate case TCSETA: 27940Sstevel@tonic-gate case TCSETAW: 27950Sstevel@tonic-gate case TCSETAF: 27960Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 27970Sstevel@tonic-gate zsa_program(za, 1); 27980Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(za); 27990Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 28000Sstevel@tonic-gate break; 28010Sstevel@tonic-gate } 28020Sstevel@tonic-gate } else if (error < 0) { 28030Sstevel@tonic-gate /* 28040Sstevel@tonic-gate * "ttycommon_ioctl" didn't do anything; we process it here. 28050Sstevel@tonic-gate */ 28060Sstevel@tonic-gate error = 0; 28070Sstevel@tonic-gate 28080Sstevel@tonic-gate switch (iocp->ioc_cmd) { 28090Sstevel@tonic-gate 28100Sstevel@tonic-gate case TCSBRK: 28110Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 28120Sstevel@tonic-gate if (error != 0) 28130Sstevel@tonic-gate break; 28140Sstevel@tonic-gate 28150Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr == 0) { 28160Sstevel@tonic-gate /* 28170Sstevel@tonic-gate * The delay ensures that a 3 byte transmit 28180Sstevel@tonic-gate * fifo is empty. 28190Sstevel@tonic-gate */ 28200Sstevel@tonic-gate mutex_exit(zs->zs_excl); 28210Sstevel@tonic-gate delay(ztdelay(SPEED(za->za_ttycommon.t_cflag))); 28220Sstevel@tonic-gate mutex_enter(zs->zs_excl); 28230Sstevel@tonic-gate 28240Sstevel@tonic-gate /* 28250Sstevel@tonic-gate * Set the break bit, and arrange for 28260Sstevel@tonic-gate * "zsa_restart" to be called in 1/4 second; 28270Sstevel@tonic-gate * it will turn the break bit off, and call 28280Sstevel@tonic-gate * "zsa_start" to grab the next message. 28290Sstevel@tonic-gate */ 28300Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 28310Sstevel@tonic-gate SCC_BIS(5, ZSWR5_BREAK); 28320Sstevel@tonic-gate if (!za->za_zsa_restart_id) { 28330Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 28340Sstevel@tonic-gate za->za_zsa_restart_id = 28350Sstevel@tonic-gate timeout(zsa_restart, zs, hz / 4); 28360Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 28370Sstevel@tonic-gate } 28380Sstevel@tonic-gate za->za_flags |= ZAS_BREAK; 28390Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 28400Sstevel@tonic-gate } 28410Sstevel@tonic-gate break; 28420Sstevel@tonic-gate 28430Sstevel@tonic-gate case TIOCSBRK: 28440Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 28450Sstevel@tonic-gate SCC_BIS(5, ZSWR5_BREAK); 28460Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 28470Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 28480Sstevel@tonic-gate break; 28490Sstevel@tonic-gate 28500Sstevel@tonic-gate case TIOCCBRK: 28510Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 28520Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK); 28530Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 28540Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 28550Sstevel@tonic-gate break; 28560Sstevel@tonic-gate 28570Sstevel@tonic-gate case TIOCMSET: 28580Sstevel@tonic-gate case TIOCMBIS: 28590Sstevel@tonic-gate case TIOCMBIC: { 28600Sstevel@tonic-gate int mlines; 28610Sstevel@tonic-gate 28620Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) { 28630Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL); 28640Sstevel@tonic-gate break; 28650Sstevel@tonic-gate } 28660Sstevel@tonic-gate 28670Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 28680Sstevel@tonic-gate if (error != 0) 28690Sstevel@tonic-gate break; 28700Sstevel@tonic-gate 28710Sstevel@tonic-gate mlines = *(int *)mp->b_cont->b_rptr; 28720Sstevel@tonic-gate 28730Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 28740Sstevel@tonic-gate switch (iocp->ioc_cmd) { 28750Sstevel@tonic-gate case TIOCMSET: 28760Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(mlines), DMSET); 28770Sstevel@tonic-gate break; 28780Sstevel@tonic-gate case TIOCMBIS: 28790Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(mlines), DMBIS); 28800Sstevel@tonic-gate break; 28810Sstevel@tonic-gate case TIOCMBIC: 28820Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(mlines), DMBIC); 28830Sstevel@tonic-gate break; 28840Sstevel@tonic-gate } 28850Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 28860Sstevel@tonic-gate 28870Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0); 28880Sstevel@tonic-gate break; 28890Sstevel@tonic-gate } 28900Sstevel@tonic-gate 28910Sstevel@tonic-gate case TIOCMGET: 28920Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED); 28930Sstevel@tonic-gate if (tmp == NULL) { 28940Sstevel@tonic-gate error = EAGAIN; 28950Sstevel@tonic-gate break; 28960Sstevel@tonic-gate } 28970Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT) 28980Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0); 28990Sstevel@tonic-gate else 29000Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp); 29010Sstevel@tonic-gate 29020Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 29030Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr = 29040Sstevel@tonic-gate zstodm(zsmctl(zs, 0, DMGET)); 29050Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 29060Sstevel@tonic-gate /* 29070Sstevel@tonic-gate * qreply done below 29080Sstevel@tonic-gate */ 29090Sstevel@tonic-gate break; 29100Sstevel@tonic-gate 29110Sstevel@tonic-gate default: 29120Sstevel@tonic-gate /* 29130Sstevel@tonic-gate * If we don't understand it, it's an error. NAK it. 29140Sstevel@tonic-gate */ 29150Sstevel@tonic-gate error = EINVAL; 29160Sstevel@tonic-gate break; 29170Sstevel@tonic-gate } 29180Sstevel@tonic-gate } 29190Sstevel@tonic-gate 29200Sstevel@tonic-gate if (error != 0) { 29210Sstevel@tonic-gate iocp->ioc_error = error; 29220Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 29230Sstevel@tonic-gate } 29240Sstevel@tonic-gate 29250Sstevel@tonic-gate ZSA_QREPLY(wq, mp); 29260Sstevel@tonic-gate } 29270Sstevel@tonic-gate 29280Sstevel@tonic-gate 29290Sstevel@tonic-gate static int 29300Sstevel@tonic-gate dmtozs(int bits) 29310Sstevel@tonic-gate { 29320Sstevel@tonic-gate register int b = 0; 29330Sstevel@tonic-gate 29340Sstevel@tonic-gate if (bits & TIOCM_CAR) 29350Sstevel@tonic-gate b |= ZSRR0_CD; 29360Sstevel@tonic-gate if (bits & TIOCM_CTS) 29370Sstevel@tonic-gate b |= ZSRR0_CTS; 29380Sstevel@tonic-gate if (bits & TIOCM_RTS) 29390Sstevel@tonic-gate b |= ZSWR5_RTS; 29400Sstevel@tonic-gate if (bits & TIOCM_DTR) 29410Sstevel@tonic-gate b |= ZSWR5_DTR; 29420Sstevel@tonic-gate return (b); 29430Sstevel@tonic-gate } 29440Sstevel@tonic-gate 29450Sstevel@tonic-gate static int 29460Sstevel@tonic-gate zstodm(int bits) 29470Sstevel@tonic-gate { 29480Sstevel@tonic-gate register int b; 29490Sstevel@tonic-gate 29500Sstevel@tonic-gate b = 0; 29510Sstevel@tonic-gate if (bits & ZSRR0_CD) 29520Sstevel@tonic-gate b |= TIOCM_CAR; 29530Sstevel@tonic-gate if (bits & ZSRR0_CTS) 29540Sstevel@tonic-gate b |= TIOCM_CTS; 29550Sstevel@tonic-gate if (bits & ZSWR5_RTS) 29560Sstevel@tonic-gate b |= TIOCM_RTS; 29570Sstevel@tonic-gate if (bits & ZSWR5_DTR) 29580Sstevel@tonic-gate b |= TIOCM_DTR; 29590Sstevel@tonic-gate return (b); 29600Sstevel@tonic-gate } 29610Sstevel@tonic-gate 29620Sstevel@tonic-gate /* 29630Sstevel@tonic-gate * Assemble registers and flags necessary to program the port to our liking. 29640Sstevel@tonic-gate * For async operation, most of this is based on the values of 29650Sstevel@tonic-gate * the "c_iflag" and "c_cflag" fields supplied to us. 29660Sstevel@tonic-gate */ 29670Sstevel@tonic-gate static void 29680Sstevel@tonic-gate zsa_program(struct asyncline *za, int setibaud) 29690Sstevel@tonic-gate { 29700Sstevel@tonic-gate register struct zscom *zs = za->za_common; 29710Sstevel@tonic-gate register struct zs_prog *zspp; 29720Sstevel@tonic-gate register int wr3, wr4, wr5, wr15, speed, baudrate, flags = 0; 29730Sstevel@tonic-gate 29740Sstevel@tonic-gate if ((baudrate = SPEED(za->za_ttycommon.t_cflag)) == 0) { 29750Sstevel@tonic-gate /* 29760Sstevel@tonic-gate * Hang up line. 29770Sstevel@tonic-gate */ 29780Sstevel@tonic-gate (void) zsmctl(zs, ZS_OFF, DMSET); 29790Sstevel@tonic-gate return; 29800Sstevel@tonic-gate } 29810Sstevel@tonic-gate 29820Sstevel@tonic-gate /* 29830Sstevel@tonic-gate * set input speed same as output, as split speed not supported 29840Sstevel@tonic-gate */ 29850Sstevel@tonic-gate if (setibaud) { 29860Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~(CIBAUD); 29870Sstevel@tonic-gate if (baudrate > CBAUD) { 29880Sstevel@tonic-gate za->za_ttycommon.t_cflag |= CIBAUDEXT; 29890Sstevel@tonic-gate za->za_ttycommon.t_cflag |= 29900Sstevel@tonic-gate (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD); 29910Sstevel@tonic-gate } else { 29920Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~CIBAUDEXT; 29930Sstevel@tonic-gate za->za_ttycommon.t_cflag |= 29940Sstevel@tonic-gate ((baudrate << IBSHIFT) & CIBAUD); 29950Sstevel@tonic-gate } 29960Sstevel@tonic-gate } 29970Sstevel@tonic-gate 29980Sstevel@tonic-gate /* 29990Sstevel@tonic-gate * Do not allow the console/keyboard device to have its receiver 30000Sstevel@tonic-gate * disabled; doing that would mean you couldn't type an abort 30010Sstevel@tonic-gate * sequence. 30020Sstevel@tonic-gate */ 30030Sstevel@tonic-gate if ((za->za_dev == rconsdev) || (za->za_dev == kbddev) || 30040Sstevel@tonic-gate (za->za_dev == stdindev) || (za->za_ttycommon.t_cflag & CREAD)) 30050Sstevel@tonic-gate wr3 = ZSWR3_RX_ENABLE; 30060Sstevel@tonic-gate else 30070Sstevel@tonic-gate wr3 = 0; 30080Sstevel@tonic-gate wr4 = ZSWR4_X16_CLK; 30090Sstevel@tonic-gate wr5 = (zs->zs_wreg[5] & (ZSWR5_RTS|ZSWR5_DTR)) | ZSWR5_TX_ENABLE; 30100Sstevel@tonic-gate 30110Sstevel@tonic-gate if (zsb134_weird && baudrate == B134) { /* what a joke! */ 30120Sstevel@tonic-gate /* 30130Sstevel@tonic-gate * XXX - should B134 set all this crap in the compatibility 30140Sstevel@tonic-gate * module, leaving this stuff fairly clean? 30150Sstevel@tonic-gate */ 30160Sstevel@tonic-gate flags |= ZSP_PARITY_SPECIAL; 30170Sstevel@tonic-gate wr3 |= ZSWR3_RX_6; 30180Sstevel@tonic-gate wr4 |= ZSWR4_PARITY_ENABLE | ZSWR4_PARITY_EVEN; 30190Sstevel@tonic-gate wr4 |= ZSWR4_1_5_STOP; 30200Sstevel@tonic-gate wr5 |= ZSWR5_TX_6; 30210Sstevel@tonic-gate } else { 30220Sstevel@tonic-gate 30230Sstevel@tonic-gate switch (za->za_ttycommon.t_cflag & CSIZE) { 30240Sstevel@tonic-gate 30250Sstevel@tonic-gate case CS5: 30260Sstevel@tonic-gate wr3 |= ZSWR3_RX_5; 30270Sstevel@tonic-gate wr5 |= ZSWR5_TX_5; 30280Sstevel@tonic-gate break; 30290Sstevel@tonic-gate 30300Sstevel@tonic-gate case CS6: 30310Sstevel@tonic-gate wr3 |= ZSWR3_RX_6; 30320Sstevel@tonic-gate wr5 |= ZSWR5_TX_6; 30330Sstevel@tonic-gate break; 30340Sstevel@tonic-gate 30350Sstevel@tonic-gate case CS7: 30360Sstevel@tonic-gate wr3 |= ZSWR3_RX_7; 30370Sstevel@tonic-gate wr5 |= ZSWR5_TX_7; 30380Sstevel@tonic-gate break; 30390Sstevel@tonic-gate 30400Sstevel@tonic-gate case CS8: 30410Sstevel@tonic-gate wr3 |= ZSWR3_RX_8; 30420Sstevel@tonic-gate wr5 |= ZSWR5_TX_8; 30430Sstevel@tonic-gate break; 30440Sstevel@tonic-gate } 30450Sstevel@tonic-gate 30460Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARENB) { 30470Sstevel@tonic-gate /* 30480Sstevel@tonic-gate * The PARITY_SPECIAL bit causes a special rx 30490Sstevel@tonic-gate * interrupt on parity errors. Turn it on if 30500Sstevel@tonic-gate * we're checking the parity of characters. 30510Sstevel@tonic-gate */ 30520Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & INPCK) 30530Sstevel@tonic-gate flags |= ZSP_PARITY_SPECIAL; 30540Sstevel@tonic-gate wr4 |= ZSWR4_PARITY_ENABLE; 30550Sstevel@tonic-gate if (!(za->za_ttycommon.t_cflag & PARODD)) 30560Sstevel@tonic-gate wr4 |= ZSWR4_PARITY_EVEN; 30570Sstevel@tonic-gate } 30580Sstevel@tonic-gate wr4 |= (za->za_ttycommon.t_cflag & CSTOPB) ? 30590Sstevel@tonic-gate ZSWR4_2_STOP : ZSWR4_1_STOP; 30600Sstevel@tonic-gate } 30610Sstevel@tonic-gate 30620Sstevel@tonic-gate #if 0 30630Sstevel@tonic-gate /* 30640Sstevel@tonic-gate * The AUTO_CD_CTS flag enables the hardware flow control feature of 30650Sstevel@tonic-gate * the 8530, which allows the state of CTS and DCD to control the 30660Sstevel@tonic-gate * enabling of the transmitter and receiver, respectively. The 30670Sstevel@tonic-gate * receiver and transmitter still must have their enable bits set in 30680Sstevel@tonic-gate * WR3 and WR5, respectively, for CTS and DCD to be monitored this way. 30690Sstevel@tonic-gate * Hardware flow control can thus be implemented with no help from 30700Sstevel@tonic-gate * software. 30710Sstevel@tonic-gate */ 30720Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) 30730Sstevel@tonic-gate wr3 |= ZSWR3_AUTO_CD_CTS; 30740Sstevel@tonic-gate #endif 30750Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) 30760Sstevel@tonic-gate wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD | ZSR15_CTS; 30770Sstevel@tonic-gate else 30780Sstevel@tonic-gate wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD; 30790Sstevel@tonic-gate 30800Sstevel@tonic-gate speed = zs->zs_wreg[12] + (zs->zs_wreg[13] << 8); 30810Sstevel@tonic-gate 30820Sstevel@tonic-gate /* 30830Sstevel@tonic-gate * Here we assemble a set of changes to be passed to zs_program. 30840Sstevel@tonic-gate * Note: Write Register 15 must be set to enable BREAK and UNDERrun 30850Sstevel@tonic-gate * interrupts. It must also enable CD interrupts which, although 30860Sstevel@tonic-gate * not processed by the hardware interrupt handler, will be processed 30870Sstevel@tonic-gate * by zsa_process, indirectly resulting in a SIGHUP being delivered 30880Sstevel@tonic-gate * to the controlling process if CD drops. CTS interrupts must NOT 30890Sstevel@tonic-gate * be enabled. We don't use them at all, and they will hang IPC/IPX 30900Sstevel@tonic-gate * systems at boot time if synchronous modems that supply transmit 30910Sstevel@tonic-gate * clock are attached to any of their serial ports. 30920Sstevel@tonic-gate */ 30930Sstevel@tonic-gate if (((zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) && 30940Sstevel@tonic-gate !(flags & ZSP_PARITY_SPECIAL)) || 30950Sstevel@tonic-gate (!(zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) && 30960Sstevel@tonic-gate (flags & ZSP_PARITY_SPECIAL)) || 30970Sstevel@tonic-gate wr3 != zs->zs_wreg[3] || wr4 != zs->zs_wreg[4] || 30980Sstevel@tonic-gate wr5 != zs->zs_wreg[5] || wr15 != zs->zs_wreg[15] || 30990Sstevel@tonic-gate speed != zs_speeds[baudrate]) { 31000Sstevel@tonic-gate 31010Sstevel@tonic-gate za->za_flags |= ZAS_DRAINING; 31020Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit]; 31030Sstevel@tonic-gate zspp->zs = zs; 31040Sstevel@tonic-gate zspp->flags = (uchar_t)flags; 31050Sstevel@tonic-gate zspp->wr4 = (uchar_t)wr4; 31060Sstevel@tonic-gate zspp->wr11 = (uchar_t)(ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD); 31070Sstevel@tonic-gate 31080Sstevel@tonic-gate speed = zs_speeds[baudrate]; 31090Sstevel@tonic-gate zspp->wr12 = (uchar_t)(speed & 0xff); 31100Sstevel@tonic-gate zspp->wr13 = (uchar_t)((speed >> 8) & 0xff); 31110Sstevel@tonic-gate zspp->wr3 = (uchar_t)wr3; 31120Sstevel@tonic-gate zspp->wr5 = (uchar_t)wr5; 31130Sstevel@tonic-gate zspp->wr15 = (uchar_t)wr15; 31140Sstevel@tonic-gate 31150Sstevel@tonic-gate zs_program(zspp); 31160Sstevel@tonic-gate za->za_flags &= ~ZAS_DRAINING; 31170Sstevel@tonic-gate } 31180Sstevel@tonic-gate } 31190Sstevel@tonic-gate 31200Sstevel@tonic-gate /* 31210Sstevel@tonic-gate * Get the current speed of the console and turn it into something 31220Sstevel@tonic-gate * UNIX knows about - used to preserve console speed when UNIX comes up. 31230Sstevel@tonic-gate */ 31240Sstevel@tonic-gate int 31250Sstevel@tonic-gate zsgetspeed(dev_t dev) 31260Sstevel@tonic-gate { 31270Sstevel@tonic-gate register struct zscom *zs; 31280Sstevel@tonic-gate register int uspeed, zspeed; 31290Sstevel@tonic-gate register uchar_t rr; 31300Sstevel@tonic-gate 31310Sstevel@tonic-gate zs = &zscom[UNIT(dev)]; 31320Sstevel@tonic-gate SCC_READ(12, zspeed); 31330Sstevel@tonic-gate SCC_READ(13, rr); 31340Sstevel@tonic-gate zspeed |= rr << 8; 31350Sstevel@tonic-gate for (uspeed = 0; uspeed < NSPEED; uspeed++) 31360Sstevel@tonic-gate if (zs_speeds[uspeed] == zspeed) 31370Sstevel@tonic-gate return (uspeed); 31380Sstevel@tonic-gate /* 31390Sstevel@tonic-gate * 9600 baud if we can't figure it out 31400Sstevel@tonic-gate */ 31410Sstevel@tonic-gate return (ISPEED); 31420Sstevel@tonic-gate } 31430Sstevel@tonic-gate 31440Sstevel@tonic-gate /* 31450Sstevel@tonic-gate * callback routine when enough memory is available. 31460Sstevel@tonic-gate */ 31470Sstevel@tonic-gate static void 31480Sstevel@tonic-gate zsa_callback(void *arg) 31490Sstevel@tonic-gate { 31500Sstevel@tonic-gate struct zscom *zs = arg; 31510Sstevel@tonic-gate struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 31520Sstevel@tonic-gate int allocbcount = zsa_rstandby; 31530Sstevel@tonic-gate 31540Sstevel@tonic-gate mutex_enter(zs->zs_excl); 31550Sstevel@tonic-gate if (za->za_bufcid) { 31560Sstevel@tonic-gate za->za_bufcid = 0; 31570Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount); 31580Sstevel@tonic-gate } 31590Sstevel@tonic-gate mutex_exit(zs->zs_excl); 31600Sstevel@tonic-gate } 31610Sstevel@tonic-gate 31620Sstevel@tonic-gate /* 31630Sstevel@tonic-gate * Set the receiver flags 31640Sstevel@tonic-gate */ 31650Sstevel@tonic-gate static void 31660Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(struct asyncline *za) 31670Sstevel@tonic-gate { 31680Sstevel@tonic-gate register uint_t mask; 31690Sstevel@tonic-gate 31700Sstevel@tonic-gate za->za_rcv_flags_mask &= ~0xFF; 31710Sstevel@tonic-gate switch (za->za_ttycommon.t_cflag & CSIZE) { 31720Sstevel@tonic-gate case CS5: 31730Sstevel@tonic-gate mask = 0x1f; 31740Sstevel@tonic-gate break; 31750Sstevel@tonic-gate case CS6: 31760Sstevel@tonic-gate mask = 0x3f; 31770Sstevel@tonic-gate break; 31780Sstevel@tonic-gate case CS7: 31790Sstevel@tonic-gate mask = 0x7f; 31800Sstevel@tonic-gate break; 31810Sstevel@tonic-gate default: 31820Sstevel@tonic-gate mask = 0xff; 31830Sstevel@tonic-gate } 31840Sstevel@tonic-gate 31850Sstevel@tonic-gate za->za_rcv_flags_mask &= ~(0xFF << 16); 31860Sstevel@tonic-gate za->za_rcv_flags_mask |= mask << 16; 31870Sstevel@tonic-gate 31880Sstevel@tonic-gate if ((za->za_ttycommon.t_iflag & PARMRK) && 31890Sstevel@tonic-gate !(za->za_ttycommon.t_iflag & (IGNPAR|ISTRIP))) { 31900Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_ESC; 31910Sstevel@tonic-gate } else 31920Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_ESC; 31930Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IXON) { 31940Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_STOPC; 31950Sstevel@tonic-gate za->za_rcv_flags_mask &= ~0xFF; 31960Sstevel@tonic-gate za->za_rcv_flags_mask |= za->za_ttycommon.t_stopc; 31970Sstevel@tonic-gate } else 31980Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_STOPC; 31990Sstevel@tonic-gate } 32000Sstevel@tonic-gate 32010Sstevel@tonic-gate static int 32020Sstevel@tonic-gate zsa_suspend(struct zscom *zs) 32030Sstevel@tonic-gate { 32040Sstevel@tonic-gate struct asyncline *za; 32050Sstevel@tonic-gate queue_t *q; 32060Sstevel@tonic-gate mblk_t *bp = NULL; 32070Sstevel@tonic-gate timeout_id_t restart_id, kick_rcv_id; 32080Sstevel@tonic-gate struct zs_prog *zspp; 32090Sstevel@tonic-gate 32100Sstevel@tonic-gate za = (struct asyncline *)&zs->zs_priv_str; 32110Sstevel@tonic-gate mutex_enter(zs->zs_excl); 32120Sstevel@tonic-gate if (zs->zs_suspended) { 32130Sstevel@tonic-gate mutex_exit(zs->zs_excl); 32140Sstevel@tonic-gate return (DDI_SUCCESS); 32150Sstevel@tonic-gate } 32160Sstevel@tonic-gate zs->zs_suspended = 1; 32170Sstevel@tonic-gate 32180Sstevel@tonic-gate /* 32190Sstevel@tonic-gate * Turn off interrupts and get any bytes in receiver 32200Sstevel@tonic-gate */ 32210Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 32220Sstevel@tonic-gate SCC_BIC(1, ZSWR1_INIT); 32230Sstevel@tonic-gate ZSA_KICK_RCV; 32240Sstevel@tonic-gate restart_id = za->za_zsa_restart_id; 32250Sstevel@tonic-gate za->za_zsa_restart_id = 0; 32260Sstevel@tonic-gate kick_rcv_id = za->za_kick_rcv_id; 32270Sstevel@tonic-gate za->za_kick_rcv_id = 0; 32280Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 32290Sstevel@tonic-gate mutex_exit(zs->zs_excl); 32300Sstevel@tonic-gate 32310Sstevel@tonic-gate /* 32320Sstevel@tonic-gate * Cancel any timeouts 32330Sstevel@tonic-gate */ 32340Sstevel@tonic-gate if (restart_id) 32350Sstevel@tonic-gate (void) untimeout(restart_id); 32360Sstevel@tonic-gate if (kick_rcv_id) 32370Sstevel@tonic-gate (void) untimeout(kick_rcv_id); 32380Sstevel@tonic-gate 32390Sstevel@tonic-gate /* 32400Sstevel@tonic-gate * Since we have turned off interrupts, zsa_txint will not be called 32410Sstevel@tonic-gate * and no new chars will given to the chip. We just wait for the 32420Sstevel@tonic-gate * current character(s) to drain. 32430Sstevel@tonic-gate */ 32440Sstevel@tonic-gate delay(ztdelay(za->za_ttycommon.t_cflag & CBAUD)); 32450Sstevel@tonic-gate 32460Sstevel@tonic-gate /* 32470Sstevel@tonic-gate * Return remains of partially sent message to queue 32480Sstevel@tonic-gate */ 32490Sstevel@tonic-gate mutex_enter(zs->zs_excl); 32500Sstevel@tonic-gate if ((q = za->za_ttycommon.t_writeq) != NULL) { 32510Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 32520Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) { 32530Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY; 32540Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT; 32550Sstevel@tonic-gate bp = za->za_xmitblk; 32560Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur; 32570Sstevel@tonic-gate zs->zs_wr_cur = NULL; 32580Sstevel@tonic-gate zs->zs_wr_lim = NULL; 32590Sstevel@tonic-gate za->za_xmitblk = NULL; 32600Sstevel@tonic-gate } 32610Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 32620Sstevel@tonic-gate if (bp) 32630Sstevel@tonic-gate (void) putbq(q, bp); 32640Sstevel@tonic-gate } 32650Sstevel@tonic-gate 32660Sstevel@tonic-gate /* 32670Sstevel@tonic-gate * Stop any breaks in progress. 32680Sstevel@tonic-gate */ 32690Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 32700Sstevel@tonic-gate if (zs->zs_wreg[5] & ZSWR5_BREAK) { 32710Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK); 32720Sstevel@tonic-gate za->za_flags &= ~ZAS_BREAK; 32730Sstevel@tonic-gate } 32740Sstevel@tonic-gate 32750Sstevel@tonic-gate /* 32760Sstevel@tonic-gate * Now get a copy of current registers setting. 32770Sstevel@tonic-gate */ 32780Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit]; 32790Sstevel@tonic-gate zspp->zs = zs; 32800Sstevel@tonic-gate zspp->flags = 0; 32810Sstevel@tonic-gate zspp->wr3 = zs->zs_wreg[3]; 32820Sstevel@tonic-gate zspp->wr4 = zs->zs_wreg[4]; 32830Sstevel@tonic-gate zspp->wr5 = zs->zs_wreg[5]; 32840Sstevel@tonic-gate zspp->wr11 = zs->zs_wreg[11]; 32850Sstevel@tonic-gate zspp->wr12 = zs->zs_wreg[12]; 32860Sstevel@tonic-gate zspp->wr13 = zs->zs_wreg[13]; 32870Sstevel@tonic-gate zspp->wr15 = zs->zs_wreg[15]; 32880Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 32890Sstevel@tonic-gate mutex_exit(zs->zs_excl); 32900Sstevel@tonic-gate /* 32910Sstevel@tonic-gate * We do this on the off chance that zsa_close is waiting on a timed 32920Sstevel@tonic-gate * break to complete and nothing else. 32930Sstevel@tonic-gate */ 32940Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv); 32950Sstevel@tonic-gate return (DDI_SUCCESS); 32960Sstevel@tonic-gate } 32970Sstevel@tonic-gate 32980Sstevel@tonic-gate static int 32990Sstevel@tonic-gate zsa_resume(struct zscom *zs) 33000Sstevel@tonic-gate { 33010Sstevel@tonic-gate register struct asyncline *za; 33020Sstevel@tonic-gate struct zs_prog *zspp; 33030Sstevel@tonic-gate 33040Sstevel@tonic-gate za = (struct asyncline *)&zs->zs_priv_str; 33050Sstevel@tonic-gate mutex_enter(zs->zs_excl); 33060Sstevel@tonic-gate if (!(zs->zs_suspended)) { 33070Sstevel@tonic-gate mutex_exit(zs->zs_excl); 33080Sstevel@tonic-gate return (DDI_SUCCESS); 33090Sstevel@tonic-gate } 33100Sstevel@tonic-gate 33110Sstevel@tonic-gate /* 33120Sstevel@tonic-gate * Restore H/W state 33130Sstevel@tonic-gate */ 33140Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 33150Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit]; 33160Sstevel@tonic-gate zs_program(zspp); 33170Sstevel@tonic-gate 33180Sstevel@tonic-gate /* 33190Sstevel@tonic-gate * Enable all interrupts for this chip and delay to let chip settle 33200Sstevel@tonic-gate */ 33210Sstevel@tonic-gate SCC_WRITE(9, ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT); 33220Sstevel@tonic-gate DELAY(4000); 33230Sstevel@tonic-gate 33240Sstevel@tonic-gate /* 33250Sstevel@tonic-gate * Restart receiving and transmitting 33260Sstevel@tonic-gate */ 33270Sstevel@tonic-gate zs->zs_suspended = 0; 33280Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT; 33290Sstevel@tonic-gate za->za_ext = 1; 33300Sstevel@tonic-gate ZSSETSOFT(zs); 33310Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 33320Sstevel@tonic-gate mutex_exit(zs->zs_excl); 33330Sstevel@tonic-gate 33340Sstevel@tonic-gate return (DDI_SUCCESS); 33350Sstevel@tonic-gate } 33360Sstevel@tonic-gate 33370Sstevel@tonic-gate #ifdef ZSA_DEBUG 33380Sstevel@tonic-gate static void 33390Sstevel@tonic-gate zsa_print_info(struct zscom *zs) 33400Sstevel@tonic-gate { 33410Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str; 33420Sstevel@tonic-gate register queue_t *q = za->za_ttycommon.t_writeq; 33430Sstevel@tonic-gate 33440Sstevel@tonic-gate printf(" next q=%s\n", (RD(q))->q_next->q_qinfo->qi_minfo->mi_idname); 33450Sstevel@tonic-gate printf("unit=%d\n", zs->zs_unit); 33460Sstevel@tonic-gate printf("tflag:\n"); 33470Sstevel@tonic-gate if (za->za_ttycommon.t_flags & TS_SOFTCAR) printf(" t_fl:TS_SOFTCAR"); 33480Sstevel@tonic-gate if (za->za_ttycommon.t_flags & TS_XCLUDE) printf(" t_fl:TS_XCLUDE"); 33490Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IGNBRK) printf(" t_ifl:IGNBRK"); 33500Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & BRKINT) printf(" t_ifl:BRKINT"); 33510Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IGNPAR) printf(" t_ifl:IGNPAR"); 33520Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & PARMRK) printf(" t_ifl:PARMRK"); 33530Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & INPCK) printf(" t_ifl:INPCK"); 33540Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & ISTRIP) printf(" t_ifl:ISTRIP"); 33550Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & INLCR) printf(" t_ifl:INLCR"); 33560Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IGNCR) printf(" t_ifl:IGNCR"); 33570Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & ICRNL) printf(" t_ifl:ICRNL"); 33580Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IUCLC) printf(" t_ifl:IUCLC"); 33590Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IXON) printf(" t_ifl:IXON"); 33600Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IXOFF) printf(" t_ifl:IXOFF"); 33610Sstevel@tonic-gate 33620Sstevel@tonic-gate printf("\n"); 33630Sstevel@tonic-gate 33640Sstevel@tonic-gate 33650Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS5) printf(" t_cfl:CS5"); 33660Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS6) printf(" t_cfl:CS6"); 33670Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS7) printf(" t_cfl:CS7"); 33680Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS8) printf(" t_cfl:CS8"); 33690Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSTOPB) printf(" t_cfl:CSTOPB"); 33700Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CREAD) printf(" t_cfl:CREAD"); 33710Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARENB) printf(" t_cfl:PARENB"); 33720Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARODD) printf(" t_cfl:PARODD"); 33730Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & HUPCL) printf(" t_cfl:HUPCL"); 33740Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CLOCAL) printf(" t_cfl:CLOCAL"); 33750Sstevel@tonic-gate printf(" t_stopc=%x", za->za_ttycommon.t_stopc); 33760Sstevel@tonic-gate printf("\n"); 33770Sstevel@tonic-gate } 33780Sstevel@tonic-gate #endif 33790Sstevel@tonic-gate 33800Sstevel@tonic-gate /* 33810Sstevel@tonic-gate * Check for abort character sequence 33820Sstevel@tonic-gate */ 33830Sstevel@tonic-gate static boolean_t 33840Sstevel@tonic-gate abort_charseq_recognize(uchar_t ch) 33850Sstevel@tonic-gate { 33860Sstevel@tonic-gate static int state = 0; 33870Sstevel@tonic-gate #define CNTRL(c) ((c)&037) 33880Sstevel@tonic-gate static char sequence[] = { '\r', '~', CNTRL('b') }; 33890Sstevel@tonic-gate 33900Sstevel@tonic-gate if (ch == sequence[state]) { 33910Sstevel@tonic-gate if (++state >= sizeof (sequence)) { 33920Sstevel@tonic-gate state = 0; 33930Sstevel@tonic-gate return (B_TRUE); 33940Sstevel@tonic-gate } 33950Sstevel@tonic-gate } else { 33960Sstevel@tonic-gate state = (ch == sequence[0]) ? 1 : 0; 33970Sstevel@tonic-gate } 33980Sstevel@tonic-gate return (B_FALSE); 33990Sstevel@tonic-gate } 3400