17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*d3d50737SRafael Vanoni * Common Development and Distribution License (the "License").
6*d3d50737SRafael Vanoni * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * Asynchronous protocol handler for Z8530 chips
287c478bd9Sstevel@tonic-gate * Handles normal UNIX support for terminals & modems
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
357c478bd9Sstevel@tonic-gate #include <sys/signal.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/termios.h>
387c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
397c478bd9Sstevel@tonic-gate #include <sys/stream.h>
407c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
417c478bd9Sstevel@tonic-gate #include <sys/tty.h>
427c478bd9Sstevel@tonic-gate #include <sys/ptyvar.h>
437c478bd9Sstevel@tonic-gate #include <sys/cred.h>
447c478bd9Sstevel@tonic-gate #include <sys/user.h>
457c478bd9Sstevel@tonic-gate #include <sys/proc.h>
467c478bd9Sstevel@tonic-gate #include <sys/file.h>
477c478bd9Sstevel@tonic-gate #include <sys/uio.h>
487c478bd9Sstevel@tonic-gate #include <sys/buf.h>
497c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
507c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
517c478bd9Sstevel@tonic-gate #include <sys/strtty.h>
527c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
537c478bd9Sstevel@tonic-gate #include <sys/zsdev.h>
547c478bd9Sstevel@tonic-gate #include <sys/ser_async.h>
557c478bd9Sstevel@tonic-gate #include <sys/debug.h>
567c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
577c478bd9Sstevel@tonic-gate #include <sys/conf.h>
587c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
597c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
607c478bd9Sstevel@tonic-gate #include <sys/promif.h>
617c478bd9Sstevel@tonic-gate #include <sys/policy.h>
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate * PPS (Pulse Per Second) support.
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gate extern void ddi_hardpps(struct timeval *, int);
677c478bd9Sstevel@tonic-gate static struct ppsclockev ppsclockev;
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate #ifdef PPSCLOCKLED
707c478bd9Sstevel@tonic-gate /* XXX Use these to observe PPS latencies and jitter on a scope */
717c478bd9Sstevel@tonic-gate #define LED_ON
727c478bd9Sstevel@tonic-gate #define LED_OFF
737c478bd9Sstevel@tonic-gate #else
747c478bd9Sstevel@tonic-gate #define LED_ON
757c478bd9Sstevel@tonic-gate #define LED_OFF
767c478bd9Sstevel@tonic-gate #endif
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate #define ZSA_RCV_SIZE 64
797c478bd9Sstevel@tonic-gate #define ZA_KICK_RCV_COUNT 3
807c478bd9Sstevel@tonic-gate #define ZSA_GRACE_MIN_FLOW_CONTROL 5
817c478bd9Sstevel@tonic-gate #define ZSA_GRACE_MAX_FLOW_CONTROL 20
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate int zsasoftdtr = 0; /* if nonzero, softcarrier raises dtr at attach */
847c478bd9Sstevel@tonic-gate int zsb134_weird = 0; /* if set, old weird B134 behavior */
857c478bd9Sstevel@tonic-gate int g_zsticks = 0; /* if set, becomes the global zsticks value */
867c478bd9Sstevel@tonic-gate int g_nocluster = 0; /* if set, disables clustering of received data */
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate unsigned int zsa_rstandby = ZSA_MIN_RSTANDBY;
897c478bd9Sstevel@tonic-gate unsigned int zsa_rdone = ZSA_RDONE_MIN;
907c478bd9Sstevel@tonic-gate unsigned int zsa_grace_flow_control = ZSA_GRACE_MIN_FLOW_CONTROL;
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate #define NSPEED 18 /* max # of speeds */
947c478bd9Sstevel@tonic-gate ushort_t zs_speeds[NSPEED] = {
957c478bd9Sstevel@tonic-gate 0,
967c478bd9Sstevel@tonic-gate ZSPEED(50), /* 1 */
977c478bd9Sstevel@tonic-gate ZSPEED(75), /* 2 */
987c478bd9Sstevel@tonic-gate ZSPEED(110), /* 3 */
997c478bd9Sstevel@tonic-gate #ifdef lint
1007c478bd9Sstevel@tonic-gate ZSPEED(134), /* 4 */
1017c478bd9Sstevel@tonic-gate #else
1027c478bd9Sstevel@tonic-gate ZSPEED(269/2), /* XXX - This is sleazy */
1037c478bd9Sstevel@tonic-gate #endif
1047c478bd9Sstevel@tonic-gate ZSPEED(150), /* 5 */
1057c478bd9Sstevel@tonic-gate ZSPEED(200), /* 6 */
1067c478bd9Sstevel@tonic-gate ZSPEED(300), /* 7 */
1077c478bd9Sstevel@tonic-gate ZSPEED(600), /* 8 */
1087c478bd9Sstevel@tonic-gate ZSPEED(1200), /* 9 */
1097c478bd9Sstevel@tonic-gate ZSPEED(1800), /* 10 */
1107c478bd9Sstevel@tonic-gate ZSPEED(2400), /* 11 */
1117c478bd9Sstevel@tonic-gate ZSPEED(4800), /* 12 */
1127c478bd9Sstevel@tonic-gate ZSPEED(9600), /* 13 */
1137c478bd9Sstevel@tonic-gate ZSPEED(19200), /* 14 */
1147c478bd9Sstevel@tonic-gate ZSPEED(38400), /* 15 */
1157c478bd9Sstevel@tonic-gate ZSPEED(57680), /* 16 */
1167c478bd9Sstevel@tonic-gate ZSPEED(76800) /* 17 */
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate ushort_t zsticks[NSPEED] = {
1207c478bd9Sstevel@tonic-gate 3, /* 0 */
1217c478bd9Sstevel@tonic-gate 3, /* 1 */
1227c478bd9Sstevel@tonic-gate 3, /* 2 */
1237c478bd9Sstevel@tonic-gate 3, /* 3 */
1247c478bd9Sstevel@tonic-gate 3, /* 4 */
1257c478bd9Sstevel@tonic-gate 3, /* 5 */
1267c478bd9Sstevel@tonic-gate 3, /* 6 */
1277c478bd9Sstevel@tonic-gate 3, /* 7 */
1287c478bd9Sstevel@tonic-gate 3, /* 8 */
1297c478bd9Sstevel@tonic-gate 3, /* 9 */
1307c478bd9Sstevel@tonic-gate 3, /* 10 */
1317c478bd9Sstevel@tonic-gate 3, /* 11 */
1327c478bd9Sstevel@tonic-gate 3, /* 12 */
1337c478bd9Sstevel@tonic-gate 3, /* 13 */
1347c478bd9Sstevel@tonic-gate 2, /* 14 */
1357c478bd9Sstevel@tonic-gate 1, /* 15 */
1367c478bd9Sstevel@tonic-gate 1, /* 16 */
1377c478bd9Sstevel@tonic-gate 1 /* 17 */
1387c478bd9Sstevel@tonic-gate };
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate #define ztdelay(nsp) (zsdelay[(nsp)]*(hz/100))
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate ushort_t zsdelay[NSPEED] = {
1437c478bd9Sstevel@tonic-gate 0,
1447c478bd9Sstevel@tonic-gate ZDELAY(50), /* 1 */
1457c478bd9Sstevel@tonic-gate ZDELAY(75), /* 2 */
1467c478bd9Sstevel@tonic-gate ZDELAY(110), /* 3 */
1477c478bd9Sstevel@tonic-gate #ifdef lint
1487c478bd9Sstevel@tonic-gate ZDELAY(134), /* 4 */
1497c478bd9Sstevel@tonic-gate #else
1507c478bd9Sstevel@tonic-gate ZDELAY(269/2),
1517c478bd9Sstevel@tonic-gate #endif
1527c478bd9Sstevel@tonic-gate ZDELAY(150), /* 5 */
1537c478bd9Sstevel@tonic-gate ZDELAY(200), /* 6 */
1547c478bd9Sstevel@tonic-gate ZDELAY(300), /* 7 */
1557c478bd9Sstevel@tonic-gate ZDELAY(600), /* 8 */
1567c478bd9Sstevel@tonic-gate ZDELAY(1200), /* 9 */
1577c478bd9Sstevel@tonic-gate ZDELAY(1800), /* 10 */
1587c478bd9Sstevel@tonic-gate ZDELAY(2400), /* 11 */
1597c478bd9Sstevel@tonic-gate ZDELAY(4800), /* 12 */
1607c478bd9Sstevel@tonic-gate ZDELAY(9600), /* 13 */
1617c478bd9Sstevel@tonic-gate ZDELAY(19200), /* 14 */
1627c478bd9Sstevel@tonic-gate ZDELAY(38400), /* 15 */
1637c478bd9Sstevel@tonic-gate ZDELAY(57600), /* 16 */
1647c478bd9Sstevel@tonic-gate ZDELAY(76800) /* 17 */
1657c478bd9Sstevel@tonic-gate };
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate ushort_t zslowat[NSPEED] = {
1687c478bd9Sstevel@tonic-gate 3, /* 0 */
1697c478bd9Sstevel@tonic-gate 3, /* 1 */
1707c478bd9Sstevel@tonic-gate 3, /* 2 */
1717c478bd9Sstevel@tonic-gate 3, /* 3 */
1727c478bd9Sstevel@tonic-gate 3, /* 4 */
1737c478bd9Sstevel@tonic-gate 3, /* 5 */
1747c478bd9Sstevel@tonic-gate 3, /* 6 */
1757c478bd9Sstevel@tonic-gate 2, /* 7 */
1767c478bd9Sstevel@tonic-gate 2, /* 8 */
1777c478bd9Sstevel@tonic-gate 2, /* 9 */
1787c478bd9Sstevel@tonic-gate 2, /* 10 */
1797c478bd9Sstevel@tonic-gate 1, /* 11 */
1807c478bd9Sstevel@tonic-gate 1, /* 12 */
1817c478bd9Sstevel@tonic-gate 1, /* 13 */
1827c478bd9Sstevel@tonic-gate 1, /* 14 */
1837c478bd9Sstevel@tonic-gate 1, /* 15 */
1847c478bd9Sstevel@tonic-gate 1, /* 16 */
1857c478bd9Sstevel@tonic-gate 1 /* 17 */
1867c478bd9Sstevel@tonic-gate };
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate ushort_t zshiwat[NSPEED] = {
1897c478bd9Sstevel@tonic-gate 0, /* 0 */
1907c478bd9Sstevel@tonic-gate 1, /* 1 */
1917c478bd9Sstevel@tonic-gate 1, /* 2 */
1927c478bd9Sstevel@tonic-gate 1, /* 3 */
1937c478bd9Sstevel@tonic-gate 1, /* 4 */
1947c478bd9Sstevel@tonic-gate 1, /* 5 */
1957c478bd9Sstevel@tonic-gate 1, /* 6 */
1967c478bd9Sstevel@tonic-gate 1, /* 7 */
1977c478bd9Sstevel@tonic-gate 1, /* 8 */
1987c478bd9Sstevel@tonic-gate 1, /* 9 */
1997c478bd9Sstevel@tonic-gate 1, /* 10 */
2007c478bd9Sstevel@tonic-gate 1, /* 11 */
2017c478bd9Sstevel@tonic-gate 1, /* 12 */
2027c478bd9Sstevel@tonic-gate 3, /* 13 */
2037c478bd9Sstevel@tonic-gate 3, /* 14 */
2047c478bd9Sstevel@tonic-gate 4, /* 15 */
2057c478bd9Sstevel@tonic-gate 4, /* 16 */
2067c478bd9Sstevel@tonic-gate 4 /* 17 */
2077c478bd9Sstevel@tonic-gate };
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate #define SLAVIO_BUG /* this workaround required to fix bug 1102778 */
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate #define SPEED(cflag) \
2127c478bd9Sstevel@tonic-gate ((cflag) & CBAUDEXT) ? \
2137c478bd9Sstevel@tonic-gate (((cflag) & 0x1) + CBAUD + 1) : ((cflag) & CBAUD)
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate * Special macros to handle STREAMS operations.
2177c478bd9Sstevel@tonic-gate * These are required to address memory leakage problems.
2187c478bd9Sstevel@tonic-gate * WARNING : the macro do NOT call ZSSETSOFT
2197c478bd9Sstevel@tonic-gate */
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /*
2227c478bd9Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex.
2237c478bd9Sstevel@tonic-gate */
2247c478bd9Sstevel@tonic-gate #define ZSA_GETBLOCK(zs, allocbcount) \
2257c478bd9Sstevel@tonic-gate { \
2267c478bd9Sstevel@tonic-gate register int n = zsa_rstandby; \
2277c478bd9Sstevel@tonic-gate while (--n >= 0 && allocbcount > 0) { \
2287c478bd9Sstevel@tonic-gate if (!za->za_rstandby[n]) { \
2297c478bd9Sstevel@tonic-gate if ((za->za_rstandby[n] = allocb(ZSA_RCV_SIZE, \
2307c478bd9Sstevel@tonic-gate BPRI_MED)) == NULL) { \
2317c478bd9Sstevel@tonic-gate if (za->za_bufcid == 0) { \
2327c478bd9Sstevel@tonic-gate za->za_bufcid = bufcall(ZSA_RCV_SIZE, \
2337c478bd9Sstevel@tonic-gate BPRI_MED, \
2347c478bd9Sstevel@tonic-gate zsa_callback, zs); \
2357c478bd9Sstevel@tonic-gate break; \
2367c478bd9Sstevel@tonic-gate } \
2377c478bd9Sstevel@tonic-gate } \
2387c478bd9Sstevel@tonic-gate allocbcount--; \
2397c478bd9Sstevel@tonic-gate } \
2407c478bd9Sstevel@tonic-gate } \
2417c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { \
2427c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); \
2437c478bd9Sstevel@tonic-gate if (!(zs->zs_wreg[5] & ZSWR5_RTS)) { \
2447c478bd9Sstevel@tonic-gate register int usedcnt = 0; \
2457c478bd9Sstevel@tonic-gate for (n = 0; n < zsa_rstandby; n++) \
2467c478bd9Sstevel@tonic-gate if (!za->za_rstandby[n]) \
2477c478bd9Sstevel@tonic-gate usedcnt++; \
2487c478bd9Sstevel@tonic-gate if ((ushort_t)usedcnt <= \
2497c478bd9Sstevel@tonic-gate zslowat[SPEED(za->za_ttycommon.t_cflag)]) \
2507c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_RTS); \
2517c478bd9Sstevel@tonic-gate } \
2527c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \
2537c478bd9Sstevel@tonic-gate } \
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex.
2587c478bd9Sstevel@tonic-gate */
2597c478bd9Sstevel@tonic-gate #define ZSA_ALLOCB(mp) \
2607c478bd9Sstevel@tonic-gate { \
2617c478bd9Sstevel@tonic-gate register int n = zsa_rstandby; \
2627c478bd9Sstevel@tonic-gate while (--n >= 0) { \
2637c478bd9Sstevel@tonic-gate if ((mp = za->za_rstandby[n]) != NULL) { \
2647c478bd9Sstevel@tonic-gate za->za_rstandby[n] = NULL; \
2657c478bd9Sstevel@tonic-gate break; \
2667c478bd9Sstevel@tonic-gate } \
2677c478bd9Sstevel@tonic-gate } \
2687c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSXOFF) { \
2697c478bd9Sstevel@tonic-gate if (!mp) { \
2707c478bd9Sstevel@tonic-gate if (zs->zs_wreg[5] & ZSWR5_RTS) \
2717c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS); \
2727c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d: message lost\n", \
2737c478bd9Sstevel@tonic-gate UNIT(za->za_dev)); \
2747c478bd9Sstevel@tonic-gate } else if (zs->zs_wreg[5] & ZSWR5_RTS) { \
2757c478bd9Sstevel@tonic-gate register int usedcnt = 0; \
2767c478bd9Sstevel@tonic-gate for (n = 0; n < zsa_rstandby; n++) \
2777c478bd9Sstevel@tonic-gate if (!za->za_rstandby[n]) \
2787c478bd9Sstevel@tonic-gate usedcnt++; \
2797c478bd9Sstevel@tonic-gate if ((ushort_t)usedcnt >= (zsa_rstandby - \
2807c478bd9Sstevel@tonic-gate zshiwat[SPEED(za->za_ttycommon.t_cflag)])) \
2817c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_RTS); \
2827c478bd9Sstevel@tonic-gate } \
2837c478bd9Sstevel@tonic-gate } \
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate * Should get the spin (zs_excl_hi) mutex.
2887c478bd9Sstevel@tonic-gate */
2897c478bd9Sstevel@tonic-gate #define ZSA_QREPLY(q, mp) \
2907c478bd9Sstevel@tonic-gate { \
2917c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); \
2927c478bd9Sstevel@tonic-gate ZSA_PUTQ(mp); \
2937c478bd9Sstevel@tonic-gate ZSSETSOFT(zs); \
2947c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); \
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex.
2997c478bd9Sstevel@tonic-gate */
3007c478bd9Sstevel@tonic-gate #define ZSA_PUTQ(mp) \
3017c478bd9Sstevel@tonic-gate { \
3027c478bd9Sstevel@tonic-gate register int wptr, rptr; \
3037c478bd9Sstevel@tonic-gate wptr = za->za_rdone_wptr; \
3047c478bd9Sstevel@tonic-gate rptr = za->za_rdone_rptr; \
3057c478bd9Sstevel@tonic-gate za->za_rdone[wptr] = mp; \
3067c478bd9Sstevel@tonic-gate if ((wptr)+1 == zsa_rdone) { \
3077c478bd9Sstevel@tonic-gate za->za_rdone_wptr = wptr = 0; \
3087c478bd9Sstevel@tonic-gate } else \
3097c478bd9Sstevel@tonic-gate za->za_rdone_wptr = ++wptr; \
3107c478bd9Sstevel@tonic-gate if (wptr == rptr) { \
3117c478bd9Sstevel@tonic-gate SCC_BIC(1, ZSWR1_INIT); \
3127c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d disabled: input buffer overflow", \
3137c478bd9Sstevel@tonic-gate UNIT(za->za_dev)); \
3147c478bd9Sstevel@tonic-gate } \
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate * Should be called holding the spin (zs_excl_hi) mutex.
3197c478bd9Sstevel@tonic-gate */
3207c478bd9Sstevel@tonic-gate #define ZSA_KICK_RCV \
3217c478bd9Sstevel@tonic-gate { \
3227c478bd9Sstevel@tonic-gate register mblk_t *mp = za->za_rcvblk; \
3237c478bd9Sstevel@tonic-gate if (mp) { \
3247c478bd9Sstevel@tonic-gate if (zs->zs_rd_cur) { /* M_DATA */ \
3257c478bd9Sstevel@tonic-gate mp->b_wptr = zs->zs_rd_cur; \
3267c478bd9Sstevel@tonic-gate zs->zs_rd_cur = NULL; \
3277c478bd9Sstevel@tonic-gate zs->zs_rd_lim = NULL; \
3287c478bd9Sstevel@tonic-gate } \
3297c478bd9Sstevel@tonic-gate za->za_rcvblk = NULL; \
3307c478bd9Sstevel@tonic-gate ZSA_PUTQ(mp); \
3317c478bd9Sstevel@tonic-gate ZSSETSOFT(zs); \
3327c478bd9Sstevel@tonic-gate } \
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate #define ZSA_SEEQ(mp) \
3367c478bd9Sstevel@tonic-gate { \
3377c478bd9Sstevel@tonic-gate if (za->za_rdone_rptr != za->za_rdone_wptr) { \
3387c478bd9Sstevel@tonic-gate mp = za->za_rdone[za->za_rdone_rptr]; \
3397c478bd9Sstevel@tonic-gate } else { \
3407c478bd9Sstevel@tonic-gate mp = NULL; \
3417c478bd9Sstevel@tonic-gate } \
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex.
3477c478bd9Sstevel@tonic-gate */
3487c478bd9Sstevel@tonic-gate #define ZSA_GETQ(mp) \
3497c478bd9Sstevel@tonic-gate { \
3507c478bd9Sstevel@tonic-gate if (za->za_rdone_rptr != za->za_rdone_wptr) { \
3517c478bd9Sstevel@tonic-gate mp = za->za_rdone[za->za_rdone_rptr]; \
3527c478bd9Sstevel@tonic-gate za->za_rdone[za->za_rdone_rptr++] = NULL; \
3537c478bd9Sstevel@tonic-gate if (za->za_rdone_rptr == zsa_rdone) \
3547c478bd9Sstevel@tonic-gate za->za_rdone_rptr = 0; \
3557c478bd9Sstevel@tonic-gate } else { \
3567c478bd9Sstevel@tonic-gate mp = NULL; \
3577c478bd9Sstevel@tonic-gate } \
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate * Should be called holding only the adaptive (zs_excl) mutex.
3627c478bd9Sstevel@tonic-gate */
3637c478bd9Sstevel@tonic-gate #define ZSA_FLUSHQ \
3647c478bd9Sstevel@tonic-gate { \
3657c478bd9Sstevel@tonic-gate register mblk_t *tmp; \
3667c478bd9Sstevel@tonic-gate for (;;) { \
3677c478bd9Sstevel@tonic-gate ZSA_GETQ(tmp); \
3687c478bd9Sstevel@tonic-gate if (!(tmp)) \
3697c478bd9Sstevel@tonic-gate break; \
3707c478bd9Sstevel@tonic-gate freemsg(tmp); \
3717c478bd9Sstevel@tonic-gate } \
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate * Logging definitions
3777c478bd9Sstevel@tonic-gate */
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate #ifdef ZS_DEBUG_ALL
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate extern char zs_h_log[];
3847c478bd9Sstevel@tonic-gate extern int zs_h_log_n;
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate #define zsa_h_log_clear
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate #define zsa_h_log_add(c) \
3897c478bd9Sstevel@tonic-gate { \
3907c478bd9Sstevel@tonic-gate if (zs_h_log_n >= ZS_H_LOG_MAX) \
3917c478bd9Sstevel@tonic-gate zs_h_log_n = 0; \
3927c478bd9Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = 'A' + zs->zs_unit; \
3937c478bd9Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = c; \
3947c478bd9Sstevel@tonic-gate zs_h_log[zs_h_log_n] = '\0'; \
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate #else /* ZS_DEBUG_ALL */
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate #define ZSA_H_LOG_MAX 0x4000
4007c478bd9Sstevel@tonic-gate char zsa_h_log[40][ZSA_H_LOG_MAX +10];
4017c478bd9Sstevel@tonic-gate int zsa_h_log_n[40];
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate #define zsa_h_log_add(c) \
4047c478bd9Sstevel@tonic-gate { \
4057c478bd9Sstevel@tonic-gate if (zsa_h_log_n[zs->zs_unit] >= ZSA_H_LOG_MAX) \
4067c478bd9Sstevel@tonic-gate zsa_h_log_n[zs->zs_unit] = 0; \
4077c478bd9Sstevel@tonic-gate zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]++] = c; \
4087c478bd9Sstevel@tonic-gate zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]] = '\0'; \
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate #define zsa_h_log_clear \
4127c478bd9Sstevel@tonic-gate { \
4137c478bd9Sstevel@tonic-gate register char *p; \
4147c478bd9Sstevel@tonic-gate for (p = &zsa_h_log[zs->zs_unit][ZSA_H_LOG_MAX]; \
4157c478bd9Sstevel@tonic-gate p >= &zsa_h_log[zs->zs_unit][0]; /* null */) \
4167c478bd9Sstevel@tonic-gate *p-- = '\0'; \
4177c478bd9Sstevel@tonic-gate zsa_h_log_n[zs->zs_unit] = 0; \
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate #endif /* ZS_DEBUG_ALL */
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate #define ZSA_R0_LOG(r0) \
4237c478bd9Sstevel@tonic-gate { \
4247c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_RX_READY) zsa_h_log_add('R'); \
4257c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_TIMER) zsa_h_log_add('Z'); \
4267c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_TX_READY) zsa_h_log_add('T'); \
4277c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_CD) zsa_h_log_add('D'); \
4287c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_SYNC) zsa_h_log_add('S'); \
4297c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_CTS) zsa_h_log_add('C'); \
4307c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_TXUNDER) zsa_h_log_add('U'); \
4317c478bd9Sstevel@tonic-gate if (r0 & ZSRR0_BREAK) zsa_h_log_add('B'); \
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate #else /* ZSA_DEBUG */
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate #define zsa_h_log_clear
4377c478bd9Sstevel@tonic-gate #define zsa_h_log_add(c)
4387c478bd9Sstevel@tonic-gate #define ZSA_R0_LOG(r0)
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate #endif /* ZSA_DEBUG */
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate static int zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
4457c478bd9Sstevel@tonic-gate static int zsa_close(queue_t *q, int flag);
4467c478bd9Sstevel@tonic-gate static void zsa_wput(queue_t *q, mblk_t *mp);
4477c478bd9Sstevel@tonic-gate static void zsa_rsrv(queue_t *q);
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate static struct module_info asyncm_info = {
4507c478bd9Sstevel@tonic-gate 0,
4517c478bd9Sstevel@tonic-gate "zs",
4527c478bd9Sstevel@tonic-gate 0,
4537c478bd9Sstevel@tonic-gate INFPSZ,
4547c478bd9Sstevel@tonic-gate 2048,
4557c478bd9Sstevel@tonic-gate 128
4567c478bd9Sstevel@tonic-gate };
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate static struct qinit async_rinit = {
4597c478bd9Sstevel@tonic-gate putq,
4607c478bd9Sstevel@tonic-gate (int (*)())zsa_rsrv,
4617c478bd9Sstevel@tonic-gate zsa_open,
4627c478bd9Sstevel@tonic-gate zsa_close,
4637c478bd9Sstevel@tonic-gate NULL,
4647c478bd9Sstevel@tonic-gate &asyncm_info,
4657c478bd9Sstevel@tonic-gate NULL
4667c478bd9Sstevel@tonic-gate };
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate static struct qinit async_winit = {
4697c478bd9Sstevel@tonic-gate (int (*)())zsa_wput,
4707c478bd9Sstevel@tonic-gate NULL,
4717c478bd9Sstevel@tonic-gate NULL,
4727c478bd9Sstevel@tonic-gate NULL,
4737c478bd9Sstevel@tonic-gate NULL,
4747c478bd9Sstevel@tonic-gate &asyncm_info,
4757c478bd9Sstevel@tonic-gate NULL
4767c478bd9Sstevel@tonic-gate };
4777c478bd9Sstevel@tonic-gate
4787c478bd9Sstevel@tonic-gate struct streamtab asynctab = {
4797c478bd9Sstevel@tonic-gate &async_rinit,
4807c478bd9Sstevel@tonic-gate &async_winit,
4817c478bd9Sstevel@tonic-gate NULL,
4827c478bd9Sstevel@tonic-gate NULL,
4837c478bd9Sstevel@tonic-gate };
4847c478bd9Sstevel@tonic-gate
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate * The async interrupt entry points.
4877c478bd9Sstevel@tonic-gate */
4887c478bd9Sstevel@tonic-gate static void zsa_txint(struct zscom *zs);
4897c478bd9Sstevel@tonic-gate static void zsa_xsint(struct zscom *zs);
4907c478bd9Sstevel@tonic-gate static void zsa_rxint(struct zscom *zs);
4917c478bd9Sstevel@tonic-gate static void zsa_srint(struct zscom *zs);
4927c478bd9Sstevel@tonic-gate static int zsa_softint(struct zscom *zs);
4937c478bd9Sstevel@tonic-gate static int zsa_suspend(struct zscom *zs);
4947c478bd9Sstevel@tonic-gate static int zsa_resume(struct zscom *zs);
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate static void
zsa_null(struct zscom * zs)4977c478bd9Sstevel@tonic-gate zsa_null(struct zscom *zs)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate /* LINTED */
5007c478bd9Sstevel@tonic-gate register short c;
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
5037c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS);
5047c478bd9Sstevel@tonic-gate c = SCC_READDATA();
5057c478bd9Sstevel@tonic-gate ZSDELAY();
5067c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5107c478bd9Sstevel@tonic-gate static int
zsa_null_int(struct zscom * zs)5117c478bd9Sstevel@tonic-gate zsa_null_int(struct zscom *zs)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate return (0);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate struct zsops zsops_null_async = {
5177c478bd9Sstevel@tonic-gate zsa_null,
5187c478bd9Sstevel@tonic-gate zsa_null,
5197c478bd9Sstevel@tonic-gate zsa_null,
5207c478bd9Sstevel@tonic-gate zsa_null,
5217c478bd9Sstevel@tonic-gate zsa_null_int,
5227c478bd9Sstevel@tonic-gate zsa_null_int,
5237c478bd9Sstevel@tonic-gate zsa_null_int
5247c478bd9Sstevel@tonic-gate };
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate struct zsops zsops_async = {
5277c478bd9Sstevel@tonic-gate zsa_txint,
5287c478bd9Sstevel@tonic-gate zsa_xsint,
5297c478bd9Sstevel@tonic-gate zsa_rxint,
5307c478bd9Sstevel@tonic-gate zsa_srint,
5317c478bd9Sstevel@tonic-gate zsa_softint,
5327c478bd9Sstevel@tonic-gate zsa_suspend,
5337c478bd9Sstevel@tonic-gate zsa_resume
5347c478bd9Sstevel@tonic-gate };
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate static int dmtozs(int bits);
5377c478bd9Sstevel@tonic-gate static int zstodm(int bits);
5387c478bd9Sstevel@tonic-gate static void zsa_restart(void *);
5397c478bd9Sstevel@tonic-gate static void zsa_reioctl(void *);
5407c478bd9Sstevel@tonic-gate static void zsa_ioctl(struct asyncline *za, queue_t *q, mblk_t *mp);
5417c478bd9Sstevel@tonic-gate static void zsa_program(struct asyncline *za, int setibaud);
5427c478bd9Sstevel@tonic-gate static void zsa_start(struct zscom *zs);
5437c478bd9Sstevel@tonic-gate static void zsa_kick_rcv(void *);
5447c478bd9Sstevel@tonic-gate static void zsa_callback(void *);
5457c478bd9Sstevel@tonic-gate static void zsa_set_za_rcv_flags_mask(struct asyncline *za);
5467c478bd9Sstevel@tonic-gate int zsgetspeed(dev_t dev);
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate static boolean_t abort_charseq_recognize(uchar_t ch);
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /* ARGSUSED */
5517c478bd9Sstevel@tonic-gate int
zsc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5527c478bd9Sstevel@tonic-gate zsc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
5537c478bd9Sstevel@tonic-gate void **result)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate register dev_t dev = (dev_t)arg;
5567c478bd9Sstevel@tonic-gate register int unit, error;
5577c478bd9Sstevel@tonic-gate register struct zscom *zs;
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate if ((unit = UNIT(dev)) >= nzs)
5607c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate switch (infocmd) {
5637c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
5647c478bd9Sstevel@tonic-gate zs = &zscom[unit];
5657c478bd9Sstevel@tonic-gate *result = zs->zs_dip;
5667c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
5677c478bd9Sstevel@tonic-gate break;
5687c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
569360e6f5eSmathue *result = (void *)(uintptr_t)(unit / 2);
5707c478bd9Sstevel@tonic-gate error = DDI_SUCCESS;
5717c478bd9Sstevel@tonic-gate break;
5727c478bd9Sstevel@tonic-gate default:
5737c478bd9Sstevel@tonic-gate error = DDI_FAILURE;
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate return (error);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate * The Asynchronous Driver.
5807c478bd9Sstevel@tonic-gate */
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate /*
5837c478bd9Sstevel@tonic-gate * Determine if the zsminor device is in use as either a stdin or stdout
5847c478bd9Sstevel@tonic-gate * device, so we can be careful about how we initialize the DUART, if
5857c478bd9Sstevel@tonic-gate * it is, in fact, in use.
5867c478bd9Sstevel@tonic-gate *
5877c478bd9Sstevel@tonic-gate * Since this is expensive, we do it once and store away the answers,
5887c478bd9Sstevel@tonic-gate * since this gets called a number of times per phyical zs device.
5897c478bd9Sstevel@tonic-gate * Perhaps, this should be in a loadable module, so it can get thrown
5907c478bd9Sstevel@tonic-gate * away after all the zs devices are attached?
5917c478bd9Sstevel@tonic-gate */
5927c478bd9Sstevel@tonic-gate
5937c478bd9Sstevel@tonic-gate /*
5947c478bd9Sstevel@tonic-gate * To determine if a given unit is being used by the PROM,
5957c478bd9Sstevel@tonic-gate * we need to map stdin/stdout devices as known to the PROM
5967c478bd9Sstevel@tonic-gate * to zs internal minor device numbers:
5977c478bd9Sstevel@tonic-gate *
5987c478bd9Sstevel@tonic-gate * PROM (real device) zs minor device
5997c478bd9Sstevel@tonic-gate *
6007c478bd9Sstevel@tonic-gate * "zs", 0, "a" 0 ttya
6017c478bd9Sstevel@tonic-gate * "zs", 0, "b" 1 ttyb
6027c478bd9Sstevel@tonic-gate * "zs", 1, "a" 2 keyboard
6037c478bd9Sstevel@tonic-gate * "zs", 1, "b" 3 mouse
6047c478bd9Sstevel@tonic-gate * "zs", 2, "a" 4 ttyc
6057c478bd9Sstevel@tonic-gate * "zs", 2, "b" 5 ttyd
6067c478bd9Sstevel@tonic-gate *
6077c478bd9Sstevel@tonic-gate * The following value mapping lines assume that insource
6087c478bd9Sstevel@tonic-gate * and outsink map as "screen, a, b, c, d, ...", and that
6097c478bd9Sstevel@tonic-gate * zs minors are "a, b, kbd, mouse, c, d, ...".
6107c478bd9Sstevel@tonic-gate */
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate static int zsa_inuse; /* Strictly for debugging */
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate int
zsa_channel_is_active_in_rom(dev_info_t * dev,int zsminor)6157c478bd9Sstevel@tonic-gate zsa_channel_is_active_in_rom(dev_info_t *dev, int zsminor)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate char pathname[OBP_MAXPATHLEN];
6187c478bd9Sstevel@tonic-gate char default_pathname[OBP_MAXPATHLEN];
6197c478bd9Sstevel@tonic-gate char *stdioname;
6207c478bd9Sstevel@tonic-gate char minordata[3];
6217c478bd9Sstevel@tonic-gate
6227c478bd9Sstevel@tonic-gate /*
6237c478bd9Sstevel@tonic-gate * Basically, get my name and compare it to stdio devnames
6247c478bd9Sstevel@tonic-gate * and if we get a match, then the device is in use as either
6257c478bd9Sstevel@tonic-gate * stdin or stdout device (console tip line or keyboard device).
6267c478bd9Sstevel@tonic-gate *
6277c478bd9Sstevel@tonic-gate * We get two forms of the pathname, one complete with the
6287c478bd9Sstevel@tonic-gate * the channel number, and if the channel is 'a', then
6297c478bd9Sstevel@tonic-gate * we also deal with the user's ability to default to
6307c478bd9Sstevel@tonic-gate * channel 'a', by omitting the channel number option.
6317c478bd9Sstevel@tonic-gate * We then compare these pathnames to both the stdin and
6327c478bd9Sstevel@tonic-gate * stdout pathnames. If any of these match, then the channel
6337c478bd9Sstevel@tonic-gate * is in use.
6347c478bd9Sstevel@tonic-gate */
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate (void) ddi_pathname(dev, pathname); /* device pathname */
6377c478bd9Sstevel@tonic-gate default_pathname[0] = (char)0; /* default pathname if channel 'a' */
6387c478bd9Sstevel@tonic-gate if ((zsminor & 1) == 0)
6397c478bd9Sstevel@tonic-gate (void) strcpy(default_pathname, pathname);
6407c478bd9Sstevel@tonic-gate minordata[0] = ':';
6417c478bd9Sstevel@tonic-gate minordata[1] = (char)('a' + (zsminor & 1));
6427c478bd9Sstevel@tonic-gate minordata[2] = (char)0;
6437c478bd9Sstevel@tonic-gate (void) strcat(pathname, minordata);
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate stdioname = prom_stdinpath();
6467c478bd9Sstevel@tonic-gate if (strcmp(pathname, stdioname) == 0) {
6477c478bd9Sstevel@tonic-gate zsa_inuse |= (1 << zsminor);
6487c478bd9Sstevel@tonic-gate return (1);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate if (strcmp(default_pathname, stdioname) == 0) {
6517c478bd9Sstevel@tonic-gate zsa_inuse |= (1 << zsminor);
6527c478bd9Sstevel@tonic-gate return (1);
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate stdioname = prom_stdoutpath();
6567c478bd9Sstevel@tonic-gate if (strcmp(pathname, stdioname) == 0) {
6577c478bd9Sstevel@tonic-gate zsa_inuse |= (1 << zsminor);
6587c478bd9Sstevel@tonic-gate return (1);
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate if (strcmp(default_pathname, stdioname) == 0) {
6617c478bd9Sstevel@tonic-gate zsa_inuse |= (1 << zsminor);
6627c478bd9Sstevel@tonic-gate return (1);
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate return (0);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate /*
6697c478bd9Sstevel@tonic-gate * Initialize zs
6707c478bd9Sstevel@tonic-gate */
6717c478bd9Sstevel@tonic-gate void
zsa_init(struct zscom * zs)6727c478bd9Sstevel@tonic-gate zsa_init(struct zscom *zs)
6737c478bd9Sstevel@tonic-gate {
6747c478bd9Sstevel@tonic-gate /*
6757c478bd9Sstevel@tonic-gate * This routine is called near the end of the zs module's attach
6767c478bd9Sstevel@tonic-gate * process. It initializes the TTY protocol-private data for this
6777c478bd9Sstevel@tonic-gate * channel that needs to be in place before interrupts are enabled.
6787c478bd9Sstevel@tonic-gate */
6797c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
6807c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate /*
6837c478bd9Sstevel@tonic-gate * Raise modem control lines on serial ports associated
6847c478bd9Sstevel@tonic-gate * with the console and (optionally) softcarrier lines.
6857c478bd9Sstevel@tonic-gate * Drop modem control lines on all others so that modems
6867c478bd9Sstevel@tonic-gate * will not answer and portselectors will skip these
6877c478bd9Sstevel@tonic-gate * lines until they are opened by a getty.
6887c478bd9Sstevel@tonic-gate */
6897c478bd9Sstevel@tonic-gate if (zsa_channel_is_active_in_rom(zs->zs_dip, zs->zs_unit))
6907c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); /* raise dtr */
6917c478bd9Sstevel@tonic-gate else if (zsasoftdtr && (zssoftCAR[zs->zs_unit]))
6927c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET); /* raise dtr */
6937c478bd9Sstevel@tonic-gate else
6947c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZS_OFF, DMSET); /* drop dtr */
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate if (zsa_rstandby > ZSA_MAX_RSTANDBY)
6977c478bd9Sstevel@tonic-gate zsa_rstandby = ZSA_MAX_RSTANDBY;
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate if (zsa_rdone > ZSA_RDONE_MAX)
7007c478bd9Sstevel@tonic-gate zsa_rdone = ZSA_RDONE_MAX;
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate if (zsa_grace_flow_control > ZSA_GRACE_MAX_FLOW_CONTROL)
7037c478bd9Sstevel@tonic-gate zsa_grace_flow_control = ZSA_GRACE_MAX_FLOW_CONTROL;
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7067c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate * Open routine.
7127c478bd9Sstevel@tonic-gate */
7137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7147c478bd9Sstevel@tonic-gate static int
zsa_open(queue_t * rq,dev_t * dev,int flag,int sflag,cred_t * cr)7157c478bd9Sstevel@tonic-gate zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
7167c478bd9Sstevel@tonic-gate {
7177c478bd9Sstevel@tonic-gate register struct zscom *zs;
7187c478bd9Sstevel@tonic-gate register struct asyncline *za;
7197c478bd9Sstevel@tonic-gate register int speed, unit;
7207c478bd9Sstevel@tonic-gate struct termios *termiosp;
7217c478bd9Sstevel@tonic-gate int len;
7227c478bd9Sstevel@tonic-gate register int allocbcount = zsa_rstandby;
7237c478bd9Sstevel@tonic-gate boolean_t set_zsoptinit = B_FALSE;
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate unit = UNIT(*dev);
7267c478bd9Sstevel@tonic-gate if (unit >= nzs)
7277c478bd9Sstevel@tonic-gate return (ENXIO); /* unit not configured */
7287c478bd9Sstevel@tonic-gate
7297c478bd9Sstevel@tonic-gate /* zscom is allocated by zsattach, and thus cannot be NULL here */
7307c478bd9Sstevel@tonic-gate zs = &zscom[unit];
7317c478bd9Sstevel@tonic-gate if (zs->zs_ops == NULL) {
7327c478bd9Sstevel@tonic-gate return (ENXIO); /* device not found by autoconfig */
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_ocexcl);
7367c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
7377c478bd9Sstevel@tonic-gate again:
7387c478bd9Sstevel@tonic-gate if ((zs->zs_ops != &zsops_null) &&
7397c478bd9Sstevel@tonic-gate (zs->zs_ops != &zsops_async)) {
7407c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
7417c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl);
7427c478bd9Sstevel@tonic-gate return (EBUSY); /* another protocol got here first */
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate za = (struct asyncline *)&zs->zs_priv_str;
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate if (zs->zs_suspended) {
7487c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
7497c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl);
7507c478bd9Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
7517c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_ocexcl);
7527c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate /* Mark device as busy (for power management) */
7567c478bd9Sstevel@tonic-gate (void) pm_busy_component(zs->zs_dip, unit%2+1);
7577c478bd9Sstevel@tonic-gate
7587c478bd9Sstevel@tonic-gate if (zs->zs_ops == &zsops_null) {
7597c478bd9Sstevel@tonic-gate bzero(za, sizeof (zs->zs_priv_str));
7607c478bd9Sstevel@tonic-gate za->za_common = zs;
7617c478bd9Sstevel@tonic-gate if (zssoftCAR[zs->zs_unit])
7627c478bd9Sstevel@tonic-gate za->za_ttycommon.t_flags |= TS_SOFTCAR;
7637c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_async);
7647c478bd9Sstevel@tonic-gate set_zsoptinit = B_TRUE;
7657c478bd9Sstevel@tonic-gate za->za_rdone_wptr = 0;
7667c478bd9Sstevel@tonic-gate za->za_rdone_rptr = 0;
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate zs->zs_priv = (caddr_t)za;
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate * Block waiting for carrier to come up,
7737c478bd9Sstevel@tonic-gate * unless this is a no-delay open.
7747c478bd9Sstevel@tonic-gate */
7757c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7767c478bd9Sstevel@tonic-gate if (!(za->za_flags & ZAS_ISOPEN)) {
7777c478bd9Sstevel@tonic-gate /*
7787c478bd9Sstevel@tonic-gate * Get the default termios settings (cflag).
7797c478bd9Sstevel@tonic-gate * These are stored as a property in the
7807c478bd9Sstevel@tonic-gate * "options" node.
7817c478bd9Sstevel@tonic-gate */
7827c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
7837c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY,
7847c478bd9Sstevel@tonic-gate ddi_root_node(), 0, "ttymodes",
7857c478bd9Sstevel@tonic-gate (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
7867c478bd9Sstevel@tonic-gate len == sizeof (struct termios)) {
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag = termiosp->c_cflag;
7897c478bd9Sstevel@tonic-gate kmem_free(termiosp, len);
7907c478bd9Sstevel@tonic-gate } else {
7917c478bd9Sstevel@tonic-gate /*
7927c478bd9Sstevel@tonic-gate * Gack! Whine about it.
7937c478bd9Sstevel@tonic-gate */
7947c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
7957c478bd9Sstevel@tonic-gate "zs: Couldn't get ttymodes property!");
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
7987c478bd9Sstevel@tonic-gate if ((*dev == rconsdev) || (*dev == kbddev) ||
7997c478bd9Sstevel@tonic-gate (*dev == stdindev)) {
8007c478bd9Sstevel@tonic-gate speed = zsgetspeed(*dev);
8017c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~(CBAUD);
8027c478bd9Sstevel@tonic-gate if (speed > CBAUD) {
8037c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag |= CBAUDEXT;
8047c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag |=
8057c478bd9Sstevel@tonic-gate ((speed - CBAUD - 1) & CBAUD);
8067c478bd9Sstevel@tonic-gate } else {
8077c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~CBAUDEXT;
8087c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag |= (speed & CBAUD);
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate za->za_overrun = 0;
8127c478bd9Sstevel@tonic-gate za->za_ttycommon.t_iflag = 0;
8137c478bd9Sstevel@tonic-gate za->za_ttycommon.t_iocpending = NULL;
8147c478bd9Sstevel@tonic-gate za->za_ttycommon.t_size.ws_row = 0;
8157c478bd9Sstevel@tonic-gate za->za_ttycommon.t_size.ws_col = 0;
8167c478bd9Sstevel@tonic-gate za->za_ttycommon.t_size.ws_xpixel = 0;
8177c478bd9Sstevel@tonic-gate za->za_ttycommon.t_size.ws_ypixel = 0;
8187c478bd9Sstevel@tonic-gate za->za_dev = *dev;
8197c478bd9Sstevel@tonic-gate za->za_wbufcid = 0;
8207c478bd9Sstevel@tonic-gate zsa_program(za, za->za_ttycommon.t_cflag & (CIBAUDEXT|CIBAUD));
8217c478bd9Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(za);
8227c478bd9Sstevel@tonic-gate } else if ((za->za_ttycommon.t_flags & TS_XCLUDE) &&
8237c478bd9Sstevel@tonic-gate secpolicy_excl_open(cr) != 0) {
8247c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
8257c478bd9Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN))
8267c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_null);
8277c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
8287c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl);
8297c478bd9Sstevel@tonic-gate return (EBUSY);
8307c478bd9Sstevel@tonic-gate } else if ((*dev & OUTLINE) && !(za->za_flags & ZAS_OUT)) {
8317c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
8327c478bd9Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN))
8337c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_null);
8347c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
8357c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl);
8367c478bd9Sstevel@tonic-gate return (EBUSY);
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate
8397c478bd9Sstevel@tonic-gate if (*dev & OUTLINE)
8407c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_OUT;
8417c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET);
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate /*
8447c478bd9Sstevel@tonic-gate * Check carrier.
8457c478bd9Sstevel@tonic-gate */
8467c478bd9Sstevel@tonic-gate if ((za->za_ttycommon.t_flags & TS_SOFTCAR) ||
8477c478bd9Sstevel@tonic-gate (zsmctl(zs, 0, DMGET) & ZSRR0_CD))
8487c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_CARR_ON;
8497c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate /*
8527c478bd9Sstevel@tonic-gate * If FNDELAY and FNONBLOCK are clear, block until carrier up.
8537c478bd9Sstevel@tonic-gate * Quit on interrupt.
8547c478bd9Sstevel@tonic-gate */
8557c478bd9Sstevel@tonic-gate if (!(flag & (FNDELAY|FNONBLOCK)) &&
8567c478bd9Sstevel@tonic-gate !(za->za_ttycommon.t_cflag & CLOCAL)) {
8577c478bd9Sstevel@tonic-gate if (!(za->za_flags & (ZAS_CARR_ON|ZAS_OUT)) ||
8587c478bd9Sstevel@tonic-gate ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE))) {
8597c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_WOPEN;
8607c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
8617c478bd9Sstevel@tonic-gate if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_ocexcl) == 0) {
8627c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
8637c478bd9Sstevel@tonic-gate if (zs->zs_suspended) {
8647c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
8657c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl);
8667c478bd9Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip,
8677c478bd9Sstevel@tonic-gate 0, 1);
8687c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_ocexcl);
8697c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_WOPEN;
8727c478bd9Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN))
8737c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_null);
8747c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
8757c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl);
8767c478bd9Sstevel@tonic-gate return (EINTR);
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
8797c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_WOPEN;
8807c478bd9Sstevel@tonic-gate if ((zs->zs_ops == &zsops_null) ||
8817c478bd9Sstevel@tonic-gate (zs->zs_ops == &zsops_async))
8827c478bd9Sstevel@tonic-gate goto again;
8837c478bd9Sstevel@tonic-gate else {
8847c478bd9Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN))
8857c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_null);
8867c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
8877c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl);
8887c478bd9Sstevel@tonic-gate return (EBUSY);
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate }
8917c478bd9Sstevel@tonic-gate } else if ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE)) {
8927c478bd9Sstevel@tonic-gate if (set_zsoptinit && !(za->za_flags & ISOPEN))
8937c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_null);
8947c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
8957c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl);
8967c478bd9Sstevel@tonic-gate return (EBUSY);
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate
8997c478bd9Sstevel@tonic-gate za->za_ttycommon.t_readq = rq;
9007c478bd9Sstevel@tonic-gate za->za_ttycommon.t_writeq = WR(rq);
9017c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = (caddr_t)za;
9027c478bd9Sstevel@tonic-gate
9037c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_ISOPEN;
9047c478bd9Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount);
9057c478bd9Sstevel@tonic-gate qprocson(rq);
9067c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
9077c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_ocexcl);
9087c478bd9Sstevel@tonic-gate return (0);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate static void
zs_progress_check(void * arg)9127c478bd9Sstevel@tonic-gate zs_progress_check(void *arg)
9137c478bd9Sstevel@tonic-gate {
9147c478bd9Sstevel@tonic-gate struct asyncline *za = arg;
9157c478bd9Sstevel@tonic-gate struct zscom *zs = za->za_common;
9167c478bd9Sstevel@tonic-gate mblk_t *bp;
9177c478bd9Sstevel@tonic-gate
9187c478bd9Sstevel@tonic-gate /*
9197c478bd9Sstevel@tonic-gate * We define "progress" as either waiting on a timed break or delay, or
9207c478bd9Sstevel@tonic-gate * having had at least one transmitter interrupt. If none of these are
9217c478bd9Sstevel@tonic-gate * true, then just terminate the output and wake up that close thread.
9227c478bd9Sstevel@tonic-gate */
9237c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
9247c478bd9Sstevel@tonic-gate if (!(zs->zs_flags & ZS_PROGRESS) &&
9257c478bd9Sstevel@tonic-gate !(za->za_flags & (ZAS_BREAK|ZAS_DELAY))) {
9267c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY;
9277c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
9287c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
9297c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
9307c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
9317c478bd9Sstevel@tonic-gate bp = za->za_xmitblk;
9327c478bd9Sstevel@tonic-gate za->za_xmitblk = NULL;
9337c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
9347c478bd9Sstevel@tonic-gate zs->zs_timer = 0;
9357c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
9367c478bd9Sstevel@tonic-gate if (bp != NULL)
9377c478bd9Sstevel@tonic-gate freeb(bp);
9387c478bd9Sstevel@tonic-gate /*
9397c478bd9Sstevel@tonic-gate * Since this timer is running, we know that we're in exit(2).
9407c478bd9Sstevel@tonic-gate * That means that the user can't possibly be waiting on any
9417c478bd9Sstevel@tonic-gate * valid ioctl(2) completion anymore, and we should just flush
9427c478bd9Sstevel@tonic-gate * everything.
9437c478bd9Sstevel@tonic-gate */
9447c478bd9Sstevel@tonic-gate flushq(za->za_ttycommon.t_writeq, FLUSHALL);
9457c478bd9Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv);
9467c478bd9Sstevel@tonic-gate } else {
9477c478bd9Sstevel@tonic-gate zs->zs_flags &= ~ZS_PROGRESS;
9487c478bd9Sstevel@tonic-gate zs->zs_timer = timeout(zs_progress_check, za,
9497c478bd9Sstevel@tonic-gate drv_usectohz(zs_drain_check));
9507c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate }
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate /*
9557c478bd9Sstevel@tonic-gate * Close routine.
9567c478bd9Sstevel@tonic-gate *
9577c478bd9Sstevel@tonic-gate * Important locking note: the zs_ocexcl lock is not held at all in this
9587c478bd9Sstevel@tonic-gate * routine. This is intentional. That lock is used to coordinate multiple
9597c478bd9Sstevel@tonic-gate * simultaneous opens on a stream, and there's no such thing as multiple
9607c478bd9Sstevel@tonic-gate * simultaneous closes on a stream.
9617c478bd9Sstevel@tonic-gate */
9627c478bd9Sstevel@tonic-gate
9637c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9647c478bd9Sstevel@tonic-gate static int
zsa_close(queue_t * q,int flag)9657c478bd9Sstevel@tonic-gate zsa_close(queue_t *q, int flag)
9667c478bd9Sstevel@tonic-gate {
9677c478bd9Sstevel@tonic-gate struct asyncline *za;
9687c478bd9Sstevel@tonic-gate struct zscom *zs;
9697c478bd9Sstevel@tonic-gate int i;
9707c478bd9Sstevel@tonic-gate mblk_t *bp;
9717c478bd9Sstevel@tonic-gate timeout_id_t za_zsa_restart_id, za_kick_rcv_id;
9727c478bd9Sstevel@tonic-gate bufcall_id_t za_bufcid, za_wbufcid;
9737c478bd9Sstevel@tonic-gate int tmp;
9747c478bd9Sstevel@tonic-gate
9757c478bd9Sstevel@tonic-gate za = q->q_ptr;
9767c478bd9Sstevel@tonic-gate ASSERT(za != NULL);
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate zs = za->za_common;
9797c478bd9Sstevel@tonic-gate
9807c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
9817c478bd9Sstevel@tonic-gate zs->zs_flags |= ZS_CLOSING;
9827c478bd9Sstevel@tonic-gate
9837c478bd9Sstevel@tonic-gate /*
9847c478bd9Sstevel@tonic-gate * There are two flavors of break -- timed (M_BREAK or TCSBRK) and
9857c478bd9Sstevel@tonic-gate * untimed (TIOCSBRK). For the timed case, these are enqueued on our
9867c478bd9Sstevel@tonic-gate * write queue and there's a timer running, so we don't have to worry
9877c478bd9Sstevel@tonic-gate * about them. For the untimed case, though, the user obviously made a
9887c478bd9Sstevel@tonic-gate * mistake, because these are handled immediately. We'll terminate the
9897c478bd9Sstevel@tonic-gate * break now and honor his implicit request by discarding the rest of
9907c478bd9Sstevel@tonic-gate * the data.
9917c478bd9Sstevel@tonic-gate */
9927c478bd9Sstevel@tonic-gate if (!(za->za_flags & ZAS_BREAK) && (zs->zs_wreg[5] & ZSWR5_BREAK))
9937c478bd9Sstevel@tonic-gate goto nodrain;
9947c478bd9Sstevel@tonic-gate
9957c478bd9Sstevel@tonic-gate /*
9967c478bd9Sstevel@tonic-gate * If the user told us not to delay the close ("non-blocking"), then
9977c478bd9Sstevel@tonic-gate * don't bother trying to drain.
9987c478bd9Sstevel@tonic-gate *
9997c478bd9Sstevel@tonic-gate * If the user did M_STOP (ASYNC_STOPPED), there's no hope of ever
10007c478bd9Sstevel@tonic-gate * getting an M_START (since these messages aren't enqueued), and the
10017c478bd9Sstevel@tonic-gate * only other way to clear the stop condition is by loss of DCD, which
10027c478bd9Sstevel@tonic-gate * would discard the queue data. Thus, we drop the output data if
10037c478bd9Sstevel@tonic-gate * ASYNC_STOPPED is set.
10047c478bd9Sstevel@tonic-gate */
10057c478bd9Sstevel@tonic-gate if ((flag & (FNDELAY|FNONBLOCK)) || (za->za_flags & ZAS_STOPPED))
10067c478bd9Sstevel@tonic-gate goto nodrain;
10077c478bd9Sstevel@tonic-gate
10087c478bd9Sstevel@tonic-gate /*
10097c478bd9Sstevel@tonic-gate * If there's any pending output, then we have to try to drain it.
10107c478bd9Sstevel@tonic-gate * There are two main cases to be handled:
10117c478bd9Sstevel@tonic-gate * - called by close(2): need to drain until done or until
10127c478bd9Sstevel@tonic-gate * a signal is received. No timeout.
10137c478bd9Sstevel@tonic-gate * - called by exit(2): need to drain while making progress
10147c478bd9Sstevel@tonic-gate * or until a timeout occurs. No signals.
10157c478bd9Sstevel@tonic-gate *
10167c478bd9Sstevel@tonic-gate * If we can't rely on receiving a signal to get us out of a hung
10177c478bd9Sstevel@tonic-gate * session, then we have to use a timer. In this case, we set a timer
10187c478bd9Sstevel@tonic-gate * to check for progress in sending the output data -- all that we ask
10197c478bd9Sstevel@tonic-gate * (at each interval) is that there's been some progress made. Since
10207c478bd9Sstevel@tonic-gate * the interrupt routine grabs buffers from the write queue, we can't
10217c478bd9Sstevel@tonic-gate * trust changes in zs_wr_cur. Instead, we use a progress flag.
10227c478bd9Sstevel@tonic-gate *
10237c478bd9Sstevel@tonic-gate * Note that loss of carrier will cause the output queue to be flushed,
10247c478bd9Sstevel@tonic-gate * and we'll wake up again and finish normally.
10257c478bd9Sstevel@tonic-gate */
10267c478bd9Sstevel@tonic-gate if (!ddi_can_receive_sig() && zs_drain_check != 0) {
10277c478bd9Sstevel@tonic-gate zs->zs_flags &= ~ZS_PROGRESS;
10287c478bd9Sstevel@tonic-gate zs->zs_timer = timeout(zs_progress_check, za,
10297c478bd9Sstevel@tonic-gate drv_usectohz(zs_drain_check));
10307c478bd9Sstevel@tonic-gate }
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate while (zs->zs_wr_cur != NULL ||
10337c478bd9Sstevel@tonic-gate za->za_ttycommon.t_writeq->q_first != NULL ||
10347c478bd9Sstevel@tonic-gate (za->za_flags & (ZAS_BUSY|ZAS_DELAY|ZAS_BREAK))) {
10357c478bd9Sstevel@tonic-gate if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_excl) == 0)
10367c478bd9Sstevel@tonic-gate break;
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate
10397c478bd9Sstevel@tonic-gate if (zs->zs_timer != 0) {
10407c478bd9Sstevel@tonic-gate (void) untimeout(zs->zs_timer);
10417c478bd9Sstevel@tonic-gate zs->zs_timer = 0;
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate
10447c478bd9Sstevel@tonic-gate nodrain:
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate * If break is in progress, stop it.
10477c478bd9Sstevel@tonic-gate */
10487c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
10497c478bd9Sstevel@tonic-gate if (zs->zs_wreg[5] & ZSWR5_BREAK) {
10507c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK);
10517c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_BREAK;
10527c478bd9Sstevel@tonic-gate }
10537c478bd9Sstevel@tonic-gate
10547c478bd9Sstevel@tonic-gate za_wbufcid = za->za_wbufcid;
10557c478bd9Sstevel@tonic-gate za_bufcid = za->za_bufcid;
10567c478bd9Sstevel@tonic-gate za_zsa_restart_id = za->za_zsa_restart_id;
10577c478bd9Sstevel@tonic-gate za_kick_rcv_id = za->za_kick_rcv_id;
10587c478bd9Sstevel@tonic-gate
10597c478bd9Sstevel@tonic-gate za->za_wbufcid = za->za_bufcid = 0;
10607c478bd9Sstevel@tonic-gate za->za_zsa_restart_id = za->za_kick_rcv_id = 0;
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate /*
10637c478bd9Sstevel@tonic-gate * If line has HUPCL set or is incompletely opened,
10647c478bd9Sstevel@tonic-gate * and it is not the console or the keyboard,
10657c478bd9Sstevel@tonic-gate * fix up the modem lines.
10667c478bd9Sstevel@tonic-gate */
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_null_async);
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate /*
10717c478bd9Sstevel@tonic-gate * Nobody, zsh or zs can now open this port until
10727c478bd9Sstevel@tonic-gate * zsopinit(zs, &zsops_null);
10737c478bd9Sstevel@tonic-gate *
10747c478bd9Sstevel@tonic-gate */
10757c478bd9Sstevel@tonic-gate
10767c478bd9Sstevel@tonic-gate if ((za->za_dev != rconsdev) && (za->za_dev != kbddev) &&
10777c478bd9Sstevel@tonic-gate (za->za_dev != stdindev) &&
10787c478bd9Sstevel@tonic-gate (((za->za_flags & (ZAS_WOPEN|ZAS_ISOPEN)) != ZAS_ISOPEN) ||
10797c478bd9Sstevel@tonic-gate (za->za_ttycommon.t_cflag & HUPCL))) {
10807c478bd9Sstevel@tonic-gate /*
10817c478bd9Sstevel@tonic-gate * If DTR is being held high by softcarrier,
10827c478bd9Sstevel@tonic-gate * set up the ZS_ON set; if not, hang up.
10837c478bd9Sstevel@tonic-gate */
10847c478bd9Sstevel@tonic-gate if (zsasoftdtr && (za->za_ttycommon.t_flags & TS_SOFTCAR))
10857c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZS_ON, DMSET);
10867c478bd9Sstevel@tonic-gate else
10877c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZS_OFF, DMSET);
10887c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
10897c478bd9Sstevel@tonic-gate /*
10907c478bd9Sstevel@tonic-gate * Don't let an interrupt in the middle of close
10917c478bd9Sstevel@tonic-gate * bounce us back to the top; just continue
10927c478bd9Sstevel@tonic-gate * closing as if nothing had happened.
10937c478bd9Sstevel@tonic-gate */
1094*d3d50737SRafael Vanoni tmp = cv_reltimedwait_sig(&zs->zs_flags_cv, zs->zs_excl,
1095*d3d50737SRafael Vanoni drv_usectohz(10000), TR_CLOCK_TICK);
10967c478bd9Sstevel@tonic-gate if (zs->zs_suspended) {
10977c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
10987c478bd9Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
10997c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
11007c478bd9Sstevel@tonic-gate }
11017c478bd9Sstevel@tonic-gate if (tmp == 0)
11027c478bd9Sstevel@tonic-gate goto out;
11037c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gate /*
11077c478bd9Sstevel@tonic-gate * If nobody's now using it, turn off receiver interrupts.
11087c478bd9Sstevel@tonic-gate */
11097c478bd9Sstevel@tonic-gate if ((za->za_flags & (ZAS_ISOPEN|ZAS_WOPEN)) == 0)
11107c478bd9Sstevel@tonic-gate SCC_BIC(1, ZSWR1_RIE);
11117c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
11127c478bd9Sstevel@tonic-gate
11137c478bd9Sstevel@tonic-gate out:
11147c478bd9Sstevel@tonic-gate /*
11157c478bd9Sstevel@tonic-gate * Clear out device state.
11167c478bd9Sstevel@tonic-gate */
11177c478bd9Sstevel@tonic-gate ttycommon_close(&za->za_ttycommon);
11187c478bd9Sstevel@tonic-gate
11197c478bd9Sstevel@tonic-gate za->za_ttycommon.t_readq = NULL;
11207c478bd9Sstevel@tonic-gate za->za_ttycommon.t_writeq = NULL;
11217c478bd9Sstevel@tonic-gate
11227c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
11237c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
11247c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
11257c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
11267c478bd9Sstevel@tonic-gate bp = za->za_xmitblk;
11277c478bd9Sstevel@tonic-gate za->za_xmitblk = NULL;
11287c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
11297c478bd9Sstevel@tonic-gate if (bp)
11307c478bd9Sstevel@tonic-gate freemsg(bp);
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
11337c478bd9Sstevel@tonic-gate zs->zs_rd_cur = NULL;
11347c478bd9Sstevel@tonic-gate zs->zs_rd_lim = NULL;
11357c478bd9Sstevel@tonic-gate bp = za->za_rcvblk;
11367c478bd9Sstevel@tonic-gate za->za_rcvblk = NULL;
11377c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
11387c478bd9Sstevel@tonic-gate if (bp)
11397c478bd9Sstevel@tonic-gate freemsg(bp);
11407c478bd9Sstevel@tonic-gate
11417c478bd9Sstevel@tonic-gate for (i = 0; i < zsa_rstandby; i++) {
11427c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
11437c478bd9Sstevel@tonic-gate bp = za->za_rstandby[i];
11447c478bd9Sstevel@tonic-gate za->za_rstandby[i] = NULL;
11457c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
11467c478bd9Sstevel@tonic-gate if (bp)
11477c478bd9Sstevel@tonic-gate freemsg(bp);
11487c478bd9Sstevel@tonic-gate }
11497c478bd9Sstevel@tonic-gate
11507c478bd9Sstevel@tonic-gate if (za->za_soft_active || za->za_kick_active) {
11517c478bd9Sstevel@tonic-gate zs->zs_flags |= ZS_CLOSED;
11527c478bd9Sstevel@tonic-gate while (za->za_soft_active || za->za_kick_active)
11537c478bd9Sstevel@tonic-gate cv_wait(&zs->zs_flags_cv, zs->zs_excl);
11547c478bd9Sstevel@tonic-gate }
11557c478bd9Sstevel@tonic-gate if (zs->zs_suspended) {
11567c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
11577c478bd9Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
11587c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
11597c478bd9Sstevel@tonic-gate }
11607c478bd9Sstevel@tonic-gate
11617c478bd9Sstevel@tonic-gate ZSA_FLUSHQ;
11627c478bd9Sstevel@tonic-gate bzero(za, sizeof (struct asyncline));
11637c478bd9Sstevel@tonic-gate qprocsoff(q);
11647c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
11657c478bd9Sstevel@tonic-gate
11667c478bd9Sstevel@tonic-gate /*
11677c478bd9Sstevel@tonic-gate * Cancel outstanding "bufcall" request.
11687c478bd9Sstevel@tonic-gate */
11697c478bd9Sstevel@tonic-gate if (za_wbufcid)
11707c478bd9Sstevel@tonic-gate unbufcall(za_wbufcid);
11717c478bd9Sstevel@tonic-gate if (za_bufcid)
11727c478bd9Sstevel@tonic-gate unbufcall(za_bufcid);
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate /*
11757c478bd9Sstevel@tonic-gate * Cancel outstanding timeout.
11767c478bd9Sstevel@tonic-gate */
11777c478bd9Sstevel@tonic-gate if (za_zsa_restart_id)
11787c478bd9Sstevel@tonic-gate (void) untimeout(za_zsa_restart_id);
11797c478bd9Sstevel@tonic-gate
11807c478bd9Sstevel@tonic-gate if (za_kick_rcv_id)
11817c478bd9Sstevel@tonic-gate (void) untimeout(za_kick_rcv_id);
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL;
11847c478bd9Sstevel@tonic-gate zsopinit(zs, &zsops_null);
11857c478bd9Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv);
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate /* Mark device as available for power management */
11887c478bd9Sstevel@tonic-gate (void) pm_idle_component(zs->zs_dip, zs->zs_unit%2+1);
11897c478bd9Sstevel@tonic-gate return (0);
11907c478bd9Sstevel@tonic-gate }
11917c478bd9Sstevel@tonic-gate
11927c478bd9Sstevel@tonic-gate /*
11937c478bd9Sstevel@tonic-gate * Put procedure for write queue.
11947c478bd9Sstevel@tonic-gate * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here;
11957c478bd9Sstevel@tonic-gate * set the flow control character for M_STOPI and M_STARTI messages;
11967c478bd9Sstevel@tonic-gate * queue up M_BREAK, M_DELAY, and M_DATA messages for processing
11977c478bd9Sstevel@tonic-gate * by the start routine, and then call the start routine; discard
11987c478bd9Sstevel@tonic-gate * everything else. Note that this driver does not incorporate any
11997c478bd9Sstevel@tonic-gate * mechanism to negotiate to handle the canonicalization process.
12007c478bd9Sstevel@tonic-gate * It expects that these functions are handled in upper module(s),
12017c478bd9Sstevel@tonic-gate * as we do in ldterm.
12027c478bd9Sstevel@tonic-gate */
12037c478bd9Sstevel@tonic-gate static void
zsa_wput(queue_t * q,mblk_t * mp)12047c478bd9Sstevel@tonic-gate zsa_wput(queue_t *q, mblk_t *mp)
12057c478bd9Sstevel@tonic-gate {
12067c478bd9Sstevel@tonic-gate register struct asyncline *za;
12077c478bd9Sstevel@tonic-gate register struct zscom *zs;
12087c478bd9Sstevel@tonic-gate register struct copyresp *resp;
12097c478bd9Sstevel@tonic-gate register mblk_t *bp = NULL;
12107c478bd9Sstevel@tonic-gate int error;
12117c478bd9Sstevel@tonic-gate struct iocblk *iocp;
12127c478bd9Sstevel@tonic-gate
12137c478bd9Sstevel@tonic-gate za = (struct asyncline *)q->q_ptr;
12147c478bd9Sstevel@tonic-gate zs = za->za_common;
12157c478bd9Sstevel@tonic-gate if (zs->zs_flags & ZS_NEEDSOFT) {
12167c478bd9Sstevel@tonic-gate zs->zs_flags &= ~ZS_NEEDSOFT;
12177c478bd9Sstevel@tonic-gate (void) zsa_softint(zs);
12187c478bd9Sstevel@tonic-gate }
12197c478bd9Sstevel@tonic-gate
12207c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
12217c478bd9Sstevel@tonic-gate
12227c478bd9Sstevel@tonic-gate case M_STOP:
12237c478bd9Sstevel@tonic-gate /*
12247c478bd9Sstevel@tonic-gate * Since we don't do real DMA, we can just let the
12257c478bd9Sstevel@tonic-gate * chip coast to a stop after applying the brakes.
12267c478bd9Sstevel@tonic-gate */
12277c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
12287c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
12297c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_STOPPED;
12307c478bd9Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) {
12317c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY;
12327c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
12337c478bd9Sstevel@tonic-gate bp = za->za_xmitblk;
12347c478bd9Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur;
12357c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
12367c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
12377c478bd9Sstevel@tonic-gate za->za_xmitblk = NULL;
12387c478bd9Sstevel@tonic-gate }
12397c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
12407c478bd9Sstevel@tonic-gate if (bp)
12417c478bd9Sstevel@tonic-gate (void) putbq(q, bp);
12427c478bd9Sstevel@tonic-gate freemsg(mp);
12437c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
12447c478bd9Sstevel@tonic-gate break;
12457c478bd9Sstevel@tonic-gate
12467c478bd9Sstevel@tonic-gate case M_START:
12477c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
12487c478bd9Sstevel@tonic-gate if (za->za_flags & ZAS_STOPPED) {
12497c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_STOPPED;
12507c478bd9Sstevel@tonic-gate /*
12517c478bd9Sstevel@tonic-gate * If an output operation is in progress,
12527c478bd9Sstevel@tonic-gate * resume it. Otherwise, prod the start
12537c478bd9Sstevel@tonic-gate * routine.
12547c478bd9Sstevel@tonic-gate */
12557c478bd9Sstevel@tonic-gate zsa_start(zs);
12567c478bd9Sstevel@tonic-gate }
12577c478bd9Sstevel@tonic-gate freemsg(mp);
12587c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
12597c478bd9Sstevel@tonic-gate break;
12607c478bd9Sstevel@tonic-gate
12617c478bd9Sstevel@tonic-gate case M_IOCTL:
12627c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
12637c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
12647c478bd9Sstevel@tonic-gate
12657c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
12667c478bd9Sstevel@tonic-gate
12677c478bd9Sstevel@tonic-gate case TIOCGPPS:
12687c478bd9Sstevel@tonic-gate /*
12697c478bd9Sstevel@tonic-gate * Get PPS state.
12707c478bd9Sstevel@tonic-gate */
12717c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL)
12727c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
12737c478bd9Sstevel@tonic-gate
12747c478bd9Sstevel@tonic-gate mp->b_cont = allocb(sizeof (int), BPRI_HI);
12757c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) {
12767c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK;
12777c478bd9Sstevel@tonic-gate iocp->ioc_error = ENOMEM;
12787c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
12797c478bd9Sstevel@tonic-gate break;
12807c478bd9Sstevel@tonic-gate }
12817c478bd9Sstevel@tonic-gate if (za->za_pps)
12827c478bd9Sstevel@tonic-gate *(int *)mp->b_cont->b_wptr = 1;
12837c478bd9Sstevel@tonic-gate else
12847c478bd9Sstevel@tonic-gate *(int *)mp->b_cont->b_wptr = 0;
12857c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (int);
12867c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
12877c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (int);
12887c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
12897c478bd9Sstevel@tonic-gate break;
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate case TIOCSPPS:
12927c478bd9Sstevel@tonic-gate /*
12937c478bd9Sstevel@tonic-gate * Set PPS state.
12947c478bd9Sstevel@tonic-gate */
12957c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int));
12967c478bd9Sstevel@tonic-gate if (error != 0) {
12977c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK;
12987c478bd9Sstevel@tonic-gate iocp->ioc_error = error;
12997c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
13007c478bd9Sstevel@tonic-gate break;
13017c478bd9Sstevel@tonic-gate }
13027c478bd9Sstevel@tonic-gate
13037c478bd9Sstevel@tonic-gate za->za_pps = (*(int *)mp->b_cont->b_rptr != 0);
13047c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
13057c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
13067c478bd9Sstevel@tonic-gate break;
13077c478bd9Sstevel@tonic-gate
13087c478bd9Sstevel@tonic-gate case TIOCGPPSEV:
13097c478bd9Sstevel@tonic-gate {
13107c478bd9Sstevel@tonic-gate /*
13117c478bd9Sstevel@tonic-gate * Get PPS event data.
13127c478bd9Sstevel@tonic-gate */
13137c478bd9Sstevel@tonic-gate void *buf;
13147c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13157c478bd9Sstevel@tonic-gate struct ppsclockev32 p32;
13167c478bd9Sstevel@tonic-gate #endif
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) {
13197c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
13207c478bd9Sstevel@tonic-gate mp->b_cont = NULL;
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate if (za->za_pps == NULL) {
13237c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK;
13247c478bd9Sstevel@tonic-gate iocp->ioc_error = ENXIO;
13257c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
13267c478bd9Sstevel@tonic-gate break;
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13307c478bd9Sstevel@tonic-gate if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
13317c478bd9Sstevel@tonic-gate TIMEVAL_TO_TIMEVAL32(&p32.tv, &ppsclockev.tv);
13327c478bd9Sstevel@tonic-gate p32.serial = ppsclockev.serial;
13337c478bd9Sstevel@tonic-gate buf = &p32;
13347c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ppsclockev32);
13357c478bd9Sstevel@tonic-gate } else
13367c478bd9Sstevel@tonic-gate #endif
13377c478bd9Sstevel@tonic-gate {
13387c478bd9Sstevel@tonic-gate buf = &ppsclockev;
13397c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ppsclockev);
13407c478bd9Sstevel@tonic-gate }
13417c478bd9Sstevel@tonic-gate
13427c478bd9Sstevel@tonic-gate if ((bp = allocb(iocp->ioc_count, BPRI_HI)) == NULL) {
13437c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK;
13447c478bd9Sstevel@tonic-gate iocp->ioc_error = ENOMEM;
13457c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
13467c478bd9Sstevel@tonic-gate break;
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate mp->b_cont = bp;
13497c478bd9Sstevel@tonic-gate
13507c478bd9Sstevel@tonic-gate bcopy(buf, bp->b_wptr, iocp->ioc_count);
13517c478bd9Sstevel@tonic-gate bp->b_wptr += iocp->ioc_count;
13527c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
13537c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
13547c478bd9Sstevel@tonic-gate break;
13557c478bd9Sstevel@tonic-gate }
13567c478bd9Sstevel@tonic-gate
13577c478bd9Sstevel@tonic-gate case TCSETSW:
13587c478bd9Sstevel@tonic-gate case TCSETSF:
13597c478bd9Sstevel@tonic-gate case TCSETAW:
13607c478bd9Sstevel@tonic-gate case TCSETAF:
13617c478bd9Sstevel@tonic-gate case TCSBRK:
13627c478bd9Sstevel@tonic-gate /*
13637c478bd9Sstevel@tonic-gate * The changes do not take effect until all
13647c478bd9Sstevel@tonic-gate * output queued before them is drained.
13657c478bd9Sstevel@tonic-gate * Put this message on the queue, so that
13667c478bd9Sstevel@tonic-gate * "zsa_start" will see it when it's done
13677c478bd9Sstevel@tonic-gate * with the output before it. Poke the
13687c478bd9Sstevel@tonic-gate * start routine, just in case.
13697c478bd9Sstevel@tonic-gate */
13707c478bd9Sstevel@tonic-gate (void) putq(q, mp);
13717c478bd9Sstevel@tonic-gate zsa_start(zs);
13727c478bd9Sstevel@tonic-gate break;
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate default:
13757c478bd9Sstevel@tonic-gate /*
13767c478bd9Sstevel@tonic-gate * Do it now.
13777c478bd9Sstevel@tonic-gate */
13787c478bd9Sstevel@tonic-gate zsa_ioctl(za, q, mp);
13797c478bd9Sstevel@tonic-gate break;
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
13827c478bd9Sstevel@tonic-gate break;
13837c478bd9Sstevel@tonic-gate
13847c478bd9Sstevel@tonic-gate
13857c478bd9Sstevel@tonic-gate case M_IOCDATA:
13867c478bd9Sstevel@tonic-gate
13877c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
13887c478bd9Sstevel@tonic-gate resp = (struct copyresp *)mp->b_rptr;
13897c478bd9Sstevel@tonic-gate if (resp->cp_rval) {
13907c478bd9Sstevel@tonic-gate /*
13917c478bd9Sstevel@tonic-gate * Just free message on failure.
13927c478bd9Sstevel@tonic-gate */
13937c478bd9Sstevel@tonic-gate freemsg(mp);
13947c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
13957c478bd9Sstevel@tonic-gate break;
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate switch (resp->cp_cmd) {
13987c478bd9Sstevel@tonic-gate
13997c478bd9Sstevel@tonic-gate case TIOCMSET:
14007c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
14017c478bd9Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr),
14027c478bd9Sstevel@tonic-gate DMSET);
14037c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14047c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
14057c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
14067c478bd9Sstevel@tonic-gate break;
14077c478bd9Sstevel@tonic-gate
14087c478bd9Sstevel@tonic-gate case TIOCMBIS:
14097c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
14107c478bd9Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr),
14117c478bd9Sstevel@tonic-gate DMBIS);
14127c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14137c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
14147c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
14157c478bd9Sstevel@tonic-gate break;
14167c478bd9Sstevel@tonic-gate
14177c478bd9Sstevel@tonic-gate case TIOCMBIC:
14187c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
14197c478bd9Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr),
14207c478bd9Sstevel@tonic-gate DMBIC);
14217c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14227c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
14237c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
14247c478bd9Sstevel@tonic-gate break;
14257c478bd9Sstevel@tonic-gate
14267c478bd9Sstevel@tonic-gate case TIOCMGET:
14277c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
14287c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
14297c478bd9Sstevel@tonic-gate break;
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate default:
14327c478bd9Sstevel@tonic-gate freemsg(mp);
14337c478bd9Sstevel@tonic-gate
14347c478bd9Sstevel@tonic-gate }
14357c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
14367c478bd9Sstevel@tonic-gate break;
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate
14397c478bd9Sstevel@tonic-gate case M_FLUSH:
14407c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
14417c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) {
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate /*
14447c478bd9Sstevel@tonic-gate * Abort any output in progress.
14457c478bd9Sstevel@tonic-gate */
14467c478bd9Sstevel@tonic-gate if (za->za_flags & ZAS_BUSY) {
14477c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY;
14487c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
14497c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
14507c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
14517c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
14527c478bd9Sstevel@tonic-gate bp = za->za_xmitblk;
14537c478bd9Sstevel@tonic-gate za->za_xmitblk = NULL;
14547c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14557c478bd9Sstevel@tonic-gate if (bp)
14567c478bd9Sstevel@tonic-gate freemsg(bp);
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate /*
14597c478bd9Sstevel@tonic-gate * Flush our write queue.
14607c478bd9Sstevel@tonic-gate */
14617c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */
14627c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; /* it has been flushed */
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) {
14657c478bd9Sstevel@tonic-gate /*
14667c478bd9Sstevel@tonic-gate * Flush any data in the temporary receive buffer
14677c478bd9Sstevel@tonic-gate */
14687c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
14697c478bd9Sstevel@tonic-gate if ((za->za_ttycommon.t_flags & TS_SOFTCAR) ||
14707c478bd9Sstevel@tonic-gate (SCC_READ0() & ZSRR0_CD)) {
14717c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
14727c478bd9Sstevel@tonic-gate } else {
14737c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
14747c478bd9Sstevel@tonic-gate if (!(SCC_READ0() & ZSRR0_RX_READY)) {
14757c478bd9Sstevel@tonic-gate /*
14767c478bd9Sstevel@tonic-gate * settle time for 1 character shift
14777c478bd9Sstevel@tonic-gate */
14787c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14797c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
1480*d3d50737SRafael Vanoni delay(ztdelay(SPEED(
1481*d3d50737SRafael Vanoni za->za_ttycommon.t_cflag))/3 + 1);
14827c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
14837c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
14847c478bd9Sstevel@tonic-gate if (!(SCC_READ0() & ZSRR0_CD))
14857c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate while ((SCC_READ0() &
1488*d3d50737SRafael Vanoni (ZSRR0_CD | ZSRR0_RX_READY)) ==
1489*d3d50737SRafael Vanoni ZSRR0_RX_READY) {
14907c478bd9Sstevel@tonic-gate /*
14917c478bd9Sstevel@tonic-gate * Empty Receiver
14927c478bd9Sstevel@tonic-gate */
14937c478bd9Sstevel@tonic-gate (void) SCC_READDATA();
14947c478bd9Sstevel@tonic-gate }
14957c478bd9Sstevel@tonic-gate }
14967c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
14977c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA);
14987c478bd9Sstevel@tonic-gate ZSA_QREPLY(q, mp);
14997c478bd9Sstevel@tonic-gate /*
15007c478bd9Sstevel@tonic-gate * give the read queues a crack at it
15017c478bd9Sstevel@tonic-gate */
15027c478bd9Sstevel@tonic-gate } else
15037c478bd9Sstevel@tonic-gate freemsg(mp);
15047c478bd9Sstevel@tonic-gate
15057c478bd9Sstevel@tonic-gate /*
15067c478bd9Sstevel@tonic-gate * We must make sure we process messages that survive the
15077c478bd9Sstevel@tonic-gate * write-side flush. Without this call, the close protocol
15087c478bd9Sstevel@tonic-gate * with ldterm can hang forever. (ldterm will have sent us a
15097c478bd9Sstevel@tonic-gate * TCSBRK ioctl that it expects a response to.)
15107c478bd9Sstevel@tonic-gate */
15117c478bd9Sstevel@tonic-gate zsa_start(zs);
15127c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
15137c478bd9Sstevel@tonic-gate break;
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate case M_BREAK:
15167c478bd9Sstevel@tonic-gate case M_DELAY:
15177c478bd9Sstevel@tonic-gate case M_DATA:
15187c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
15197c478bd9Sstevel@tonic-gate /*
15207c478bd9Sstevel@tonic-gate * Queue the message up to be transmitted,
15217c478bd9Sstevel@tonic-gate * and poke the start routine.
15227c478bd9Sstevel@tonic-gate */
15237c478bd9Sstevel@tonic-gate (void) putq(q, mp);
15247c478bd9Sstevel@tonic-gate zsa_start(zs);
15257c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
15267c478bd9Sstevel@tonic-gate break;
15277c478bd9Sstevel@tonic-gate
15287c478bd9Sstevel@tonic-gate case M_STOPI:
15297c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
15307c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
15317c478bd9Sstevel@tonic-gate za->za_flowc = za->za_ttycommon.t_stopc;
15327c478bd9Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) {
15337c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
15347c478bd9Sstevel@tonic-gate bp = za->za_xmitblk;
15357c478bd9Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur;
15367c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
15377c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
15387c478bd9Sstevel@tonic-gate za->za_xmitblk = NULL;
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
15417c478bd9Sstevel@tonic-gate if (bp)
15427c478bd9Sstevel@tonic-gate (void) putbq(q, bp);
15437c478bd9Sstevel@tonic-gate else
15447c478bd9Sstevel@tonic-gate zsa_start(zs); /* poke the start routine */
15457c478bd9Sstevel@tonic-gate freemsg(mp);
15467c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
15477c478bd9Sstevel@tonic-gate break;
15487c478bd9Sstevel@tonic-gate
15497c478bd9Sstevel@tonic-gate case M_STARTI:
15507c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
15517c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
15527c478bd9Sstevel@tonic-gate za->za_flowc = za->za_ttycommon.t_startc;
15537c478bd9Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) {
15547c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
15557c478bd9Sstevel@tonic-gate bp = za->za_xmitblk;
15567c478bd9Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur;
15577c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
15587c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
15597c478bd9Sstevel@tonic-gate za->za_xmitblk = NULL;
15607c478bd9Sstevel@tonic-gate }
15617c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
15627c478bd9Sstevel@tonic-gate if (bp)
15637c478bd9Sstevel@tonic-gate (void) putbq(q, bp);
15647c478bd9Sstevel@tonic-gate else
15657c478bd9Sstevel@tonic-gate zsa_start(zs); /* poke the start routine */
15667c478bd9Sstevel@tonic-gate freemsg(mp);
15677c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
15687c478bd9Sstevel@tonic-gate break;
15697c478bd9Sstevel@tonic-gate
15707c478bd9Sstevel@tonic-gate case M_CTL:
15717c478bd9Sstevel@tonic-gate if (MBLKL(mp) >= sizeof (struct iocblk) &&
15727c478bd9Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) {
15737c478bd9Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_cmd = MC_HAS_POSIX;
15747c478bd9Sstevel@tonic-gate qreply(q, mp);
15757c478bd9Sstevel@tonic-gate } else {
15767c478bd9Sstevel@tonic-gate /*
15777c478bd9Sstevel@tonic-gate * These MC_SERVICE type messages are used by upper
15787c478bd9Sstevel@tonic-gate * modules to tell this driver to send input up
15797c478bd9Sstevel@tonic-gate * immediately, or that it can wait for normal
15807c478bd9Sstevel@tonic-gate * processing that may or may not be done. Sun
15817c478bd9Sstevel@tonic-gate * requires these for the mouse module.
15827c478bd9Sstevel@tonic-gate */
15837c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
15847c478bd9Sstevel@tonic-gate switch (*mp->b_rptr) {
15857c478bd9Sstevel@tonic-gate
15867c478bd9Sstevel@tonic-gate case MC_SERVICEIMM:
15877c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
15887c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_SERVICEIMM;
15897c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
15907c478bd9Sstevel@tonic-gate break;
15917c478bd9Sstevel@tonic-gate
15927c478bd9Sstevel@tonic-gate case MC_SERVICEDEF:
15937c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
15947c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_SERVICEIMM;
15957c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
15967c478bd9Sstevel@tonic-gate break;
15977c478bd9Sstevel@tonic-gate }
15987c478bd9Sstevel@tonic-gate freemsg(mp);
15997c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate break;
16027c478bd9Sstevel@tonic-gate
16037c478bd9Sstevel@tonic-gate default:
16047c478bd9Sstevel@tonic-gate /*
16057c478bd9Sstevel@tonic-gate * "No, I don't want a subscription to Chain Store Age,
16067c478bd9Sstevel@tonic-gate * thank you anyway."
16077c478bd9Sstevel@tonic-gate */
16087c478bd9Sstevel@tonic-gate freemsg(mp);
16097c478bd9Sstevel@tonic-gate break;
16107c478bd9Sstevel@tonic-gate }
16117c478bd9Sstevel@tonic-gate }
16127c478bd9Sstevel@tonic-gate
16137c478bd9Sstevel@tonic-gate /*
16147c478bd9Sstevel@tonic-gate * zs read service procedure
16157c478bd9Sstevel@tonic-gate */
16167c478bd9Sstevel@tonic-gate static void
zsa_rsrv(queue_t * q)16177c478bd9Sstevel@tonic-gate zsa_rsrv(queue_t *q)
16187c478bd9Sstevel@tonic-gate {
16197c478bd9Sstevel@tonic-gate struct asyncline *za;
16207c478bd9Sstevel@tonic-gate struct zscom *zs;
16217c478bd9Sstevel@tonic-gate
16227c478bd9Sstevel@tonic-gate if (((za = (struct asyncline *)q->q_ptr) != NULL) &&
16237c478bd9Sstevel@tonic-gate (za->za_ttycommon.t_cflag & CRTSXOFF)) {
16247c478bd9Sstevel@tonic-gate zs = za->za_common;
16257c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
16267c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
16277c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
16287c478bd9Sstevel@tonic-gate }
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate
16317c478bd9Sstevel@tonic-gate /*
16327c478bd9Sstevel@tonic-gate * Transmitter interrupt service routine.
16337c478bd9Sstevel@tonic-gate * If there's more data to transmit in the current pseudo-DMA block,
16347c478bd9Sstevel@tonic-gate * and the transmitter is ready, send the next character if output
16357c478bd9Sstevel@tonic-gate * is not stopped or draining.
16367c478bd9Sstevel@tonic-gate * Otherwise, queue up a soft interrupt.
16377c478bd9Sstevel@tonic-gate */
16387c478bd9Sstevel@tonic-gate static void
zsa_txint(struct zscom * zs)16397c478bd9Sstevel@tonic-gate zsa_txint(struct zscom *zs)
16407c478bd9Sstevel@tonic-gate {
16417c478bd9Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
16427c478bd9Sstevel@tonic-gate register uchar_t *wr_cur;
16437c478bd9Sstevel@tonic-gate register uchar_t s0;
16447c478bd9Sstevel@tonic-gate
16457c478bd9Sstevel@tonic-gate s0 = SCC_READ0();
16467c478bd9Sstevel@tonic-gate
16477c478bd9Sstevel@tonic-gate if ((wr_cur = zs->zs_wr_cur) != NULL) {
16487c478bd9Sstevel@tonic-gate if (wr_cur < zs->zs_wr_lim) {
16497c478bd9Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
16507c478bd9Sstevel@tonic-gate !(s0 & ZSRR0_CTS)) {
16517c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
16527c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_RETRANSMIT;
16537c478bd9Sstevel@tonic-gate return;
16547c478bd9Sstevel@tonic-gate }
16557c478bd9Sstevel@tonic-gate SCC_WRITEDATA(*wr_cur++);
16567c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
16577c478bd9Sstevel@tonic-gate za->za_wr++;
16587c478bd9Sstevel@tonic-gate #endif
16597c478bd9Sstevel@tonic-gate zs->zs_wr_cur = wr_cur;
16607c478bd9Sstevel@tonic-gate zs->zs_flags |= ZS_PROGRESS;
16617c478bd9Sstevel@tonic-gate return;
16627c478bd9Sstevel@tonic-gate } else {
16637c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
16647c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
16657c478bd9Sstevel@tonic-gate /*
16667c478bd9Sstevel@tonic-gate * Use the rcv_flags_mask as it is set and
16677c478bd9Sstevel@tonic-gate * test while holding the zs_excl_hi mutex
16687c478bd9Sstevel@tonic-gate */
16697c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT;
16707c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
16717c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
16727c478bd9Sstevel@tonic-gate return;
16737c478bd9Sstevel@tonic-gate }
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate
16767c478bd9Sstevel@tonic-gate if (za->za_flowc != '\0' && (!(za->za_flags & ZAS_DRAINING))) {
16777c478bd9Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
16787c478bd9Sstevel@tonic-gate !(s0 & ZSRR0_CTS)) {
16797c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
16807c478bd9Sstevel@tonic-gate return;
16817c478bd9Sstevel@tonic-gate }
16827c478bd9Sstevel@tonic-gate SCC_WRITEDATA(za->za_flowc);
16837c478bd9Sstevel@tonic-gate za->za_flowc = '\0';
16847c478bd9Sstevel@tonic-gate return;
16857c478bd9Sstevel@tonic-gate }
16867c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT);
16877c478bd9Sstevel@tonic-gate /*
16887c478bd9Sstevel@tonic-gate * Set DO_TRANSMIT bit so that the soft interrupt can
16897c478bd9Sstevel@tonic-gate * test it and unset the ZAS_BUSY in za_flags while holding
16907c478bd9Sstevel@tonic-gate * the mutex zs_excl and zs_excl_hi
16917c478bd9Sstevel@tonic-gate */
16927c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT;
16937c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate /*
16977c478bd9Sstevel@tonic-gate * External/Status interrupt.
16987c478bd9Sstevel@tonic-gate */
16997c478bd9Sstevel@tonic-gate static void
zsa_xsint(struct zscom * zs)17007c478bd9Sstevel@tonic-gate zsa_xsint(struct zscom *zs)
17017c478bd9Sstevel@tonic-gate {
17027c478bd9Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
17037c478bd9Sstevel@tonic-gate register uchar_t s0, x0;
17047c478bd9Sstevel@tonic-gate
17057c478bd9Sstevel@tonic-gate s0 = SCC_READ0();
17067c478bd9Sstevel@tonic-gate ZSA_R0_LOG(s0);
17077c478bd9Sstevel@tonic-gate x0 = s0 ^ za->za_rr0;
17087c478bd9Sstevel@tonic-gate za->za_rr0 = s0;
17097c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS);
17107c478bd9Sstevel@tonic-gate
17117c478bd9Sstevel@tonic-gate /*
17127c478bd9Sstevel@tonic-gate * PPS (Pulse Per Second) support.
17137c478bd9Sstevel@tonic-gate */
17147c478bd9Sstevel@tonic-gate if (za->za_pps && (x0 & ZSRR0_CD) && (s0 & ZSRR0_CD)) {
17157c478bd9Sstevel@tonic-gate /*
17167c478bd9Sstevel@tonic-gate * This code captures a timestamp at the designated
17177c478bd9Sstevel@tonic-gate * transition of the PPS signal (CD asserted). The
17187c478bd9Sstevel@tonic-gate * code provides a pointer to the timestamp, as well
17197c478bd9Sstevel@tonic-gate * as the hardware counter value at the capture.
17207c478bd9Sstevel@tonic-gate *
17217c478bd9Sstevel@tonic-gate * Note: the kernel has nano based time values while
17227c478bd9Sstevel@tonic-gate * NTP requires micro based, an in-line fast algorithm
17237c478bd9Sstevel@tonic-gate * to convert nsec to usec is used here -- see hrt2ts()
17247c478bd9Sstevel@tonic-gate * in common/os/timers.c for a full description.
17257c478bd9Sstevel@tonic-gate */
17267c478bd9Sstevel@tonic-gate struct timeval *tvp = &ppsclockev.tv;
17277c478bd9Sstevel@tonic-gate timespec_t ts;
17287c478bd9Sstevel@tonic-gate int nsec, usec;
17297c478bd9Sstevel@tonic-gate
17307c478bd9Sstevel@tonic-gate LED_OFF;
17317c478bd9Sstevel@tonic-gate gethrestime(&ts);
17327c478bd9Sstevel@tonic-gate LED_ON;
17337c478bd9Sstevel@tonic-gate nsec = ts.tv_nsec;
17347c478bd9Sstevel@tonic-gate usec = nsec + (nsec >> 2);
17357c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 1);
17367c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 2);
17377c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 4);
17387c478bd9Sstevel@tonic-gate usec = nsec - (usec >> 3);
17397c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 2);
17407c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 3);
17417c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 4);
17427c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 1);
17437c478bd9Sstevel@tonic-gate usec = nsec + (usec >> 6);
17447c478bd9Sstevel@tonic-gate tvp->tv_usec = usec >> 10;
17457c478bd9Sstevel@tonic-gate tvp->tv_sec = ts.tv_sec;
17467c478bd9Sstevel@tonic-gate
17477c478bd9Sstevel@tonic-gate ++ppsclockev.serial;
17487c478bd9Sstevel@tonic-gate
17497c478bd9Sstevel@tonic-gate /*
17507c478bd9Sstevel@tonic-gate * Because the kernel keeps a high-resolution time, pass the
17517c478bd9Sstevel@tonic-gate * current highres timestamp in tvp and zero in usec.
17527c478bd9Sstevel@tonic-gate */
17537c478bd9Sstevel@tonic-gate ddi_hardpps(tvp, 0);
17547c478bd9Sstevel@tonic-gate }
17557c478bd9Sstevel@tonic-gate
17567c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
17577c478bd9Sstevel@tonic-gate
17587c478bd9Sstevel@tonic-gate if ((x0 & ZSRR0_BREAK) && (s0 & ZSRR0_BREAK) == 0) {
17597c478bd9Sstevel@tonic-gate #ifdef SLAVIO_BUG
17607c478bd9Sstevel@tonic-gate /*
17617c478bd9Sstevel@tonic-gate * ZSRR0_BREAK turned off. This means that the break sequence
17627c478bd9Sstevel@tonic-gate * has completed (i.e., the stop bit finally arrived).
17637c478bd9Sstevel@tonic-gate */
17647c478bd9Sstevel@tonic-gate if ((s0 & ZSRR0_RX_READY) == 0) {
17657c478bd9Sstevel@tonic-gate /*
17667c478bd9Sstevel@tonic-gate * SLAVIO will generate a separate STATUS change
17677c478bd9Sstevel@tonic-gate * interrupt when the break sequence completes.
17687c478bd9Sstevel@tonic-gate * SCC will combine both, taking the higher priority
17697c478bd9Sstevel@tonic-gate * one, the receive. Should still see the ext/stat.
17707c478bd9Sstevel@tonic-gate * bit in REG3 on SCC. If no ext/stat, it must be
17717c478bd9Sstevel@tonic-gate * a SLAVIO.
17727c478bd9Sstevel@tonic-gate */
17737c478bd9Sstevel@tonic-gate za->za_breakoff = 1;
17747c478bd9Sstevel@tonic-gate } else {
17757c478bd9Sstevel@tonic-gate /*
17767c478bd9Sstevel@tonic-gate * The NUL character in the receiver is part of the
17777c478bd9Sstevel@tonic-gate * break sequence; it is discarded.
17787c478bd9Sstevel@tonic-gate */
17797c478bd9Sstevel@tonic-gate (void) SCC_READDATA(); /* swallow null */
17807c478bd9Sstevel@tonic-gate }
17817c478bd9Sstevel@tonic-gate #else /* SLAVIO_BUG */
17827c478bd9Sstevel@tonic-gate /*
17837c478bd9Sstevel@tonic-gate * ZSRR0_BREAK turned off. This means that the break sequence
17847c478bd9Sstevel@tonic-gate * has completed (i.e., the stop bit finally arrived). The NUL
17857c478bd9Sstevel@tonic-gate * character in the receiver is part of the break sequence;
17867c478bd9Sstevel@tonic-gate * it is discarded.
17877c478bd9Sstevel@tonic-gate */
17887c478bd9Sstevel@tonic-gate (void) SCC_READDATA(); /* swallow null */
17897c478bd9Sstevel@tonic-gate #endif /* SLAVIO_BUG */
17907c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
17917c478bd9Sstevel@tonic-gate
17927c478bd9Sstevel@tonic-gate /*
17937c478bd9Sstevel@tonic-gate * Note: this will cause an abort if a break occurs on
17947c478bd9Sstevel@tonic-gate * the "keyboard device", regardless of whether the
17957c478bd9Sstevel@tonic-gate * "keyboard device" is a real keyboard or just a
17967c478bd9Sstevel@tonic-gate * terminal on a serial line. This permits you to
17977c478bd9Sstevel@tonic-gate * abort a workstation by unplugging the keyboard,
17987c478bd9Sstevel@tonic-gate * even if the normal abort key sequence isn't working.
17997c478bd9Sstevel@tonic-gate */
18007c478bd9Sstevel@tonic-gate if ((za->za_dev == kbddev) ||
18017c478bd9Sstevel@tonic-gate ((za->za_dev == rconsdev) || (za->za_dev == stdindev)) &&
18027c478bd9Sstevel@tonic-gate (abort_enable != KIOCABORTALTERNATE)) {
18037c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)NULL);
18047c478bd9Sstevel@tonic-gate /*
18057c478bd9Sstevel@tonic-gate * We just broke into the monitor or debugger,
18067c478bd9Sstevel@tonic-gate * ignore the break in this case so whatever
18077c478bd9Sstevel@tonic-gate * random program that was running doesn't get
18087c478bd9Sstevel@tonic-gate * a SIGINT.
18097c478bd9Sstevel@tonic-gate */
18107c478bd9Sstevel@tonic-gate return;
18117c478bd9Sstevel@tonic-gate }
18127c478bd9Sstevel@tonic-gate za->za_break = 1;
18137c478bd9Sstevel@tonic-gate }
18147c478bd9Sstevel@tonic-gate
18157c478bd9Sstevel@tonic-gate /*
18167c478bd9Sstevel@tonic-gate * If hardware flow control is enabled, (re)start output
18177c478bd9Sstevel@tonic-gate * when CTS is reasserted.
18187c478bd9Sstevel@tonic-gate */
18197c478bd9Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
18207c478bd9Sstevel@tonic-gate (x0 & ZSRR0_CTS) && (s0 & ZSRR0_CTS) &&
18217c478bd9Sstevel@tonic-gate (za->za_rcv_flags_mask & DO_RETRANSMIT))
18227c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT;
18237c478bd9Sstevel@tonic-gate
18247c478bd9Sstevel@tonic-gate za->za_ext = 1;
18257c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
18267c478bd9Sstevel@tonic-gate }
18277c478bd9Sstevel@tonic-gate
18287c478bd9Sstevel@tonic-gate /*
18297c478bd9Sstevel@tonic-gate * Receive Interrupt
18307c478bd9Sstevel@tonic-gate */
18317c478bd9Sstevel@tonic-gate static void
zsa_rxint(struct zscom * zs)18327c478bd9Sstevel@tonic-gate zsa_rxint(struct zscom *zs)
18337c478bd9Sstevel@tonic-gate {
18347c478bd9Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
18357c478bd9Sstevel@tonic-gate register uchar_t c;
18367c478bd9Sstevel@tonic-gate register uchar_t *rd_cur = zs->zs_rd_cur;
18377c478bd9Sstevel@tonic-gate register uchar_t *rd_lim = zs->zs_rd_lim;
18387c478bd9Sstevel@tonic-gate register mblk_t *bp;
18397c478bd9Sstevel@tonic-gate register uint_t fm = za->za_rcv_flags_mask;
18407c478bd9Sstevel@tonic-gate
18417c478bd9Sstevel@tonic-gate
18427c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
18437c478bd9Sstevel@tonic-gate za->za_rd++;
18447c478bd9Sstevel@tonic-gate #endif
18457c478bd9Sstevel@tonic-gate c = (fm >> 16) & (SCC_READDATA());
18467c478bd9Sstevel@tonic-gate
18477c478bd9Sstevel@tonic-gate /*
18487c478bd9Sstevel@tonic-gate * Check for character break sequence
18497c478bd9Sstevel@tonic-gate */
18507c478bd9Sstevel@tonic-gate if ((abort_enable == KIOCABORTALTERNATE) && (za->za_dev == rconsdev)) {
18517c478bd9Sstevel@tonic-gate if (abort_charseq_recognize(c))
18527c478bd9Sstevel@tonic-gate abort_sequence_enter((char *)NULL);
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate
18557c478bd9Sstevel@tonic-gate if (!rd_cur) {
18567c478bd9Sstevel@tonic-gate #ifdef SLAVIO_BUG
18577c478bd9Sstevel@tonic-gate /*
18587c478bd9Sstevel@tonic-gate * SLAVIO generates FE for the start of break and
18597c478bd9Sstevel@tonic-gate * during break when parity is set. End of break is
18607c478bd9Sstevel@tonic-gate * detected when the first character is received.
18617c478bd9Sstevel@tonic-gate * This character is always garbage and is thrown away.
18627c478bd9Sstevel@tonic-gate */
18637c478bd9Sstevel@tonic-gate if (za->za_slav_break) {
18647c478bd9Sstevel@tonic-gate za->za_slav_break = 0;
18657c478bd9Sstevel@tonic-gate za->za_rr0 |= ZSRR0_BREAK;
18667c478bd9Sstevel@tonic-gate zsa_xsint(zs);
18677c478bd9Sstevel@tonic-gate return;
18687c478bd9Sstevel@tonic-gate }
18697c478bd9Sstevel@tonic-gate #endif /* SLAVIO_BUG */
18707c478bd9Sstevel@tonic-gate
18717c478bd9Sstevel@tonic-gate if (c == 0 && (za->za_rr0 & ZSRR0_BREAK)) {
18727c478bd9Sstevel@tonic-gate /*
18737c478bd9Sstevel@tonic-gate * A break sequence was under way, and a NUL character
18747c478bd9Sstevel@tonic-gate * was received. Discard the NUL character, as it is
18757c478bd9Sstevel@tonic-gate * part of the break sequence; if ZSRR0_BREAK turned
18767c478bd9Sstevel@tonic-gate * off, indicating that the break sequence has com-
18777c478bd9Sstevel@tonic-gate * pleted, call "zsa_xsint" to properly handle the
18787c478bd9Sstevel@tonic-gate * error. It would appear that External/Status
18797c478bd9Sstevel@tonic-gate * interrupts get lost occasionally, so this ensures
18807c478bd9Sstevel@tonic-gate * that one is delivered.
18817c478bd9Sstevel@tonic-gate */
18827c478bd9Sstevel@tonic-gate c = SCC_READ0();
18837c478bd9Sstevel@tonic-gate if (!(c & ZSRR0_BREAK))
18847c478bd9Sstevel@tonic-gate zsa_xsint(zs);
18857c478bd9Sstevel@tonic-gate return;
18867c478bd9Sstevel@tonic-gate }
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate #ifdef SLAVIO_BUG
18897c478bd9Sstevel@tonic-gate if (c == 0 && za->za_breakoff) {
18907c478bd9Sstevel@tonic-gate /*
18917c478bd9Sstevel@tonic-gate * A break sequence completed, but SLAVIO generates
18927c478bd9Sstevel@tonic-gate * the NULL character interrupt late, so we throw the
18937c478bd9Sstevel@tonic-gate * NULL away now.
18947c478bd9Sstevel@tonic-gate */
18957c478bd9Sstevel@tonic-gate return;
18967c478bd9Sstevel@tonic-gate }
18977c478bd9Sstevel@tonic-gate
18987c478bd9Sstevel@tonic-gate /*
18997c478bd9Sstevel@tonic-gate * make sure it gets cleared.
19007c478bd9Sstevel@tonic-gate */
19017c478bd9Sstevel@tonic-gate za->za_breakoff = 0;
19027c478bd9Sstevel@tonic-gate #endif /* SLAVIO_BUG */
19037c478bd9Sstevel@tonic-gate
19047c478bd9Sstevel@tonic-gate ZSA_KICK_RCV; /* We can have M_BREAK msg */
19057c478bd9Sstevel@tonic-gate ZSA_ALLOCB(bp);
19067c478bd9Sstevel@tonic-gate if (!bp) {
19077c478bd9Sstevel@tonic-gate za->za_sw_overrun++;
19087c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
19097c478bd9Sstevel@tonic-gate return;
19107c478bd9Sstevel@tonic-gate }
19117c478bd9Sstevel@tonic-gate za->za_rcvblk = bp;
19127c478bd9Sstevel@tonic-gate zs->zs_rd_cur = rd_cur = bp->b_wptr;
19137c478bd9Sstevel@tonic-gate zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim;
19147c478bd9Sstevel@tonic-gate if (za->za_kick_rcv_id == 0)
19157c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate if (c == 0377 && (fm & DO_ESC)) {
19187c478bd9Sstevel@tonic-gate if (rd_lim < rd_cur + 2) {
19197c478bd9Sstevel@tonic-gate ZSA_ALLOCB(bp);
19207c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
19217c478bd9Sstevel@tonic-gate if (!bp) {
19227c478bd9Sstevel@tonic-gate za->za_sw_overrun++;
19237c478bd9Sstevel@tonic-gate return;
19247c478bd9Sstevel@tonic-gate }
19257c478bd9Sstevel@tonic-gate za->za_rcvblk = bp;
19267c478bd9Sstevel@tonic-gate zs->zs_rd_cur = rd_cur = bp->b_wptr;
19277c478bd9Sstevel@tonic-gate zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim;
19287c478bd9Sstevel@tonic-gate }
19297c478bd9Sstevel@tonic-gate *rd_cur++ = c;
19307c478bd9Sstevel@tonic-gate }
19317c478bd9Sstevel@tonic-gate
19327c478bd9Sstevel@tonic-gate
19337c478bd9Sstevel@tonic-gate *rd_cur++ = c;
19347c478bd9Sstevel@tonic-gate zs->zs_rd_cur = rd_cur;
19357c478bd9Sstevel@tonic-gate
19367c478bd9Sstevel@tonic-gate if (rd_cur == rd_lim) {
19377c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
19387c478bd9Sstevel@tonic-gate } else if ((fm & DO_STOPC) && (c == (fm & 0xff))) {
19397c478bd9Sstevel@tonic-gate za->za_do_kick_rcv_in_softint = 1;
19407c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
19417c478bd9Sstevel@tonic-gate }
19427c478bd9Sstevel@tonic-gate
19437c478bd9Sstevel@tonic-gate if ((za->za_flags & ZAS_SERVICEIMM) || g_nocluster) {
19447c478bd9Sstevel@tonic-gate /*
19457c478bd9Sstevel@tonic-gate * Send the data up immediately
19467c478bd9Sstevel@tonic-gate */
19477c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
19487c478bd9Sstevel@tonic-gate }
19497c478bd9Sstevel@tonic-gate }
19507c478bd9Sstevel@tonic-gate
19517c478bd9Sstevel@tonic-gate /*
19527c478bd9Sstevel@tonic-gate * Special receive condition interrupt handler.
19537c478bd9Sstevel@tonic-gate */
19547c478bd9Sstevel@tonic-gate static void
zsa_srint(struct zscom * zs)19557c478bd9Sstevel@tonic-gate zsa_srint(struct zscom *zs)
19567c478bd9Sstevel@tonic-gate {
19577c478bd9Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
19587c478bd9Sstevel@tonic-gate register short s1;
19597c478bd9Sstevel@tonic-gate register uchar_t c;
19607c478bd9Sstevel@tonic-gate register uchar_t c1;
19617c478bd9Sstevel@tonic-gate register mblk_t *bp = za->za_rcvblk;
19627c478bd9Sstevel@tonic-gate register uchar_t *rd_cur = zs->zs_rd_cur;
19637c478bd9Sstevel@tonic-gate
19647c478bd9Sstevel@tonic-gate SCC_READ(1, s1);
19657c478bd9Sstevel@tonic-gate if (s1 & (ZSRR1_FE | ZSRR1_PE | ZSRR1_DO)) {
19667c478bd9Sstevel@tonic-gate c = SCC_READDATA(); /* swallow bad character */
19677c478bd9Sstevel@tonic-gate }
19687c478bd9Sstevel@tonic-gate #ifdef SLAVIO_BUG
19697c478bd9Sstevel@tonic-gate /*
19707c478bd9Sstevel@tonic-gate * SLAVIO does not handle breaks properly when parity is enabled.
19717c478bd9Sstevel@tonic-gate *
19727c478bd9Sstevel@tonic-gate * In general, if a null character is received when a framing
19737c478bd9Sstevel@tonic-gate * error occurs then it is a break condition and not a real
19747c478bd9Sstevel@tonic-gate * framing error. The null character must be limited to the
19757c478bd9Sstevel@tonic-gate * number of bits including the parity bit. For example, a 6
19767c478bd9Sstevel@tonic-gate * bit character with parity would be null if the lower 7 bits
19777c478bd9Sstevel@tonic-gate * read from the receive fifo were 0. (The higher order bits are
19787c478bd9Sstevel@tonic-gate * padded with 1 and/or the stop bits.) The only exception to this
19797c478bd9Sstevel@tonic-gate * general rule would be an 8 bit null character with parity being
19807c478bd9Sstevel@tonic-gate * a 1 in the parity bit and a framing error. This exception
19817c478bd9Sstevel@tonic-gate * can be determined by examining the parity error bit in RREG 1.
19827c478bd9Sstevel@tonic-gate *
19837c478bd9Sstevel@tonic-gate * A null character, even parity, 8 bits, no parity error,
19847c478bd9Sstevel@tonic-gate * (0 0000 0000) with framing error is a break condition.
19857c478bd9Sstevel@tonic-gate *
19867c478bd9Sstevel@tonic-gate * A null character, even parity, 8 bits, parity error,
19877c478bd9Sstevel@tonic-gate * (1 0000 0000) with framing error is a framing error.
19887c478bd9Sstevel@tonic-gate *
19897c478bd9Sstevel@tonic-gate * A null character, odd parity, 8 bits, parity error
19907c478bd9Sstevel@tonic-gate * (0 0000 0000) with framing error is a break condition.
19917c478bd9Sstevel@tonic-gate *
19927c478bd9Sstevel@tonic-gate * A null character, odd parity, 8 bits, no parity error,
19937c478bd9Sstevel@tonic-gate * (1 0000 0000) with framing error is a framing error.
19947c478bd9Sstevel@tonic-gate */
19957c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARENB) {
19967c478bd9Sstevel@tonic-gate switch (za->za_ttycommon.t_cflag & CSIZE) {
19977c478bd9Sstevel@tonic-gate
19987c478bd9Sstevel@tonic-gate case CS5:
19997c478bd9Sstevel@tonic-gate c1 = c & 0x3f;
20007c478bd9Sstevel@tonic-gate break;
20017c478bd9Sstevel@tonic-gate
20027c478bd9Sstevel@tonic-gate case CS6:
20037c478bd9Sstevel@tonic-gate c1 = c & 0x7f;
20047c478bd9Sstevel@tonic-gate break;
20057c478bd9Sstevel@tonic-gate
20067c478bd9Sstevel@tonic-gate case CS7:
20077c478bd9Sstevel@tonic-gate c1 = c & 0xff;
20087c478bd9Sstevel@tonic-gate break;
20097c478bd9Sstevel@tonic-gate
20107c478bd9Sstevel@tonic-gate case CS8:
20117c478bd9Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & PARODD) &&
20127c478bd9Sstevel@tonic-gate !(s1 & ZSRR1_PE))
20137c478bd9Sstevel@tonic-gate c1 = 0xff;
20147c478bd9Sstevel@tonic-gate else if (!(za->za_ttycommon.t_cflag & PARODD) &&
20157c478bd9Sstevel@tonic-gate (s1 & ZSRR1_PE))
20167c478bd9Sstevel@tonic-gate c1 = 0xff;
20177c478bd9Sstevel@tonic-gate else
20187c478bd9Sstevel@tonic-gate c1 = c;
20197c478bd9Sstevel@tonic-gate break;
20207c478bd9Sstevel@tonic-gate }
20217c478bd9Sstevel@tonic-gate
20227c478bd9Sstevel@tonic-gate /*
20237c478bd9Sstevel@tonic-gate * We fake start of break condition.
20247c478bd9Sstevel@tonic-gate */
20257c478bd9Sstevel@tonic-gate if ((s1 & ZSRR1_FE) && c1 == 0) {
20267c478bd9Sstevel@tonic-gate za->za_slav_break = 1;
20277c478bd9Sstevel@tonic-gate return;
20287c478bd9Sstevel@tonic-gate }
20297c478bd9Sstevel@tonic-gate }
20307c478bd9Sstevel@tonic-gate #endif /* SLAVIO_BUG */
20317c478bd9Sstevel@tonic-gate
20327c478bd9Sstevel@tonic-gate if (s1 & ZSRR1_PE) {
20337c478bd9Sstevel@tonic-gate
20347c478bd9Sstevel@tonic-gate /*
20357c478bd9Sstevel@tonic-gate * Mark the parity error so zsa_process will
20367c478bd9Sstevel@tonic-gate * notice it and send it up in an M_BREAK
20377c478bd9Sstevel@tonic-gate * message; ldterm will do the actual parity error
20387c478bd9Sstevel@tonic-gate * processing
20397c478bd9Sstevel@tonic-gate */
20407c478bd9Sstevel@tonic-gate
20417c478bd9Sstevel@tonic-gate if (bp && zs->zs_rd_cur) { /* M_DATA msg */
20427c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
20437c478bd9Sstevel@tonic-gate bp = NULL;
20447c478bd9Sstevel@tonic-gate }
20457c478bd9Sstevel@tonic-gate if (!bp)
20467c478bd9Sstevel@tonic-gate ZSA_ALLOCB(bp);
20477c478bd9Sstevel@tonic-gate if (!bp) {
20487c478bd9Sstevel@tonic-gate za->za_sw_overrun++;
20497c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
20507c478bd9Sstevel@tonic-gate } else {
20517c478bd9Sstevel@tonic-gate za->za_rcvblk = bp;
20527c478bd9Sstevel@tonic-gate zs->zs_rd_cur = rd_cur = bp->b_wptr;
20537c478bd9Sstevel@tonic-gate zs->zs_rd_lim = bp->b_datap->db_lim;
20547c478bd9Sstevel@tonic-gate *rd_cur++ = c;
20557c478bd9Sstevel@tonic-gate zs->zs_rd_cur = rd_cur;
20567c478bd9Sstevel@tonic-gate bp->b_datap->db_type = M_BREAK;
20577c478bd9Sstevel@tonic-gate if (bp->b_datap->db_lim <= rd_cur)
20587c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
20597c478bd9Sstevel@tonic-gate za->za_do_kick_rcv_in_softint = 1;
20607c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
20617c478bd9Sstevel@tonic-gate
20627c478bd9Sstevel@tonic-gate }
20637c478bd9Sstevel@tonic-gate }
20647c478bd9Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS);
20657c478bd9Sstevel@tonic-gate if (s1 & ZSRR1_DO) {
20667c478bd9Sstevel@tonic-gate za->za_hw_overrun++;
20677c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
20687c478bd9Sstevel@tonic-gate }
20697c478bd9Sstevel@tonic-gate }
20707c478bd9Sstevel@tonic-gate
20717c478bd9Sstevel@tonic-gate /*
20727c478bd9Sstevel@tonic-gate * Process software interrupts (or poll)
20737c478bd9Sstevel@tonic-gate * Crucial points:
20747c478bd9Sstevel@tonic-gate * 3. BUG - breaks are handled "out-of-band" - their relative position
20757c478bd9Sstevel@tonic-gate * among input events is lost, as well as multiple breaks together.
20767c478bd9Sstevel@tonic-gate * This is probably not a problem in practice.
20777c478bd9Sstevel@tonic-gate */
20787c478bd9Sstevel@tonic-gate static int
zsa_softint(struct zscom * zs)20797c478bd9Sstevel@tonic-gate zsa_softint(struct zscom *zs)
20807c478bd9Sstevel@tonic-gate {
20817c478bd9Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
20827c478bd9Sstevel@tonic-gate register uchar_t r0;
20837c478bd9Sstevel@tonic-gate register uchar_t za_kick_active;
20847c478bd9Sstevel@tonic-gate register int m_error;
20857c478bd9Sstevel@tonic-gate register int allocbcount = 0;
20867c478bd9Sstevel@tonic-gate register int do_ttycommon_qfull = 0;
20877c478bd9Sstevel@tonic-gate boolean_t hangup = B_FALSE, unhangup = B_FALSE;
20887c478bd9Sstevel@tonic-gate boolean_t m_break = B_FALSE, wakeup = B_FALSE;
20897c478bd9Sstevel@tonic-gate register queue_t *q;
20907c478bd9Sstevel@tonic-gate register mblk_t *bp;
20917c478bd9Sstevel@tonic-gate register mblk_t *head = NULL, *tail = NULL;
20927c478bd9Sstevel@tonic-gate
20937c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
20947c478bd9Sstevel@tonic-gate if (zs->zs_suspended || (zs->zs_flags & ZS_CLOSED)) {
20957c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
20967c478bd9Sstevel@tonic-gate return (0);
20977c478bd9Sstevel@tonic-gate }
20987c478bd9Sstevel@tonic-gate q = za->za_ttycommon.t_readq;
20997c478bd9Sstevel@tonic-gate if (za->za_flags & ZAS_WOPEN && !q) {
21007c478bd9Sstevel@tonic-gate if (za->za_ext) {
21017c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
21027c478bd9Sstevel@tonic-gate r0 = SCC_READ0();
21037c478bd9Sstevel@tonic-gate za->za_ext = 0;
21047c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
21057c478bd9Sstevel@tonic-gate /*
21067c478bd9Sstevel@tonic-gate * carrier up?
21077c478bd9Sstevel@tonic-gate */
21087c478bd9Sstevel@tonic-gate if ((r0 & ZSRR0_CD) ||
21097c478bd9Sstevel@tonic-gate (za->za_ttycommon.t_flags & TS_SOFTCAR)) {
21107c478bd9Sstevel@tonic-gate /*
21117c478bd9Sstevel@tonic-gate * carrier present
21127c478bd9Sstevel@tonic-gate */
21137c478bd9Sstevel@tonic-gate if ((za->za_flags & ZAS_CARR_ON) == 0) {
21147c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_CARR_ON;
21157c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
21167c478bd9Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv);
21177c478bd9Sstevel@tonic-gate return (0);
21187c478bd9Sstevel@tonic-gate }
21197c478bd9Sstevel@tonic-gate }
21207c478bd9Sstevel@tonic-gate }
21217c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
21227c478bd9Sstevel@tonic-gate return (0);
21237c478bd9Sstevel@tonic-gate }
21247c478bd9Sstevel@tonic-gate q = za->za_ttycommon.t_readq;
21257c478bd9Sstevel@tonic-gate if (!q) {
21267c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
21277c478bd9Sstevel@tonic-gate return (0);
21287c478bd9Sstevel@tonic-gate }
21297c478bd9Sstevel@tonic-gate
21307c478bd9Sstevel@tonic-gate m_error = za->za_m_error;
21317c478bd9Sstevel@tonic-gate za->za_m_error = 0;
21327c478bd9Sstevel@tonic-gate
21337c478bd9Sstevel@tonic-gate if (za->za_do_kick_rcv_in_softint) {
21347c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
21357c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
21367c478bd9Sstevel@tonic-gate za->za_do_kick_rcv_in_softint = 0;
21377c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
21387c478bd9Sstevel@tonic-gate }
21397c478bd9Sstevel@tonic-gate
21407c478bd9Sstevel@tonic-gate za_kick_active = za->za_kick_active;
21417c478bd9Sstevel@tonic-gate
21427c478bd9Sstevel@tonic-gate while (!za_kick_active) {
21437c478bd9Sstevel@tonic-gate ZSA_SEEQ(bp);
21447c478bd9Sstevel@tonic-gate if (!bp)
21457c478bd9Sstevel@tonic-gate break;
21467c478bd9Sstevel@tonic-gate
21477c478bd9Sstevel@tonic-gate allocbcount++;
21487c478bd9Sstevel@tonic-gate
21497c478bd9Sstevel@tonic-gate if (bp->b_datap->db_type <= QPCTL) {
21507c478bd9Sstevel@tonic-gate if (!(canputnext(q))) {
21517c478bd9Sstevel@tonic-gate if (za->za_grace_flow_control >=
21527c478bd9Sstevel@tonic-gate zsa_grace_flow_control) {
2153*d3d50737SRafael Vanoni if (za->za_ttycommon.t_cflag &
2154*d3d50737SRafael Vanoni CRTSXOFF) {
21557c478bd9Sstevel@tonic-gate allocbcount--;
21567c478bd9Sstevel@tonic-gate break;
21577c478bd9Sstevel@tonic-gate }
21587c478bd9Sstevel@tonic-gate ZSA_GETQ(bp);
21597c478bd9Sstevel@tonic-gate freemsg(bp);
21607c478bd9Sstevel@tonic-gate do_ttycommon_qfull = 1;
21617c478bd9Sstevel@tonic-gate continue;
21627c478bd9Sstevel@tonic-gate } else
21637c478bd9Sstevel@tonic-gate za->za_grace_flow_control++;
21647c478bd9Sstevel@tonic-gate } else
21657c478bd9Sstevel@tonic-gate za->za_grace_flow_control = 0;
21667c478bd9Sstevel@tonic-gate }
21677c478bd9Sstevel@tonic-gate ZSA_GETQ(bp);
21687c478bd9Sstevel@tonic-gate if (!head) {
21697c478bd9Sstevel@tonic-gate head = bp;
21707c478bd9Sstevel@tonic-gate } else {
21717c478bd9Sstevel@tonic-gate if (!tail)
21727c478bd9Sstevel@tonic-gate tail = head;
21737c478bd9Sstevel@tonic-gate tail->b_next = bp;
21747c478bd9Sstevel@tonic-gate tail = bp;
21757c478bd9Sstevel@tonic-gate }
21767c478bd9Sstevel@tonic-gate }
21777c478bd9Sstevel@tonic-gate
21787c478bd9Sstevel@tonic-gate if (allocbcount)
21797c478bd9Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount);
21807c478bd9Sstevel@tonic-gate
21817c478bd9Sstevel@tonic-gate if (za->za_ext) {
21827c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
21837c478bd9Sstevel@tonic-gate r0 = SCC_READ0();
21847c478bd9Sstevel@tonic-gate za->za_ext = 0;
21857c478bd9Sstevel@tonic-gate /*
21867c478bd9Sstevel@tonic-gate * carrier up?
21877c478bd9Sstevel@tonic-gate */
21887c478bd9Sstevel@tonic-gate if ((r0 & ZSRR0_CD) ||
21897c478bd9Sstevel@tonic-gate (za->za_ttycommon.t_flags & TS_SOFTCAR)) {
21907c478bd9Sstevel@tonic-gate /*
21917c478bd9Sstevel@tonic-gate * carrier present
21927c478bd9Sstevel@tonic-gate */
21937c478bd9Sstevel@tonic-gate if ((za->za_flags & ZAS_CARR_ON) == 0) {
21947c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_CARR_ON;
21957c478bd9Sstevel@tonic-gate unhangup = B_TRUE;
21967c478bd9Sstevel@tonic-gate wakeup = B_TRUE;
21977c478bd9Sstevel@tonic-gate }
21987c478bd9Sstevel@tonic-gate } else {
21997c478bd9Sstevel@tonic-gate if ((za->za_flags & ZAS_CARR_ON) &&
22007c478bd9Sstevel@tonic-gate !(za->za_ttycommon.t_cflag & CLOCAL)) {
22017c478bd9Sstevel@tonic-gate /*
22027c478bd9Sstevel@tonic-gate * Carrier went away.
22037c478bd9Sstevel@tonic-gate * Drop DTR, abort any output in progress,
22047c478bd9Sstevel@tonic-gate * indicate that output is not stopped, and
22057c478bd9Sstevel@tonic-gate * send a hangup notification upstream.
22067c478bd9Sstevel@tonic-gate */
22077c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZSWR5_DTR, DMBIC);
22087c478bd9Sstevel@tonic-gate if ((za->za_flags & ZAS_BUSY) &&
22097c478bd9Sstevel@tonic-gate (zs->zs_wr_cur != NULL)) {
22107c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
22117c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
22127c478bd9Sstevel@tonic-gate }
22137c478bd9Sstevel@tonic-gate hangup = B_TRUE;
22147c478bd9Sstevel@tonic-gate wakeup = B_TRUE;
22157c478bd9Sstevel@tonic-gate za->za_flags &= ~(ZAS_STOPPED | ZAS_CARR_ON |
22167c478bd9Sstevel@tonic-gate ZAS_BUSY);
22177c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~(DO_TRANSMIT |
22187c478bd9Sstevel@tonic-gate DO_RETRANSMIT);
22197c478bd9Sstevel@tonic-gate }
22207c478bd9Sstevel@tonic-gate }
22217c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22227c478bd9Sstevel@tonic-gate if (hangup && (bp = za->za_xmitblk) != NULL) {
22237c478bd9Sstevel@tonic-gate za->za_xmitblk = NULL;
22247c478bd9Sstevel@tonic-gate freeb(bp);
22257c478bd9Sstevel@tonic-gate }
22267c478bd9Sstevel@tonic-gate }
22277c478bd9Sstevel@tonic-gate
22287c478bd9Sstevel@tonic-gate if (za->za_break != 0) {
22297c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
22307c478bd9Sstevel@tonic-gate r0 = SCC_READ0();
22317c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22327c478bd9Sstevel@tonic-gate if ((r0 & ZSRR0_BREAK) == 0) {
22337c478bd9Sstevel@tonic-gate za->za_break = 0;
22347c478bd9Sstevel@tonic-gate m_break = B_TRUE;
22357c478bd9Sstevel@tonic-gate }
22367c478bd9Sstevel@tonic-gate }
22377c478bd9Sstevel@tonic-gate
22387c478bd9Sstevel@tonic-gate /*
22397c478bd9Sstevel@tonic-gate * If a transmission has finished, indicate that it's
22407c478bd9Sstevel@tonic-gate * finished, and start that line up again.
22417c478bd9Sstevel@tonic-gate */
22427c478bd9Sstevel@tonic-gate
22437c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
22447c478bd9Sstevel@tonic-gate if (za->za_rcv_flags_mask & DO_TRANSMIT) {
22457c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_TRANSMIT;
22467c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY;
22477c478bd9Sstevel@tonic-gate
22487c478bd9Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
22497c478bd9Sstevel@tonic-gate (za->za_rcv_flags_mask & DO_RETRANSMIT) &&
22507c478bd9Sstevel@tonic-gate zs->zs_wr_cur)
22517c478bd9Sstevel@tonic-gate bp = NULL;
22527c478bd9Sstevel@tonic-gate else {
22537c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
22547c478bd9Sstevel@tonic-gate bp = za->za_xmitblk;
22557c478bd9Sstevel@tonic-gate za->za_xmitblk = 0;
22567c478bd9Sstevel@tonic-gate }
22577c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22587c478bd9Sstevel@tonic-gate if (bp)
22597c478bd9Sstevel@tonic-gate freemsg(bp);
22607c478bd9Sstevel@tonic-gate zsa_start(zs);
22617c478bd9Sstevel@tonic-gate /* if we didn't start anything, then notify waiters */
22627c478bd9Sstevel@tonic-gate if (!(za->za_flags & ZAS_BUSY))
22637c478bd9Sstevel@tonic-gate wakeup = B_TRUE;
22647c478bd9Sstevel@tonic-gate } else {
22657c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
22667c478bd9Sstevel@tonic-gate }
22677c478bd9Sstevel@tonic-gate
22687c478bd9Sstevel@tonic-gate
22697c478bd9Sstevel@tonic-gate /*
22707c478bd9Sstevel@tonic-gate * A note about these overrun bits: all they do is *tell* someone
22717c478bd9Sstevel@tonic-gate * about an error- They do not track multiple errors. In fact,
22727c478bd9Sstevel@tonic-gate * you could consider them latched register bits if you like.
22737c478bd9Sstevel@tonic-gate * We are only interested in printing the error message once for
22747c478bd9Sstevel@tonic-gate * any cluster of overrun errrors.
22757c478bd9Sstevel@tonic-gate */
22767c478bd9Sstevel@tonic-gate if ((!za->za_kick_rcv_id) && (zs->zs_rd_cur || za_kick_active)) {
22777c478bd9Sstevel@tonic-gate if (g_zsticks)
2278*d3d50737SRafael Vanoni za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs,
2279*d3d50737SRafael Vanoni g_zsticks);
22807c478bd9Sstevel@tonic-gate else
22817c478bd9Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs,
22827c478bd9Sstevel@tonic-gate zsticks[SPEED(za->za_ttycommon.t_cflag)]);
22837c478bd9Sstevel@tonic-gate za->za_kick_rcv_count = ZA_KICK_RCV_COUNT;
22847c478bd9Sstevel@tonic-gate }
22857c478bd9Sstevel@tonic-gate za->za_soft_active = 1;
22867c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
22877c478bd9Sstevel@tonic-gate
22887c478bd9Sstevel@tonic-gate if (!hangup && do_ttycommon_qfull) {
22897c478bd9Sstevel@tonic-gate ttycommon_qfull(&za->za_ttycommon, q);
22907c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
22917c478bd9Sstevel@tonic-gate zsa_start(zs);
22927c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
22937c478bd9Sstevel@tonic-gate }
22947c478bd9Sstevel@tonic-gate
22957c478bd9Sstevel@tonic-gate if (za->za_hw_overrun > 10) {
22967c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "zs%d: silo overflow\n", UNIT(za->za_dev));
22977c478bd9Sstevel@tonic-gate za->za_hw_overrun = 0;
22987c478bd9Sstevel@tonic-gate }
22997c478bd9Sstevel@tonic-gate
23007c478bd9Sstevel@tonic-gate if (za->za_sw_overrun > 10) {
23017c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "zs%d:ring buffer overflow\n",
23027c478bd9Sstevel@tonic-gate UNIT(za->za_dev));
23037c478bd9Sstevel@tonic-gate za->za_sw_overrun = 0;
23047c478bd9Sstevel@tonic-gate }
23057c478bd9Sstevel@tonic-gate
23067c478bd9Sstevel@tonic-gate if (unhangup)
23077c478bd9Sstevel@tonic-gate (void) putnextctl(q, M_UNHANGUP);
23087c478bd9Sstevel@tonic-gate
23097c478bd9Sstevel@tonic-gate if (m_break)
23107c478bd9Sstevel@tonic-gate (void) putnextctl(q, M_BREAK);
23117c478bd9Sstevel@tonic-gate
23127c478bd9Sstevel@tonic-gate while (head) {
23137c478bd9Sstevel@tonic-gate if (!tail) {
23147c478bd9Sstevel@tonic-gate putnext(q, head);
23157c478bd9Sstevel@tonic-gate break;
23167c478bd9Sstevel@tonic-gate }
23177c478bd9Sstevel@tonic-gate bp = head;
23187c478bd9Sstevel@tonic-gate head = head->b_next;
23197c478bd9Sstevel@tonic-gate bp->b_next = NULL;
23207c478bd9Sstevel@tonic-gate putnext(q, bp);
23217c478bd9Sstevel@tonic-gate }
23227c478bd9Sstevel@tonic-gate
23237c478bd9Sstevel@tonic-gate if (hangup) {
23247c478bd9Sstevel@tonic-gate int flushflag;
23257c478bd9Sstevel@tonic-gate
23267c478bd9Sstevel@tonic-gate /*
23277c478bd9Sstevel@tonic-gate * If we're in the midst of close, then flush everything. Don't
23287c478bd9Sstevel@tonic-gate * leave stale ioctls lying about.
23297c478bd9Sstevel@tonic-gate */
23307c478bd9Sstevel@tonic-gate flushflag = (zs->zs_flags & ZS_CLOSING) ? FLUSHALL : FLUSHDATA;
23317c478bd9Sstevel@tonic-gate flushq(za->za_ttycommon.t_writeq, flushflag);
23327c478bd9Sstevel@tonic-gate (void) putnextctl(q, M_HANGUP);
23337c478bd9Sstevel@tonic-gate }
23347c478bd9Sstevel@tonic-gate
23357c478bd9Sstevel@tonic-gate if (m_error)
23367c478bd9Sstevel@tonic-gate (void) putnextctl1(q, M_ERROR, m_error);
23377c478bd9Sstevel@tonic-gate
23387c478bd9Sstevel@tonic-gate za->za_soft_active = 0;
23397c478bd9Sstevel@tonic-gate
23407c478bd9Sstevel@tonic-gate if (wakeup || (zs->zs_flags & ZS_CLOSED))
23417c478bd9Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv);
23427c478bd9Sstevel@tonic-gate
23437c478bd9Sstevel@tonic-gate return (0);
23447c478bd9Sstevel@tonic-gate }
23457c478bd9Sstevel@tonic-gate
23467c478bd9Sstevel@tonic-gate /*
23477c478bd9Sstevel@tonic-gate * Start output on a line, unless it's busy, frozen, or otherwise.
23487c478bd9Sstevel@tonic-gate */
23497c478bd9Sstevel@tonic-gate static void
zsa_start(struct zscom * zs)23507c478bd9Sstevel@tonic-gate zsa_start(struct zscom *zs)
23517c478bd9Sstevel@tonic-gate {
23527c478bd9Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
23537c478bd9Sstevel@tonic-gate register int cc;
23547c478bd9Sstevel@tonic-gate register queue_t *q;
23557c478bd9Sstevel@tonic-gate register mblk_t *bp;
23567c478bd9Sstevel@tonic-gate uchar_t *rptr, *wptr;
23577c478bd9Sstevel@tonic-gate
23587c478bd9Sstevel@tonic-gate /*
23597c478bd9Sstevel@tonic-gate * If the chip is busy (i.e., we're waiting for a break timeout
23607c478bd9Sstevel@tonic-gate * to expire, or for the current transmission to finish, or for
23617c478bd9Sstevel@tonic-gate * output to finish draining from chip), don't grab anything new.
23627c478bd9Sstevel@tonic-gate */
23637c478bd9Sstevel@tonic-gate if ((za->za_flags & (ZAS_BREAK|ZAS_BUSY|ZAS_DRAINING)) ||
23647c478bd9Sstevel@tonic-gate zs->zs_suspended)
23657c478bd9Sstevel@tonic-gate return;
23667c478bd9Sstevel@tonic-gate
23677c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) {
23687c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
23697c478bd9Sstevel@tonic-gate if (za->za_rcv_flags_mask & DO_RETRANSMIT) {
23707c478bd9Sstevel@tonic-gate rptr = zs->zs_wr_cur;
23717c478bd9Sstevel@tonic-gate wptr = zs->zs_wr_lim;
23727c478bd9Sstevel@tonic-gate goto zsa_start_retransmit;
23737c478bd9Sstevel@tonic-gate
23747c478bd9Sstevel@tonic-gate }
23757c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
23767c478bd9Sstevel@tonic-gate }
23777c478bd9Sstevel@tonic-gate
23787c478bd9Sstevel@tonic-gate /*
23797c478bd9Sstevel@tonic-gate * If we have a flow-control character to transmit, do it now.
23807c478bd9Sstevel@tonic-gate */
23817c478bd9Sstevel@tonic-gate if (za->za_flowc != '\0') {
23827c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
23837c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) {
23847c478bd9Sstevel@tonic-gate if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) !=
23857c478bd9Sstevel@tonic-gate (ZSRR0_CTS|ZSRR0_TX_READY)) {
23867c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
23877c478bd9Sstevel@tonic-gate return;
23887c478bd9Sstevel@tonic-gate }
23897c478bd9Sstevel@tonic-gate } else if (!(SCC_READ0() & ZSRR0_TX_READY)) {
23907c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
23917c478bd9Sstevel@tonic-gate return;
23927c478bd9Sstevel@tonic-gate }
23937c478bd9Sstevel@tonic-gate
23947c478bd9Sstevel@tonic-gate ZSDELAY();
23957c478bd9Sstevel@tonic-gate SCC_WRITEDATA(za->za_flowc);
23967c478bd9Sstevel@tonic-gate za->za_flowc = '\0';
23977c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
23987c478bd9Sstevel@tonic-gate return;
23997c478bd9Sstevel@tonic-gate }
24007c478bd9Sstevel@tonic-gate
24017c478bd9Sstevel@tonic-gate /*
24027c478bd9Sstevel@tonic-gate * If we're waiting for a delay timeout to expire, don't grab
24037c478bd9Sstevel@tonic-gate * anything new.
24047c478bd9Sstevel@tonic-gate */
24057c478bd9Sstevel@tonic-gate if (za->za_flags & ZAS_DELAY)
24067c478bd9Sstevel@tonic-gate return;
24077c478bd9Sstevel@tonic-gate
24087c478bd9Sstevel@tonic-gate if ((q = za->za_ttycommon.t_writeq) == NULL)
24097c478bd9Sstevel@tonic-gate return; /* not attached to a stream */
24107c478bd9Sstevel@tonic-gate
24117c478bd9Sstevel@tonic-gate zsa_start_again:
24127c478bd9Sstevel@tonic-gate for (;;) {
24137c478bd9Sstevel@tonic-gate if ((bp = getq(q)) == NULL)
24147c478bd9Sstevel@tonic-gate return; /* no data to transmit */
24157c478bd9Sstevel@tonic-gate
24167c478bd9Sstevel@tonic-gate /*
24177c478bd9Sstevel@tonic-gate * We have a message block to work on.
24187c478bd9Sstevel@tonic-gate * Check whether it's a break, a delay, or an ioctl (the latter
24197c478bd9Sstevel@tonic-gate * occurs if the ioctl in question was waiting for the output
24207c478bd9Sstevel@tonic-gate * to drain). If it's one of those, process it immediately.
24217c478bd9Sstevel@tonic-gate */
24227c478bd9Sstevel@tonic-gate switch (bp->b_datap->db_type) {
24237c478bd9Sstevel@tonic-gate
24247c478bd9Sstevel@tonic-gate case M_BREAK:
24257c478bd9Sstevel@tonic-gate /*
24267c478bd9Sstevel@tonic-gate * Set the break bit, and arrange for "zsa_restart"
24277c478bd9Sstevel@tonic-gate * to be called in 1/4 second; it will turn the
24287c478bd9Sstevel@tonic-gate * break bit off, and call "zsa_start" to grab
24297c478bd9Sstevel@tonic-gate * the next message.
24307c478bd9Sstevel@tonic-gate */
24317c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
24327c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_BREAK);
24337c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
24347c478bd9Sstevel@tonic-gate if (!za->za_zsa_restart_id) {
24357c478bd9Sstevel@tonic-gate za->za_zsa_restart_id =
24367c478bd9Sstevel@tonic-gate timeout(zsa_restart, zs, hz/4);
24377c478bd9Sstevel@tonic-gate }
24387c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_BREAK;
24397c478bd9Sstevel@tonic-gate freemsg(bp);
24407c478bd9Sstevel@tonic-gate return; /* wait for this to finish */
24417c478bd9Sstevel@tonic-gate
24427c478bd9Sstevel@tonic-gate case M_DELAY:
24437c478bd9Sstevel@tonic-gate /*
24447c478bd9Sstevel@tonic-gate * Arrange for "zsa_restart" to be called when the
24457c478bd9Sstevel@tonic-gate * delay expires; it will turn MTS_DELAY off,
24467c478bd9Sstevel@tonic-gate * and call "zsa_start" to grab the next message.
24477c478bd9Sstevel@tonic-gate */
24487c478bd9Sstevel@tonic-gate if (! za->za_zsa_restart_id) {
24497c478bd9Sstevel@tonic-gate za->za_zsa_restart_id = timeout(zsa_restart,
24507c478bd9Sstevel@tonic-gate zs,
24517c478bd9Sstevel@tonic-gate (int)(*(unsigned char *)bp->b_rptr + 6));
24527c478bd9Sstevel@tonic-gate }
24537c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_DELAY;
24547c478bd9Sstevel@tonic-gate freemsg(bp);
24557c478bd9Sstevel@tonic-gate return; /* wait for this to finish */
24567c478bd9Sstevel@tonic-gate
24577c478bd9Sstevel@tonic-gate case M_IOCTL:
24587c478bd9Sstevel@tonic-gate /*
24597c478bd9Sstevel@tonic-gate * This ioctl was waiting for the output ahead of
24607c478bd9Sstevel@tonic-gate * it to drain; obviously, it has. Do it, and
24617c478bd9Sstevel@tonic-gate * then grab the next message after it.
24627c478bd9Sstevel@tonic-gate */
24637c478bd9Sstevel@tonic-gate zsa_ioctl(za, q, bp);
24647c478bd9Sstevel@tonic-gate continue;
24657c478bd9Sstevel@tonic-gate default: /* M_DATA */
24667c478bd9Sstevel@tonic-gate goto zsa_start_transmit;
24677c478bd9Sstevel@tonic-gate }
24687c478bd9Sstevel@tonic-gate
24697c478bd9Sstevel@tonic-gate }
24707c478bd9Sstevel@tonic-gate zsa_start_transmit:
24717c478bd9Sstevel@tonic-gate /*
24727c478bd9Sstevel@tonic-gate * We have data to transmit. If output is stopped, put
24737c478bd9Sstevel@tonic-gate * it back and try again later.
24747c478bd9Sstevel@tonic-gate */
24757c478bd9Sstevel@tonic-gate if (za->za_flags & ZAS_STOPPED) {
24767c478bd9Sstevel@tonic-gate (void) putbq(q, bp);
24777c478bd9Sstevel@tonic-gate return;
24787c478bd9Sstevel@tonic-gate }
24797c478bd9Sstevel@tonic-gate
24807c478bd9Sstevel@tonic-gate za->za_xmitblk = bp;
24817c478bd9Sstevel@tonic-gate rptr = bp->b_rptr;
24827c478bd9Sstevel@tonic-gate wptr = bp->b_wptr;
24837c478bd9Sstevel@tonic-gate cc = wptr - rptr;
24847c478bd9Sstevel@tonic-gate bp = bp->b_cont;
24857c478bd9Sstevel@tonic-gate if (bp != NULL) {
24867c478bd9Sstevel@tonic-gate za->za_xmitblk->b_cont = NULL;
24877c478bd9Sstevel@tonic-gate (void) putbq(q, bp); /* not done with this message yet */
24887c478bd9Sstevel@tonic-gate }
24897c478bd9Sstevel@tonic-gate
24907c478bd9Sstevel@tonic-gate if (rptr >= wptr) {
24917c478bd9Sstevel@tonic-gate freeb(za->za_xmitblk);
24927c478bd9Sstevel@tonic-gate za->za_xmitblk = NULL;
24937c478bd9Sstevel@tonic-gate goto zsa_start_again;
24947c478bd9Sstevel@tonic-gate }
24957c478bd9Sstevel@tonic-gate
24967c478bd9Sstevel@tonic-gate /*
24977c478bd9Sstevel@tonic-gate * In 5-bit mode, the high order bits are used
24987c478bd9Sstevel@tonic-gate * to indicate character sizes less than five,
24997c478bd9Sstevel@tonic-gate * so we need to explicitly mask before transmitting
25007c478bd9Sstevel@tonic-gate */
25017c478bd9Sstevel@tonic-gate if ((za->za_ttycommon.t_cflag & CSIZE) == CS5) {
25027c478bd9Sstevel@tonic-gate register unsigned char *p = rptr;
25037c478bd9Sstevel@tonic-gate register int cnt = cc;
25047c478bd9Sstevel@tonic-gate
25057c478bd9Sstevel@tonic-gate while (cnt--)
25067c478bd9Sstevel@tonic-gate *p++ &= (unsigned char) 0x1f;
25077c478bd9Sstevel@tonic-gate }
25087c478bd9Sstevel@tonic-gate
25097c478bd9Sstevel@tonic-gate /*
25107c478bd9Sstevel@tonic-gate * Set up this block for pseudo-DMA.
25117c478bd9Sstevel@tonic-gate */
25127c478bd9Sstevel@tonic-gate
25137c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
25147c478bd9Sstevel@tonic-gate zs->zs_wr_cur = rptr;
25157c478bd9Sstevel@tonic-gate zs->zs_wr_lim = wptr;
25167c478bd9Sstevel@tonic-gate
25177c478bd9Sstevel@tonic-gate zsa_start_retransmit:
25187c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_TRANSMIT;
25197c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS) {
25207c478bd9Sstevel@tonic-gate if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) !=
25217c478bd9Sstevel@tonic-gate (ZSRR0_CTS|ZSRR0_TX_READY)) {
25227c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_RETRANSMIT;
25237c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_BUSY;
25247c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
25257c478bd9Sstevel@tonic-gate return;
25267c478bd9Sstevel@tonic-gate }
25277c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
2528*d3d50737SRafael Vanoni } else {
2529*d3d50737SRafael Vanoni if (!(SCC_READ0() & ZSRR0_TX_READY)) {
25307c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_BUSY;
25317c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
25327c478bd9Sstevel@tonic-gate return;
25337c478bd9Sstevel@tonic-gate }
2534*d3d50737SRafael Vanoni }
25357c478bd9Sstevel@tonic-gate /*
25367c478bd9Sstevel@tonic-gate * If the transmitter is ready, shove the first
25377c478bd9Sstevel@tonic-gate * character out.
25387c478bd9Sstevel@tonic-gate */
25397c478bd9Sstevel@tonic-gate ZSDELAY();
25407c478bd9Sstevel@tonic-gate SCC_WRITEDATA(*rptr++);
25417c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
25427c478bd9Sstevel@tonic-gate za->za_wr++;
25437c478bd9Sstevel@tonic-gate #endif
25447c478bd9Sstevel@tonic-gate zs->zs_wr_cur = rptr;
25457c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_BUSY;
25467c478bd9Sstevel@tonic-gate zs->zs_flags |= ZS_PROGRESS;
25477c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
25487c478bd9Sstevel@tonic-gate }
25497c478bd9Sstevel@tonic-gate
25507c478bd9Sstevel@tonic-gate /*
25517c478bd9Sstevel@tonic-gate * Restart output on a line after a delay or break timer expired.
25527c478bd9Sstevel@tonic-gate */
25537c478bd9Sstevel@tonic-gate static void
zsa_restart(void * arg)25547c478bd9Sstevel@tonic-gate zsa_restart(void *arg)
25557c478bd9Sstevel@tonic-gate {
25567c478bd9Sstevel@tonic-gate struct zscom *zs = arg;
25577c478bd9Sstevel@tonic-gate struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
25587c478bd9Sstevel@tonic-gate
25597c478bd9Sstevel@tonic-gate /*
25607c478bd9Sstevel@tonic-gate * If break timer expired, turn off the break bit.
25617c478bd9Sstevel@tonic-gate */
25627c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
25637c478bd9Sstevel@tonic-gate if (!za->za_zsa_restart_id) {
25647c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
25657c478bd9Sstevel@tonic-gate return;
25667c478bd9Sstevel@tonic-gate }
25677c478bd9Sstevel@tonic-gate za->za_zsa_restart_id = 0;
25687c478bd9Sstevel@tonic-gate if (za->za_flags & ZAS_BREAK) {
25697c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
25707c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK);
25717c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
25727c478bd9Sstevel@tonic-gate }
25737c478bd9Sstevel@tonic-gate za->za_flags &= ~(ZAS_DELAY|ZAS_BREAK);
25747c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_writeq != NULL)
25757c478bd9Sstevel@tonic-gate zsa_start(zs);
25767c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
25777c478bd9Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv);
25787c478bd9Sstevel@tonic-gate }
25797c478bd9Sstevel@tonic-gate
25807c478bd9Sstevel@tonic-gate /*
25817c478bd9Sstevel@tonic-gate * See if the receiver has any data after zs_tick delay
25827c478bd9Sstevel@tonic-gate */
25837c478bd9Sstevel@tonic-gate static void
zsa_kick_rcv(void * arg)25847c478bd9Sstevel@tonic-gate zsa_kick_rcv(void *arg)
25857c478bd9Sstevel@tonic-gate {
25867c478bd9Sstevel@tonic-gate struct zscom *zs = arg;
25877c478bd9Sstevel@tonic-gate struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
25887c478bd9Sstevel@tonic-gate queue_t *q;
25897c478bd9Sstevel@tonic-gate int tmp;
25907c478bd9Sstevel@tonic-gate mblk_t *mp;
25917c478bd9Sstevel@tonic-gate uchar_t za_soft_active, za_kick_active;
25927c478bd9Sstevel@tonic-gate int allocbcount = 0;
25937c478bd9Sstevel@tonic-gate int do_ttycommon_qfull = 0;
25947c478bd9Sstevel@tonic-gate mblk_t *head = NULL, *tail = NULL;
25957c478bd9Sstevel@tonic-gate
25967c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
25977c478bd9Sstevel@tonic-gate if (za->za_kick_rcv_id == 0 || (zs->zs_flags & ZS_CLOSED)) {
25987c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
25997c478bd9Sstevel@tonic-gate return;
26007c478bd9Sstevel@tonic-gate }
26017c478bd9Sstevel@tonic-gate za_soft_active = za->za_soft_active;
26027c478bd9Sstevel@tonic-gate za_kick_active = za->za_kick_active;
26037c478bd9Sstevel@tonic-gate q = za->za_ttycommon.t_readq;
26047c478bd9Sstevel@tonic-gate if (!q) {
26057c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
26067c478bd9Sstevel@tonic-gate return;
26077c478bd9Sstevel@tonic-gate }
26087c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
26097c478bd9Sstevel@tonic-gate if (zs->zs_rd_cur) {
26107c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
26117c478bd9Sstevel@tonic-gate za->za_kick_rcv_count = tmp = ZA_KICK_RCV_COUNT;
26127c478bd9Sstevel@tonic-gate } else
26137c478bd9Sstevel@tonic-gate tmp = --za->za_kick_rcv_count;
26147c478bd9Sstevel@tonic-gate if (tmp > 0 || za_soft_active || za_kick_active) {
26157c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
26167c478bd9Sstevel@tonic-gate if (g_zsticks)
26177c478bd9Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv,
26187c478bd9Sstevel@tonic-gate zs, g_zsticks);
26197c478bd9Sstevel@tonic-gate else
26207c478bd9Sstevel@tonic-gate za->za_kick_rcv_id = timeout(zsa_kick_rcv,
26217c478bd9Sstevel@tonic-gate zs, zsticks[SPEED(za->za_ttycommon.t_cflag)]);
26227c478bd9Sstevel@tonic-gate if (za_soft_active || za_kick_active) {
26237c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
26247c478bd9Sstevel@tonic-gate return;
26257c478bd9Sstevel@tonic-gate }
26267c478bd9Sstevel@tonic-gate } else {
26277c478bd9Sstevel@tonic-gate za->za_kick_rcv_id = 0;
26287c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
26297c478bd9Sstevel@tonic-gate }
26307c478bd9Sstevel@tonic-gate
26317c478bd9Sstevel@tonic-gate
26327c478bd9Sstevel@tonic-gate for (;;) {
26337c478bd9Sstevel@tonic-gate ZSA_SEEQ(mp);
26347c478bd9Sstevel@tonic-gate if (!mp)
26357c478bd9Sstevel@tonic-gate break;
26367c478bd9Sstevel@tonic-gate
26377c478bd9Sstevel@tonic-gate allocbcount++;
26387c478bd9Sstevel@tonic-gate
26397c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type <= QPCTL) {
26407c478bd9Sstevel@tonic-gate if (!(canputnext(q))) {
26417c478bd9Sstevel@tonic-gate if (za->za_grace_flow_control >=
26427c478bd9Sstevel@tonic-gate zsa_grace_flow_control) {
2643*d3d50737SRafael Vanoni if (za->za_ttycommon.t_cflag &
2644*d3d50737SRafael Vanoni CRTSXOFF) {
26457c478bd9Sstevel@tonic-gate allocbcount--;
26467c478bd9Sstevel@tonic-gate break;
26477c478bd9Sstevel@tonic-gate }
26487c478bd9Sstevel@tonic-gate ZSA_GETQ(mp);
26497c478bd9Sstevel@tonic-gate freemsg(mp);
26507c478bd9Sstevel@tonic-gate do_ttycommon_qfull = 1;
26517c478bd9Sstevel@tonic-gate continue;
26527c478bd9Sstevel@tonic-gate } else
26537c478bd9Sstevel@tonic-gate za->za_grace_flow_control++;
26547c478bd9Sstevel@tonic-gate } else
26557c478bd9Sstevel@tonic-gate za->za_grace_flow_control = 0;
26567c478bd9Sstevel@tonic-gate }
26577c478bd9Sstevel@tonic-gate ZSA_GETQ(mp);
26587c478bd9Sstevel@tonic-gate if (!head) {
26597c478bd9Sstevel@tonic-gate head = mp;
26607c478bd9Sstevel@tonic-gate } else {
26617c478bd9Sstevel@tonic-gate if (!tail)
26627c478bd9Sstevel@tonic-gate tail = head;
26637c478bd9Sstevel@tonic-gate tail->b_next = mp;
26647c478bd9Sstevel@tonic-gate tail = mp;
26657c478bd9Sstevel@tonic-gate }
26667c478bd9Sstevel@tonic-gate }
26677c478bd9Sstevel@tonic-gate
26687c478bd9Sstevel@tonic-gate if (allocbcount)
26697c478bd9Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount);
26707c478bd9Sstevel@tonic-gate
26717c478bd9Sstevel@tonic-gate za->za_kick_active = 1;
26727c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
26737c478bd9Sstevel@tonic-gate
26747c478bd9Sstevel@tonic-gate if (do_ttycommon_qfull) {
26757c478bd9Sstevel@tonic-gate ttycommon_qfull(&za->za_ttycommon, q);
26767c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
26777c478bd9Sstevel@tonic-gate zsa_start(zs);
26787c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
26797c478bd9Sstevel@tonic-gate }
26807c478bd9Sstevel@tonic-gate
26817c478bd9Sstevel@tonic-gate while (head) {
26827c478bd9Sstevel@tonic-gate if (!tail) {
26837c478bd9Sstevel@tonic-gate putnext(q, head);
26847c478bd9Sstevel@tonic-gate break;
26857c478bd9Sstevel@tonic-gate }
26867c478bd9Sstevel@tonic-gate mp = head;
26877c478bd9Sstevel@tonic-gate head = head->b_next;
26887c478bd9Sstevel@tonic-gate mp->b_next = NULL;
26897c478bd9Sstevel@tonic-gate putnext(q, mp);
26907c478bd9Sstevel@tonic-gate
26917c478bd9Sstevel@tonic-gate }
26927c478bd9Sstevel@tonic-gate za->za_kick_active = 0;
26937c478bd9Sstevel@tonic-gate
26947c478bd9Sstevel@tonic-gate if (zs->zs_flags & ZS_CLOSED)
26957c478bd9Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv);
26967c478bd9Sstevel@tonic-gate }
26977c478bd9Sstevel@tonic-gate
26987c478bd9Sstevel@tonic-gate /*
26997c478bd9Sstevel@tonic-gate * Retry an "ioctl", now that "bufcall" claims we may be able to allocate
27007c478bd9Sstevel@tonic-gate * the buffer we need.
27017c478bd9Sstevel@tonic-gate */
27027c478bd9Sstevel@tonic-gate static void
zsa_reioctl(void * arg)27037c478bd9Sstevel@tonic-gate zsa_reioctl(void *arg)
27047c478bd9Sstevel@tonic-gate {
27057c478bd9Sstevel@tonic-gate struct asyncline *za = arg;
27067c478bd9Sstevel@tonic-gate struct zscom *zs = za->za_common;
27077c478bd9Sstevel@tonic-gate queue_t *q;
27087c478bd9Sstevel@tonic-gate mblk_t *mp;
27097c478bd9Sstevel@tonic-gate
27107c478bd9Sstevel@tonic-gate /*
27117c478bd9Sstevel@tonic-gate * The bufcall is no longer pending.
27127c478bd9Sstevel@tonic-gate */
27137c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
27147c478bd9Sstevel@tonic-gate if (!za->za_wbufcid) {
27157c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
27167c478bd9Sstevel@tonic-gate return;
27177c478bd9Sstevel@tonic-gate }
27187c478bd9Sstevel@tonic-gate za->za_wbufcid = 0;
27197c478bd9Sstevel@tonic-gate if ((q = za->za_ttycommon.t_writeq) == NULL) {
27207c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
27217c478bd9Sstevel@tonic-gate return;
27227c478bd9Sstevel@tonic-gate }
27237c478bd9Sstevel@tonic-gate if ((mp = za->za_ttycommon.t_iocpending) != NULL) {
27247c478bd9Sstevel@tonic-gate /*
27257c478bd9Sstevel@tonic-gate * not pending any more
27267c478bd9Sstevel@tonic-gate */
27277c478bd9Sstevel@tonic-gate za->za_ttycommon.t_iocpending = NULL;
27287c478bd9Sstevel@tonic-gate zsa_ioctl(za, q, mp);
27297c478bd9Sstevel@tonic-gate }
27307c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
27317c478bd9Sstevel@tonic-gate }
27327c478bd9Sstevel@tonic-gate
27337c478bd9Sstevel@tonic-gate /*
27347c478bd9Sstevel@tonic-gate * Process an "ioctl" message sent down to us.
27357c478bd9Sstevel@tonic-gate * Note that we don't need to get any locks until we are ready to access
27367c478bd9Sstevel@tonic-gate * the hardware. Nothing we access until then is going to be altered
27377c478bd9Sstevel@tonic-gate * outside of the STREAMS framework, so we should be safe.
27387c478bd9Sstevel@tonic-gate */
27397c478bd9Sstevel@tonic-gate static void
zsa_ioctl(struct asyncline * za,queue_t * wq,mblk_t * mp)27407c478bd9Sstevel@tonic-gate zsa_ioctl(struct asyncline *za, queue_t *wq, mblk_t *mp)
27417c478bd9Sstevel@tonic-gate {
27427c478bd9Sstevel@tonic-gate register struct zscom *zs = za->za_common;
27437c478bd9Sstevel@tonic-gate register struct iocblk *iocp;
27447c478bd9Sstevel@tonic-gate register unsigned datasize;
27457c478bd9Sstevel@tonic-gate int error;
27467c478bd9Sstevel@tonic-gate register mblk_t *tmp;
27477c478bd9Sstevel@tonic-gate
27487c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iocpending != NULL) {
27497c478bd9Sstevel@tonic-gate /*
27507c478bd9Sstevel@tonic-gate * We were holding an "ioctl" response pending the
27517c478bd9Sstevel@tonic-gate * availability of an "mblk" to hold data to be passed up;
27527c478bd9Sstevel@tonic-gate * another "ioctl" came through, which means that "ioctl"
27537c478bd9Sstevel@tonic-gate * must have timed out or been aborted.
27547c478bd9Sstevel@tonic-gate */
27557c478bd9Sstevel@tonic-gate freemsg(za->za_ttycommon.t_iocpending);
27567c478bd9Sstevel@tonic-gate za->za_ttycommon.t_iocpending = NULL;
27577c478bd9Sstevel@tonic-gate }
27587c478bd9Sstevel@tonic-gate
27597c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
27607c478bd9Sstevel@tonic-gate
27617c478bd9Sstevel@tonic-gate /*
27627c478bd9Sstevel@tonic-gate * The only way in which "ttycommon_ioctl" can fail is if the "ioctl"
27637c478bd9Sstevel@tonic-gate * requires a response containing data to be returned to the user,
27647c478bd9Sstevel@tonic-gate * and no mblk could be allocated for the data.
27657c478bd9Sstevel@tonic-gate * No such "ioctl" alters our state. Thus, we always go ahead and
27667c478bd9Sstevel@tonic-gate * do any state-changes the "ioctl" calls for. If we couldn't allocate
27677c478bd9Sstevel@tonic-gate * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so
27687c478bd9Sstevel@tonic-gate * we just call "bufcall" to request that we be called back when we
27697c478bd9Sstevel@tonic-gate * stand a better chance of allocating the data.
27707c478bd9Sstevel@tonic-gate */
27717c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
27727c478bd9Sstevel@tonic-gate datasize = ttycommon_ioctl(&za->za_ttycommon, wq, mp, &error);
27737c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
27747c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_flags & TS_SOFTCAR)
27757c478bd9Sstevel@tonic-gate zssoftCAR[zs->zs_unit] = 1;
27767c478bd9Sstevel@tonic-gate else
27777c478bd9Sstevel@tonic-gate zssoftCAR[zs->zs_unit] = 0;
27787c478bd9Sstevel@tonic-gate if (datasize != 0) {
27797c478bd9Sstevel@tonic-gate if (za->za_wbufcid)
27807c478bd9Sstevel@tonic-gate unbufcall(za->za_wbufcid);
27817c478bd9Sstevel@tonic-gate za->za_wbufcid = bufcall(datasize, BPRI_HI, zsa_reioctl, za);
27827c478bd9Sstevel@tonic-gate return;
27837c478bd9Sstevel@tonic-gate }
27847c478bd9Sstevel@tonic-gate
27857c478bd9Sstevel@tonic-gate
27867c478bd9Sstevel@tonic-gate if (error == 0) {
27877c478bd9Sstevel@tonic-gate /*
27887c478bd9Sstevel@tonic-gate * "ttycommon_ioctl" did most of the work; we just use the
27897c478bd9Sstevel@tonic-gate * data it set up.
27907c478bd9Sstevel@tonic-gate */
27917c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
27927c478bd9Sstevel@tonic-gate
27937c478bd9Sstevel@tonic-gate case TCSETS:
27947c478bd9Sstevel@tonic-gate case TCSETSW:
27957c478bd9Sstevel@tonic-gate case TCSETSF:
27967c478bd9Sstevel@tonic-gate case TCSETA:
27977c478bd9Sstevel@tonic-gate case TCSETAW:
27987c478bd9Sstevel@tonic-gate case TCSETAF:
27997c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
28007c478bd9Sstevel@tonic-gate zsa_program(za, 1);
28017c478bd9Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(za);
28027c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
28037c478bd9Sstevel@tonic-gate break;
28047c478bd9Sstevel@tonic-gate }
28057c478bd9Sstevel@tonic-gate } else if (error < 0) {
28067c478bd9Sstevel@tonic-gate /*
28077c478bd9Sstevel@tonic-gate * "ttycommon_ioctl" didn't do anything; we process it here.
28087c478bd9Sstevel@tonic-gate */
28097c478bd9Sstevel@tonic-gate error = 0;
28107c478bd9Sstevel@tonic-gate
28117c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
28127c478bd9Sstevel@tonic-gate
28137c478bd9Sstevel@tonic-gate case TCSBRK:
28147c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int));
28157c478bd9Sstevel@tonic-gate if (error != 0)
28167c478bd9Sstevel@tonic-gate break;
28177c478bd9Sstevel@tonic-gate
28187c478bd9Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr == 0) {
28197c478bd9Sstevel@tonic-gate /*
28207c478bd9Sstevel@tonic-gate * The delay ensures that a 3 byte transmit
28217c478bd9Sstevel@tonic-gate * fifo is empty.
28227c478bd9Sstevel@tonic-gate */
28237c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
28247c478bd9Sstevel@tonic-gate delay(ztdelay(SPEED(za->za_ttycommon.t_cflag)));
28257c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
28267c478bd9Sstevel@tonic-gate
28277c478bd9Sstevel@tonic-gate /*
28287c478bd9Sstevel@tonic-gate * Set the break bit, and arrange for
28297c478bd9Sstevel@tonic-gate * "zsa_restart" to be called in 1/4 second;
28307c478bd9Sstevel@tonic-gate * it will turn the break bit off, and call
28317c478bd9Sstevel@tonic-gate * "zsa_start" to grab the next message.
28327c478bd9Sstevel@tonic-gate */
28337c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
28347c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_BREAK);
28357c478bd9Sstevel@tonic-gate if (!za->za_zsa_restart_id) {
28367c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
28377c478bd9Sstevel@tonic-gate za->za_zsa_restart_id =
28387c478bd9Sstevel@tonic-gate timeout(zsa_restart, zs, hz / 4);
28397c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
28407c478bd9Sstevel@tonic-gate }
28417c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_BREAK;
28427c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
28437c478bd9Sstevel@tonic-gate }
28447c478bd9Sstevel@tonic-gate break;
28457c478bd9Sstevel@tonic-gate
28467c478bd9Sstevel@tonic-gate case TIOCSBRK:
28477c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
28487c478bd9Sstevel@tonic-gate SCC_BIS(5, ZSWR5_BREAK);
28497c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
28507c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
28517c478bd9Sstevel@tonic-gate break;
28527c478bd9Sstevel@tonic-gate
28537c478bd9Sstevel@tonic-gate case TIOCCBRK:
28547c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
28557c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK);
28567c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
28577c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
28587c478bd9Sstevel@tonic-gate break;
28597c478bd9Sstevel@tonic-gate
28607c478bd9Sstevel@tonic-gate case TIOCMSET:
28617c478bd9Sstevel@tonic-gate case TIOCMBIS:
28627c478bd9Sstevel@tonic-gate case TIOCMBIC: {
28637c478bd9Sstevel@tonic-gate int mlines;
28647c478bd9Sstevel@tonic-gate
28657c478bd9Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) {
28667c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (int), NULL);
28677c478bd9Sstevel@tonic-gate break;
28687c478bd9Sstevel@tonic-gate }
28697c478bd9Sstevel@tonic-gate
28707c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int));
28717c478bd9Sstevel@tonic-gate if (error != 0)
28727c478bd9Sstevel@tonic-gate break;
28737c478bd9Sstevel@tonic-gate
28747c478bd9Sstevel@tonic-gate mlines = *(int *)mp->b_cont->b_rptr;
28757c478bd9Sstevel@tonic-gate
28767c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
28777c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
28787c478bd9Sstevel@tonic-gate case TIOCMSET:
28797c478bd9Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(mlines), DMSET);
28807c478bd9Sstevel@tonic-gate break;
28817c478bd9Sstevel@tonic-gate case TIOCMBIS:
28827c478bd9Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(mlines), DMBIS);
28837c478bd9Sstevel@tonic-gate break;
28847c478bd9Sstevel@tonic-gate case TIOCMBIC:
28857c478bd9Sstevel@tonic-gate (void) zsmctl(zs, dmtozs(mlines), DMBIC);
28867c478bd9Sstevel@tonic-gate break;
28877c478bd9Sstevel@tonic-gate }
28887c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
28897c478bd9Sstevel@tonic-gate
28907c478bd9Sstevel@tonic-gate mioc2ack(mp, NULL, 0, 0);
28917c478bd9Sstevel@tonic-gate break;
28927c478bd9Sstevel@tonic-gate }
28937c478bd9Sstevel@tonic-gate
28947c478bd9Sstevel@tonic-gate case TIOCMGET:
28957c478bd9Sstevel@tonic-gate tmp = allocb(sizeof (int), BPRI_MED);
28967c478bd9Sstevel@tonic-gate if (tmp == NULL) {
28977c478bd9Sstevel@tonic-gate error = EAGAIN;
28987c478bd9Sstevel@tonic-gate break;
28997c478bd9Sstevel@tonic-gate }
29007c478bd9Sstevel@tonic-gate if (iocp->ioc_count != TRANSPARENT)
29017c478bd9Sstevel@tonic-gate mioc2ack(mp, tmp, sizeof (int), 0);
29027c478bd9Sstevel@tonic-gate else
29037c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (int), NULL, tmp);
29047c478bd9Sstevel@tonic-gate
29057c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
29067c478bd9Sstevel@tonic-gate *(int *)mp->b_cont->b_rptr =
29077c478bd9Sstevel@tonic-gate zstodm(zsmctl(zs, 0, DMGET));
29087c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
29097c478bd9Sstevel@tonic-gate /*
29107c478bd9Sstevel@tonic-gate * qreply done below
29117c478bd9Sstevel@tonic-gate */
29127c478bd9Sstevel@tonic-gate break;
29137c478bd9Sstevel@tonic-gate
29147c478bd9Sstevel@tonic-gate default:
29157c478bd9Sstevel@tonic-gate /*
29167c478bd9Sstevel@tonic-gate * If we don't understand it, it's an error. NAK it.
29177c478bd9Sstevel@tonic-gate */
29187c478bd9Sstevel@tonic-gate error = EINVAL;
29197c478bd9Sstevel@tonic-gate break;
29207c478bd9Sstevel@tonic-gate }
29217c478bd9Sstevel@tonic-gate }
29227c478bd9Sstevel@tonic-gate
29237c478bd9Sstevel@tonic-gate if (error != 0) {
29247c478bd9Sstevel@tonic-gate iocp->ioc_error = error;
29257c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK;
29267c478bd9Sstevel@tonic-gate }
29277c478bd9Sstevel@tonic-gate
29287c478bd9Sstevel@tonic-gate ZSA_QREPLY(wq, mp);
29297c478bd9Sstevel@tonic-gate }
29307c478bd9Sstevel@tonic-gate
29317c478bd9Sstevel@tonic-gate
29327c478bd9Sstevel@tonic-gate static int
dmtozs(int bits)29337c478bd9Sstevel@tonic-gate dmtozs(int bits)
29347c478bd9Sstevel@tonic-gate {
29357c478bd9Sstevel@tonic-gate register int b = 0;
29367c478bd9Sstevel@tonic-gate
29377c478bd9Sstevel@tonic-gate if (bits & TIOCM_CAR)
29387c478bd9Sstevel@tonic-gate b |= ZSRR0_CD;
29397c478bd9Sstevel@tonic-gate if (bits & TIOCM_CTS)
29407c478bd9Sstevel@tonic-gate b |= ZSRR0_CTS;
29417c478bd9Sstevel@tonic-gate if (bits & TIOCM_RTS)
29427c478bd9Sstevel@tonic-gate b |= ZSWR5_RTS;
29437c478bd9Sstevel@tonic-gate if (bits & TIOCM_DTR)
29447c478bd9Sstevel@tonic-gate b |= ZSWR5_DTR;
29457c478bd9Sstevel@tonic-gate return (b);
29467c478bd9Sstevel@tonic-gate }
29477c478bd9Sstevel@tonic-gate
29487c478bd9Sstevel@tonic-gate static int
zstodm(int bits)29497c478bd9Sstevel@tonic-gate zstodm(int bits)
29507c478bd9Sstevel@tonic-gate {
29517c478bd9Sstevel@tonic-gate register int b;
29527c478bd9Sstevel@tonic-gate
29537c478bd9Sstevel@tonic-gate b = 0;
29547c478bd9Sstevel@tonic-gate if (bits & ZSRR0_CD)
29557c478bd9Sstevel@tonic-gate b |= TIOCM_CAR;
29567c478bd9Sstevel@tonic-gate if (bits & ZSRR0_CTS)
29577c478bd9Sstevel@tonic-gate b |= TIOCM_CTS;
29587c478bd9Sstevel@tonic-gate if (bits & ZSWR5_RTS)
29597c478bd9Sstevel@tonic-gate b |= TIOCM_RTS;
29607c478bd9Sstevel@tonic-gate if (bits & ZSWR5_DTR)
29617c478bd9Sstevel@tonic-gate b |= TIOCM_DTR;
29627c478bd9Sstevel@tonic-gate return (b);
29637c478bd9Sstevel@tonic-gate }
29647c478bd9Sstevel@tonic-gate
29657c478bd9Sstevel@tonic-gate /*
29667c478bd9Sstevel@tonic-gate * Assemble registers and flags necessary to program the port to our liking.
29677c478bd9Sstevel@tonic-gate * For async operation, most of this is based on the values of
29687c478bd9Sstevel@tonic-gate * the "c_iflag" and "c_cflag" fields supplied to us.
29697c478bd9Sstevel@tonic-gate */
29707c478bd9Sstevel@tonic-gate static void
zsa_program(struct asyncline * za,int setibaud)29717c478bd9Sstevel@tonic-gate zsa_program(struct asyncline *za, int setibaud)
29727c478bd9Sstevel@tonic-gate {
29737c478bd9Sstevel@tonic-gate register struct zscom *zs = za->za_common;
29747c478bd9Sstevel@tonic-gate register struct zs_prog *zspp;
29757c478bd9Sstevel@tonic-gate register int wr3, wr4, wr5, wr15, speed, baudrate, flags = 0;
29767c478bd9Sstevel@tonic-gate
29777c478bd9Sstevel@tonic-gate if ((baudrate = SPEED(za->za_ttycommon.t_cflag)) == 0) {
29787c478bd9Sstevel@tonic-gate /*
29797c478bd9Sstevel@tonic-gate * Hang up line.
29807c478bd9Sstevel@tonic-gate */
29817c478bd9Sstevel@tonic-gate (void) zsmctl(zs, ZS_OFF, DMSET);
29827c478bd9Sstevel@tonic-gate return;
29837c478bd9Sstevel@tonic-gate }
29847c478bd9Sstevel@tonic-gate
29857c478bd9Sstevel@tonic-gate /*
29867c478bd9Sstevel@tonic-gate * set input speed same as output, as split speed not supported
29877c478bd9Sstevel@tonic-gate */
29887c478bd9Sstevel@tonic-gate if (setibaud) {
29897c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~(CIBAUD);
29907c478bd9Sstevel@tonic-gate if (baudrate > CBAUD) {
29917c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag |= CIBAUDEXT;
29927c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag |=
29937c478bd9Sstevel@tonic-gate (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);
29947c478bd9Sstevel@tonic-gate } else {
29957c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag &= ~CIBAUDEXT;
29967c478bd9Sstevel@tonic-gate za->za_ttycommon.t_cflag |=
29977c478bd9Sstevel@tonic-gate ((baudrate << IBSHIFT) & CIBAUD);
29987c478bd9Sstevel@tonic-gate }
29997c478bd9Sstevel@tonic-gate }
30007c478bd9Sstevel@tonic-gate
30017c478bd9Sstevel@tonic-gate /*
30027c478bd9Sstevel@tonic-gate * Do not allow the console/keyboard device to have its receiver
30037c478bd9Sstevel@tonic-gate * disabled; doing that would mean you couldn't type an abort
30047c478bd9Sstevel@tonic-gate * sequence.
30057c478bd9Sstevel@tonic-gate */
30067c478bd9Sstevel@tonic-gate if ((za->za_dev == rconsdev) || (za->za_dev == kbddev) ||
30077c478bd9Sstevel@tonic-gate (za->za_dev == stdindev) || (za->za_ttycommon.t_cflag & CREAD))
30087c478bd9Sstevel@tonic-gate wr3 = ZSWR3_RX_ENABLE;
30097c478bd9Sstevel@tonic-gate else
30107c478bd9Sstevel@tonic-gate wr3 = 0;
30117c478bd9Sstevel@tonic-gate wr4 = ZSWR4_X16_CLK;
30127c478bd9Sstevel@tonic-gate wr5 = (zs->zs_wreg[5] & (ZSWR5_RTS|ZSWR5_DTR)) | ZSWR5_TX_ENABLE;
30137c478bd9Sstevel@tonic-gate
30147c478bd9Sstevel@tonic-gate if (zsb134_weird && baudrate == B134) { /* what a joke! */
30157c478bd9Sstevel@tonic-gate /*
30167c478bd9Sstevel@tonic-gate * XXX - should B134 set all this crap in the compatibility
30177c478bd9Sstevel@tonic-gate * module, leaving this stuff fairly clean?
30187c478bd9Sstevel@tonic-gate */
30197c478bd9Sstevel@tonic-gate flags |= ZSP_PARITY_SPECIAL;
30207c478bd9Sstevel@tonic-gate wr3 |= ZSWR3_RX_6;
30217c478bd9Sstevel@tonic-gate wr4 |= ZSWR4_PARITY_ENABLE | ZSWR4_PARITY_EVEN;
30227c478bd9Sstevel@tonic-gate wr4 |= ZSWR4_1_5_STOP;
30237c478bd9Sstevel@tonic-gate wr5 |= ZSWR5_TX_6;
30247c478bd9Sstevel@tonic-gate } else {
30257c478bd9Sstevel@tonic-gate
30267c478bd9Sstevel@tonic-gate switch (za->za_ttycommon.t_cflag & CSIZE) {
30277c478bd9Sstevel@tonic-gate
30287c478bd9Sstevel@tonic-gate case CS5:
30297c478bd9Sstevel@tonic-gate wr3 |= ZSWR3_RX_5;
30307c478bd9Sstevel@tonic-gate wr5 |= ZSWR5_TX_5;
30317c478bd9Sstevel@tonic-gate break;
30327c478bd9Sstevel@tonic-gate
30337c478bd9Sstevel@tonic-gate case CS6:
30347c478bd9Sstevel@tonic-gate wr3 |= ZSWR3_RX_6;
30357c478bd9Sstevel@tonic-gate wr5 |= ZSWR5_TX_6;
30367c478bd9Sstevel@tonic-gate break;
30377c478bd9Sstevel@tonic-gate
30387c478bd9Sstevel@tonic-gate case CS7:
30397c478bd9Sstevel@tonic-gate wr3 |= ZSWR3_RX_7;
30407c478bd9Sstevel@tonic-gate wr5 |= ZSWR5_TX_7;
30417c478bd9Sstevel@tonic-gate break;
30427c478bd9Sstevel@tonic-gate
30437c478bd9Sstevel@tonic-gate case CS8:
30447c478bd9Sstevel@tonic-gate wr3 |= ZSWR3_RX_8;
30457c478bd9Sstevel@tonic-gate wr5 |= ZSWR5_TX_8;
30467c478bd9Sstevel@tonic-gate break;
30477c478bd9Sstevel@tonic-gate }
30487c478bd9Sstevel@tonic-gate
30497c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARENB) {
30507c478bd9Sstevel@tonic-gate /*
30517c478bd9Sstevel@tonic-gate * The PARITY_SPECIAL bit causes a special rx
30527c478bd9Sstevel@tonic-gate * interrupt on parity errors. Turn it on if
30537c478bd9Sstevel@tonic-gate * we're checking the parity of characters.
30547c478bd9Sstevel@tonic-gate */
30557c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & INPCK)
30567c478bd9Sstevel@tonic-gate flags |= ZSP_PARITY_SPECIAL;
30577c478bd9Sstevel@tonic-gate wr4 |= ZSWR4_PARITY_ENABLE;
30587c478bd9Sstevel@tonic-gate if (!(za->za_ttycommon.t_cflag & PARODD))
30597c478bd9Sstevel@tonic-gate wr4 |= ZSWR4_PARITY_EVEN;
30607c478bd9Sstevel@tonic-gate }
30617c478bd9Sstevel@tonic-gate wr4 |= (za->za_ttycommon.t_cflag & CSTOPB) ?
30627c478bd9Sstevel@tonic-gate ZSWR4_2_STOP : ZSWR4_1_STOP;
30637c478bd9Sstevel@tonic-gate }
30647c478bd9Sstevel@tonic-gate
30657c478bd9Sstevel@tonic-gate #if 0
30667c478bd9Sstevel@tonic-gate /*
30677c478bd9Sstevel@tonic-gate * The AUTO_CD_CTS flag enables the hardware flow control feature of
30687c478bd9Sstevel@tonic-gate * the 8530, which allows the state of CTS and DCD to control the
30697c478bd9Sstevel@tonic-gate * enabling of the transmitter and receiver, respectively. The
30707c478bd9Sstevel@tonic-gate * receiver and transmitter still must have their enable bits set in
30717c478bd9Sstevel@tonic-gate * WR3 and WR5, respectively, for CTS and DCD to be monitored this way.
30727c478bd9Sstevel@tonic-gate * Hardware flow control can thus be implemented with no help from
30737c478bd9Sstevel@tonic-gate * software.
30747c478bd9Sstevel@tonic-gate */
30757c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS)
30767c478bd9Sstevel@tonic-gate wr3 |= ZSWR3_AUTO_CD_CTS;
30777c478bd9Sstevel@tonic-gate #endif
30787c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CRTSCTS)
30797c478bd9Sstevel@tonic-gate wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD | ZSR15_CTS;
30807c478bd9Sstevel@tonic-gate else
30817c478bd9Sstevel@tonic-gate wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD;
30827c478bd9Sstevel@tonic-gate
30837c478bd9Sstevel@tonic-gate speed = zs->zs_wreg[12] + (zs->zs_wreg[13] << 8);
30847c478bd9Sstevel@tonic-gate
30857c478bd9Sstevel@tonic-gate /*
30867c478bd9Sstevel@tonic-gate * Here we assemble a set of changes to be passed to zs_program.
30877c478bd9Sstevel@tonic-gate * Note: Write Register 15 must be set to enable BREAK and UNDERrun
30887c478bd9Sstevel@tonic-gate * interrupts. It must also enable CD interrupts which, although
30897c478bd9Sstevel@tonic-gate * not processed by the hardware interrupt handler, will be processed
30907c478bd9Sstevel@tonic-gate * by zsa_process, indirectly resulting in a SIGHUP being delivered
30917c478bd9Sstevel@tonic-gate * to the controlling process if CD drops. CTS interrupts must NOT
30927c478bd9Sstevel@tonic-gate * be enabled. We don't use them at all, and they will hang IPC/IPX
30937c478bd9Sstevel@tonic-gate * systems at boot time if synchronous modems that supply transmit
30947c478bd9Sstevel@tonic-gate * clock are attached to any of their serial ports.
30957c478bd9Sstevel@tonic-gate */
30967c478bd9Sstevel@tonic-gate if (((zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) &&
30977c478bd9Sstevel@tonic-gate !(flags & ZSP_PARITY_SPECIAL)) ||
30987c478bd9Sstevel@tonic-gate (!(zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) &&
30997c478bd9Sstevel@tonic-gate (flags & ZSP_PARITY_SPECIAL)) ||
31007c478bd9Sstevel@tonic-gate wr3 != zs->zs_wreg[3] || wr4 != zs->zs_wreg[4] ||
31017c478bd9Sstevel@tonic-gate wr5 != zs->zs_wreg[5] || wr15 != zs->zs_wreg[15] ||
31027c478bd9Sstevel@tonic-gate speed != zs_speeds[baudrate]) {
31037c478bd9Sstevel@tonic-gate
31047c478bd9Sstevel@tonic-gate za->za_flags |= ZAS_DRAINING;
31057c478bd9Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit];
31067c478bd9Sstevel@tonic-gate zspp->zs = zs;
31077c478bd9Sstevel@tonic-gate zspp->flags = (uchar_t)flags;
31087c478bd9Sstevel@tonic-gate zspp->wr4 = (uchar_t)wr4;
31097c478bd9Sstevel@tonic-gate zspp->wr11 = (uchar_t)(ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD);
31107c478bd9Sstevel@tonic-gate
31117c478bd9Sstevel@tonic-gate speed = zs_speeds[baudrate];
31127c478bd9Sstevel@tonic-gate zspp->wr12 = (uchar_t)(speed & 0xff);
31137c478bd9Sstevel@tonic-gate zspp->wr13 = (uchar_t)((speed >> 8) & 0xff);
31147c478bd9Sstevel@tonic-gate zspp->wr3 = (uchar_t)wr3;
31157c478bd9Sstevel@tonic-gate zspp->wr5 = (uchar_t)wr5;
31167c478bd9Sstevel@tonic-gate zspp->wr15 = (uchar_t)wr15;
31177c478bd9Sstevel@tonic-gate
31187c478bd9Sstevel@tonic-gate zs_program(zspp);
31197c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_DRAINING;
31207c478bd9Sstevel@tonic-gate }
31217c478bd9Sstevel@tonic-gate }
31227c478bd9Sstevel@tonic-gate
31237c478bd9Sstevel@tonic-gate /*
31247c478bd9Sstevel@tonic-gate * Get the current speed of the console and turn it into something
31257c478bd9Sstevel@tonic-gate * UNIX knows about - used to preserve console speed when UNIX comes up.
31267c478bd9Sstevel@tonic-gate */
31277c478bd9Sstevel@tonic-gate int
zsgetspeed(dev_t dev)31287c478bd9Sstevel@tonic-gate zsgetspeed(dev_t dev)
31297c478bd9Sstevel@tonic-gate {
31307c478bd9Sstevel@tonic-gate register struct zscom *zs;
31317c478bd9Sstevel@tonic-gate register int uspeed, zspeed;
31327c478bd9Sstevel@tonic-gate register uchar_t rr;
31337c478bd9Sstevel@tonic-gate
31347c478bd9Sstevel@tonic-gate zs = &zscom[UNIT(dev)];
31357c478bd9Sstevel@tonic-gate SCC_READ(12, zspeed);
31367c478bd9Sstevel@tonic-gate SCC_READ(13, rr);
31377c478bd9Sstevel@tonic-gate zspeed |= rr << 8;
31387c478bd9Sstevel@tonic-gate for (uspeed = 0; uspeed < NSPEED; uspeed++)
31397c478bd9Sstevel@tonic-gate if (zs_speeds[uspeed] == zspeed)
31407c478bd9Sstevel@tonic-gate return (uspeed);
31417c478bd9Sstevel@tonic-gate /*
31427c478bd9Sstevel@tonic-gate * 9600 baud if we can't figure it out
31437c478bd9Sstevel@tonic-gate */
31447c478bd9Sstevel@tonic-gate return (ISPEED);
31457c478bd9Sstevel@tonic-gate }
31467c478bd9Sstevel@tonic-gate
31477c478bd9Sstevel@tonic-gate /*
31487c478bd9Sstevel@tonic-gate * callback routine when enough memory is available.
31497c478bd9Sstevel@tonic-gate */
31507c478bd9Sstevel@tonic-gate static void
zsa_callback(void * arg)31517c478bd9Sstevel@tonic-gate zsa_callback(void *arg)
31527c478bd9Sstevel@tonic-gate {
31537c478bd9Sstevel@tonic-gate struct zscom *zs = arg;
31547c478bd9Sstevel@tonic-gate struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
31557c478bd9Sstevel@tonic-gate int allocbcount = zsa_rstandby;
31567c478bd9Sstevel@tonic-gate
31577c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
31587c478bd9Sstevel@tonic-gate if (za->za_bufcid) {
31597c478bd9Sstevel@tonic-gate za->za_bufcid = 0;
31607c478bd9Sstevel@tonic-gate ZSA_GETBLOCK(zs, allocbcount);
31617c478bd9Sstevel@tonic-gate }
31627c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
31637c478bd9Sstevel@tonic-gate }
31647c478bd9Sstevel@tonic-gate
31657c478bd9Sstevel@tonic-gate /*
31667c478bd9Sstevel@tonic-gate * Set the receiver flags
31677c478bd9Sstevel@tonic-gate */
31687c478bd9Sstevel@tonic-gate static void
zsa_set_za_rcv_flags_mask(struct asyncline * za)31697c478bd9Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(struct asyncline *za)
31707c478bd9Sstevel@tonic-gate {
31717c478bd9Sstevel@tonic-gate register uint_t mask;
31727c478bd9Sstevel@tonic-gate
31737c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~0xFF;
31747c478bd9Sstevel@tonic-gate switch (za->za_ttycommon.t_cflag & CSIZE) {
31757c478bd9Sstevel@tonic-gate case CS5:
31767c478bd9Sstevel@tonic-gate mask = 0x1f;
31777c478bd9Sstevel@tonic-gate break;
31787c478bd9Sstevel@tonic-gate case CS6:
31797c478bd9Sstevel@tonic-gate mask = 0x3f;
31807c478bd9Sstevel@tonic-gate break;
31817c478bd9Sstevel@tonic-gate case CS7:
31827c478bd9Sstevel@tonic-gate mask = 0x7f;
31837c478bd9Sstevel@tonic-gate break;
31847c478bd9Sstevel@tonic-gate default:
31857c478bd9Sstevel@tonic-gate mask = 0xff;
31867c478bd9Sstevel@tonic-gate }
31877c478bd9Sstevel@tonic-gate
31887c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~(0xFF << 16);
31897c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= mask << 16;
31907c478bd9Sstevel@tonic-gate
31917c478bd9Sstevel@tonic-gate if ((za->za_ttycommon.t_iflag & PARMRK) &&
31927c478bd9Sstevel@tonic-gate !(za->za_ttycommon.t_iflag & (IGNPAR|ISTRIP))) {
31937c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_ESC;
31947c478bd9Sstevel@tonic-gate } else
31957c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_ESC;
31967c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IXON) {
31977c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_STOPC;
31987c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~0xFF;
31997c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= za->za_ttycommon.t_stopc;
32007c478bd9Sstevel@tonic-gate } else
32017c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_STOPC;
32027c478bd9Sstevel@tonic-gate }
32037c478bd9Sstevel@tonic-gate
32047c478bd9Sstevel@tonic-gate static int
zsa_suspend(struct zscom * zs)32057c478bd9Sstevel@tonic-gate zsa_suspend(struct zscom *zs)
32067c478bd9Sstevel@tonic-gate {
32077c478bd9Sstevel@tonic-gate struct asyncline *za;
32087c478bd9Sstevel@tonic-gate queue_t *q;
32097c478bd9Sstevel@tonic-gate mblk_t *bp = NULL;
32107c478bd9Sstevel@tonic-gate timeout_id_t restart_id, kick_rcv_id;
32117c478bd9Sstevel@tonic-gate struct zs_prog *zspp;
32127c478bd9Sstevel@tonic-gate
32137c478bd9Sstevel@tonic-gate za = (struct asyncline *)&zs->zs_priv_str;
32147c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
32157c478bd9Sstevel@tonic-gate if (zs->zs_suspended) {
32167c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
32177c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
32187c478bd9Sstevel@tonic-gate }
32197c478bd9Sstevel@tonic-gate zs->zs_suspended = 1;
32207c478bd9Sstevel@tonic-gate
32217c478bd9Sstevel@tonic-gate /*
32227c478bd9Sstevel@tonic-gate * Turn off interrupts and get any bytes in receiver
32237c478bd9Sstevel@tonic-gate */
32247c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
32257c478bd9Sstevel@tonic-gate SCC_BIC(1, ZSWR1_INIT);
32267c478bd9Sstevel@tonic-gate ZSA_KICK_RCV;
32277c478bd9Sstevel@tonic-gate restart_id = za->za_zsa_restart_id;
32287c478bd9Sstevel@tonic-gate za->za_zsa_restart_id = 0;
32297c478bd9Sstevel@tonic-gate kick_rcv_id = za->za_kick_rcv_id;
32307c478bd9Sstevel@tonic-gate za->za_kick_rcv_id = 0;
32317c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
32327c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
32337c478bd9Sstevel@tonic-gate
32347c478bd9Sstevel@tonic-gate /*
32357c478bd9Sstevel@tonic-gate * Cancel any timeouts
32367c478bd9Sstevel@tonic-gate */
32377c478bd9Sstevel@tonic-gate if (restart_id)
32387c478bd9Sstevel@tonic-gate (void) untimeout(restart_id);
32397c478bd9Sstevel@tonic-gate if (kick_rcv_id)
32407c478bd9Sstevel@tonic-gate (void) untimeout(kick_rcv_id);
32417c478bd9Sstevel@tonic-gate
32427c478bd9Sstevel@tonic-gate /*
32437c478bd9Sstevel@tonic-gate * Since we have turned off interrupts, zsa_txint will not be called
32447c478bd9Sstevel@tonic-gate * and no new chars will given to the chip. We just wait for the
32457c478bd9Sstevel@tonic-gate * current character(s) to drain.
32467c478bd9Sstevel@tonic-gate */
32477c478bd9Sstevel@tonic-gate delay(ztdelay(za->za_ttycommon.t_cflag & CBAUD));
32487c478bd9Sstevel@tonic-gate
32497c478bd9Sstevel@tonic-gate /*
32507c478bd9Sstevel@tonic-gate * Return remains of partially sent message to queue
32517c478bd9Sstevel@tonic-gate */
32527c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
32537c478bd9Sstevel@tonic-gate if ((q = za->za_ttycommon.t_writeq) != NULL) {
32547c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
32557c478bd9Sstevel@tonic-gate if ((zs->zs_wr_cur) != NULL) {
32567c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_BUSY;
32577c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
32587c478bd9Sstevel@tonic-gate bp = za->za_xmitblk;
32597c478bd9Sstevel@tonic-gate bp->b_rptr = zs->zs_wr_cur;
32607c478bd9Sstevel@tonic-gate zs->zs_wr_cur = NULL;
32617c478bd9Sstevel@tonic-gate zs->zs_wr_lim = NULL;
32627c478bd9Sstevel@tonic-gate za->za_xmitblk = NULL;
32637c478bd9Sstevel@tonic-gate }
32647c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
32657c478bd9Sstevel@tonic-gate if (bp)
32667c478bd9Sstevel@tonic-gate (void) putbq(q, bp);
32677c478bd9Sstevel@tonic-gate }
32687c478bd9Sstevel@tonic-gate
32697c478bd9Sstevel@tonic-gate /*
32707c478bd9Sstevel@tonic-gate * Stop any breaks in progress.
32717c478bd9Sstevel@tonic-gate */
32727c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
32737c478bd9Sstevel@tonic-gate if (zs->zs_wreg[5] & ZSWR5_BREAK) {
32747c478bd9Sstevel@tonic-gate SCC_BIC(5, ZSWR5_BREAK);
32757c478bd9Sstevel@tonic-gate za->za_flags &= ~ZAS_BREAK;
32767c478bd9Sstevel@tonic-gate }
32777c478bd9Sstevel@tonic-gate
32787c478bd9Sstevel@tonic-gate /*
32797c478bd9Sstevel@tonic-gate * Now get a copy of current registers setting.
32807c478bd9Sstevel@tonic-gate */
32817c478bd9Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit];
32827c478bd9Sstevel@tonic-gate zspp->zs = zs;
32837c478bd9Sstevel@tonic-gate zspp->flags = 0;
32847c478bd9Sstevel@tonic-gate zspp->wr3 = zs->zs_wreg[3];
32857c478bd9Sstevel@tonic-gate zspp->wr4 = zs->zs_wreg[4];
32867c478bd9Sstevel@tonic-gate zspp->wr5 = zs->zs_wreg[5];
32877c478bd9Sstevel@tonic-gate zspp->wr11 = zs->zs_wreg[11];
32887c478bd9Sstevel@tonic-gate zspp->wr12 = zs->zs_wreg[12];
32897c478bd9Sstevel@tonic-gate zspp->wr13 = zs->zs_wreg[13];
32907c478bd9Sstevel@tonic-gate zspp->wr15 = zs->zs_wreg[15];
32917c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
32927c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
32937c478bd9Sstevel@tonic-gate /*
32947c478bd9Sstevel@tonic-gate * We do this on the off chance that zsa_close is waiting on a timed
32957c478bd9Sstevel@tonic-gate * break to complete and nothing else.
32967c478bd9Sstevel@tonic-gate */
32977c478bd9Sstevel@tonic-gate cv_broadcast(&zs->zs_flags_cv);
32987c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
32997c478bd9Sstevel@tonic-gate }
33007c478bd9Sstevel@tonic-gate
33017c478bd9Sstevel@tonic-gate static int
zsa_resume(struct zscom * zs)33027c478bd9Sstevel@tonic-gate zsa_resume(struct zscom *zs)
33037c478bd9Sstevel@tonic-gate {
33047c478bd9Sstevel@tonic-gate register struct asyncline *za;
33057c478bd9Sstevel@tonic-gate struct zs_prog *zspp;
33067c478bd9Sstevel@tonic-gate
33077c478bd9Sstevel@tonic-gate za = (struct asyncline *)&zs->zs_priv_str;
33087c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl);
33097c478bd9Sstevel@tonic-gate if (!(zs->zs_suspended)) {
33107c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
33117c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
33127c478bd9Sstevel@tonic-gate }
33137c478bd9Sstevel@tonic-gate
33147c478bd9Sstevel@tonic-gate /*
33157c478bd9Sstevel@tonic-gate * Restore H/W state
33167c478bd9Sstevel@tonic-gate */
33177c478bd9Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi);
33187c478bd9Sstevel@tonic-gate zspp = &zs_prog[zs->zs_unit];
33197c478bd9Sstevel@tonic-gate zs_program(zspp);
33207c478bd9Sstevel@tonic-gate
33217c478bd9Sstevel@tonic-gate /*
33227c478bd9Sstevel@tonic-gate * Enable all interrupts for this chip and delay to let chip settle
33237c478bd9Sstevel@tonic-gate */
33247c478bd9Sstevel@tonic-gate SCC_WRITE(9, ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT);
33257c478bd9Sstevel@tonic-gate DELAY(4000);
33267c478bd9Sstevel@tonic-gate
33277c478bd9Sstevel@tonic-gate /*
33287c478bd9Sstevel@tonic-gate * Restart receiving and transmitting
33297c478bd9Sstevel@tonic-gate */
33307c478bd9Sstevel@tonic-gate zs->zs_suspended = 0;
33317c478bd9Sstevel@tonic-gate za->za_rcv_flags_mask |= DO_TRANSMIT;
33327c478bd9Sstevel@tonic-gate za->za_ext = 1;
33337c478bd9Sstevel@tonic-gate ZSSETSOFT(zs);
33347c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi);
33357c478bd9Sstevel@tonic-gate mutex_exit(zs->zs_excl);
33367c478bd9Sstevel@tonic-gate
33377c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
33387c478bd9Sstevel@tonic-gate }
33397c478bd9Sstevel@tonic-gate
33407c478bd9Sstevel@tonic-gate #ifdef ZSA_DEBUG
33417c478bd9Sstevel@tonic-gate static void
zsa_print_info(struct zscom * zs)33427c478bd9Sstevel@tonic-gate zsa_print_info(struct zscom *zs)
33437c478bd9Sstevel@tonic-gate {
33447c478bd9Sstevel@tonic-gate register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
33457c478bd9Sstevel@tonic-gate register queue_t *q = za->za_ttycommon.t_writeq;
33467c478bd9Sstevel@tonic-gate
33477c478bd9Sstevel@tonic-gate printf(" next q=%s\n", (RD(q))->q_next->q_qinfo->qi_minfo->mi_idname);
33487c478bd9Sstevel@tonic-gate printf("unit=%d\n", zs->zs_unit);
33497c478bd9Sstevel@tonic-gate printf("tflag:\n");
33507c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_flags & TS_SOFTCAR) printf(" t_fl:TS_SOFTCAR");
33517c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_flags & TS_XCLUDE) printf(" t_fl:TS_XCLUDE");
33527c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IGNBRK) printf(" t_ifl:IGNBRK");
33537c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & BRKINT) printf(" t_ifl:BRKINT");
33547c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IGNPAR) printf(" t_ifl:IGNPAR");
33557c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & PARMRK) printf(" t_ifl:PARMRK");
33567c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & INPCK) printf(" t_ifl:INPCK");
33577c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & ISTRIP) printf(" t_ifl:ISTRIP");
33587c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & INLCR) printf(" t_ifl:INLCR");
33597c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IGNCR) printf(" t_ifl:IGNCR");
33607c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & ICRNL) printf(" t_ifl:ICRNL");
33617c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IUCLC) printf(" t_ifl:IUCLC");
33627c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IXON) printf(" t_ifl:IXON");
33637c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_iflag & IXOFF) printf(" t_ifl:IXOFF");
33647c478bd9Sstevel@tonic-gate
33657c478bd9Sstevel@tonic-gate printf("\n");
33667c478bd9Sstevel@tonic-gate
33677c478bd9Sstevel@tonic-gate
33687c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS5) printf(" t_cfl:CS5");
33697c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS6) printf(" t_cfl:CS6");
33707c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS7) printf(" t_cfl:CS7");
33717c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSIZE == CS8) printf(" t_cfl:CS8");
33727c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CSTOPB) printf(" t_cfl:CSTOPB");
33737c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CREAD) printf(" t_cfl:CREAD");
33747c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARENB) printf(" t_cfl:PARENB");
33757c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & PARODD) printf(" t_cfl:PARODD");
33767c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & HUPCL) printf(" t_cfl:HUPCL");
33777c478bd9Sstevel@tonic-gate if (za->za_ttycommon.t_cflag & CLOCAL) printf(" t_cfl:CLOCAL");
33787c478bd9Sstevel@tonic-gate printf(" t_stopc=%x", za->za_ttycommon.t_stopc);
33797c478bd9Sstevel@tonic-gate printf("\n");
33807c478bd9Sstevel@tonic-gate }
33817c478bd9Sstevel@tonic-gate #endif
33827c478bd9Sstevel@tonic-gate
33837c478bd9Sstevel@tonic-gate /*
33847c478bd9Sstevel@tonic-gate * Check for abort character sequence
33857c478bd9Sstevel@tonic-gate */
33867c478bd9Sstevel@tonic-gate static boolean_t
abort_charseq_recognize(uchar_t ch)33877c478bd9Sstevel@tonic-gate abort_charseq_recognize(uchar_t ch)
33887c478bd9Sstevel@tonic-gate {
33897c478bd9Sstevel@tonic-gate static int state = 0;
33907c478bd9Sstevel@tonic-gate #define CNTRL(c) ((c)&037)
33917c478bd9Sstevel@tonic-gate static char sequence[] = { '\r', '~', CNTRL('b') };
33927c478bd9Sstevel@tonic-gate
33937c478bd9Sstevel@tonic-gate if (ch == sequence[state]) {
33947c478bd9Sstevel@tonic-gate if (++state >= sizeof (sequence)) {
33957c478bd9Sstevel@tonic-gate state = 0;
33967c478bd9Sstevel@tonic-gate return (B_TRUE);
33977c478bd9Sstevel@tonic-gate }
33987c478bd9Sstevel@tonic-gate } else {
33997c478bd9Sstevel@tonic-gate state = (ch == sequence[0]) ? 1 : 0;
34007c478bd9Sstevel@tonic-gate }
34017c478bd9Sstevel@tonic-gate return (B_FALSE);
34027c478bd9Sstevel@tonic-gate }
3403