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