17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* 77c478bd9Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 87c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 97c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 107c478bd9Sstevel@tonic-gate */ 117c478bd9Sstevel@tonic-gate 127c478bd9Sstevel@tonic-gate #include <sys/types.h> 137c478bd9Sstevel@tonic-gate #include <sys/param.h> 147c478bd9Sstevel@tonic-gate #include <sys/signal.h> 157c478bd9Sstevel@tonic-gate #include <sys/systm.h> 167c478bd9Sstevel@tonic-gate #include <sys/termio.h> 177c478bd9Sstevel@tonic-gate #include <sys/ttold.h> 187c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 197c478bd9Sstevel@tonic-gate #include <sys/stream.h> 207c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 217c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 227c478bd9Sstevel@tonic-gate #include <sys/tty.h> 237c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 247c478bd9Sstevel@tonic-gate #include <sys/errno.h> 257c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 267c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 277c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * The default (sane) set of termios values, unless 317c478bd9Sstevel@tonic-gate * otherwise set by the user. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate static struct termios default_termios = { 347c478bd9Sstevel@tonic-gate BRKINT|ICRNL|IXON|IMAXBEL, /* c_iflag */ 357c478bd9Sstevel@tonic-gate OPOST|ONLCR|TAB3, /* c_oflag */ 367c478bd9Sstevel@tonic-gate B9600|CS8|CREAD, /* c_cflag */ 377c478bd9Sstevel@tonic-gate ISIG|ICANON|IEXTEN|ECHO|ECHOK|ECHOE|ECHOKE|ECHOCTL, /* c_lflag */ 387c478bd9Sstevel@tonic-gate { 397c478bd9Sstevel@tonic-gate CINTR, 407c478bd9Sstevel@tonic-gate CQUIT, 417c478bd9Sstevel@tonic-gate CERASE, 427c478bd9Sstevel@tonic-gate CKILL, 437c478bd9Sstevel@tonic-gate CEOF, 447c478bd9Sstevel@tonic-gate CEOL, 457c478bd9Sstevel@tonic-gate CEOL2, 467c478bd9Sstevel@tonic-gate CNSWTCH, 477c478bd9Sstevel@tonic-gate CSTART, 487c478bd9Sstevel@tonic-gate CSTOP, 497c478bd9Sstevel@tonic-gate CSUSP, 507c478bd9Sstevel@tonic-gate CDSUSP, 517c478bd9Sstevel@tonic-gate CRPRNT, 527c478bd9Sstevel@tonic-gate CFLUSH, 537c478bd9Sstevel@tonic-gate CWERASE, 547c478bd9Sstevel@tonic-gate CLNEXT, 55*19d32b9aSRobert Mustacchi CSTATUS 567c478bd9Sstevel@tonic-gate } 577c478bd9Sstevel@tonic-gate }; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate static int termioval(char **, uint_t *, char *); 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate void 637c478bd9Sstevel@tonic-gate ttycommon_close(tty_common_t *tc) 647c478bd9Sstevel@tonic-gate { 657c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 667c478bd9Sstevel@tonic-gate tc->t_flags &= ~TS_XCLUDE; 677c478bd9Sstevel@tonic-gate tc->t_readq = NULL; 687c478bd9Sstevel@tonic-gate tc->t_writeq = NULL; 697c478bd9Sstevel@tonic-gate if (tc->t_iocpending != NULL) { 707c478bd9Sstevel@tonic-gate mblk_t *mp; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate mp = tc->t_iocpending; 737c478bd9Sstevel@tonic-gate tc->t_iocpending = NULL; 747c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * We were holding an "ioctl" response pending the 777c478bd9Sstevel@tonic-gate * availability of an "mblk" to hold data to be passed up; 787c478bd9Sstevel@tonic-gate * another "ioctl" came through, which means that "ioctl" 797c478bd9Sstevel@tonic-gate * must have timed out or been aborted. 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate freemsg(mp); 827c478bd9Sstevel@tonic-gate } else 837c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 847c478bd9Sstevel@tonic-gate } 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * A "line discipline" module's queue is full. 887c478bd9Sstevel@tonic-gate * Check whether IMAXBEL is set; if so, output a ^G, otherwise send an M_FLUSH 897c478bd9Sstevel@tonic-gate * upstream flushing all the read queues. 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate void 927c478bd9Sstevel@tonic-gate ttycommon_qfull(tty_common_t *tc, queue_t *q) 937c478bd9Sstevel@tonic-gate { 947c478bd9Sstevel@tonic-gate mblk_t *mp; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate if (tc->t_iflag & IMAXBEL) { 977c478bd9Sstevel@tonic-gate if (canput(WR(q))) { 987c478bd9Sstevel@tonic-gate if ((mp = allocb(1, BPRI_HI)) != NULL) { 997c478bd9Sstevel@tonic-gate *mp->b_wptr++ = CTRL('g'); 1007c478bd9Sstevel@tonic-gate (void) putq(WR(q), mp); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate } else { 1047c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); 1057c478bd9Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHR); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * Process an "ioctl" message sent down to us, and return a reply message, 1117c478bd9Sstevel@tonic-gate * even if we don't understand the "ioctl". Our client may want to use 1127c478bd9Sstevel@tonic-gate * that reply message for its own purposes if we don't understand it but 1137c478bd9Sstevel@tonic-gate * they do, and may want to modify it if we both understand it but they 1147c478bd9Sstevel@tonic-gate * understand it better than we do. 1157c478bd9Sstevel@tonic-gate * If the "ioctl" reply requires additional data to be passed up to the 1167c478bd9Sstevel@tonic-gate * caller, and we cannot allocate an mblk to hold the data, we return the 1177c478bd9Sstevel@tonic-gate * amount of data to be sent, so that our caller can do a "bufcall" and try 1187c478bd9Sstevel@tonic-gate * again later; otherwise, we return 0. 1197c478bd9Sstevel@tonic-gate */ 1207c478bd9Sstevel@tonic-gate size_t 1217c478bd9Sstevel@tonic-gate ttycommon_ioctl(tty_common_t *tc, queue_t *q, mblk_t *mp, int *errorp) 1227c478bd9Sstevel@tonic-gate { 1237c478bd9Sstevel@tonic-gate struct iocblk *iocp; 1247c478bd9Sstevel@tonic-gate size_t ioctlrespsize; 1257c478bd9Sstevel@tonic-gate mblk_t *tmp; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate *errorp = 0; /* no error detected yet */ 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) { 1327c478bd9Sstevel@tonic-gate *errorp = -1; /* we don't understand it, maybe they do */ 1337c478bd9Sstevel@tonic-gate return (0); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate case TCSETSF: 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Flush the driver's queue, and send an M_FLUSH upstream 1417c478bd9Sstevel@tonic-gate * to flush everybody above us. 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 1447c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHR); 1457c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate case TCSETSW: 1487c478bd9Sstevel@tonic-gate case TCSETS: { 1497c478bd9Sstevel@tonic-gate struct termios *cb; 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (struct termios)) != 0) { 1527c478bd9Sstevel@tonic-gate *errorp = -1; 1537c478bd9Sstevel@tonic-gate break; 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* 1577c478bd9Sstevel@tonic-gate * The only information we look at are the iflag word, 1587c478bd9Sstevel@tonic-gate * the cflag word, and the start and stop characters. 1597c478bd9Sstevel@tonic-gate */ 1607c478bd9Sstevel@tonic-gate cb = (struct termios *)mp->b_cont->b_rptr; 1617c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 1627c478bd9Sstevel@tonic-gate tc->t_iflag = cb->c_iflag; 1637c478bd9Sstevel@tonic-gate tc->t_cflag = cb->c_cflag; 1647c478bd9Sstevel@tonic-gate tc->t_stopc = cb->c_cc[VSTOP]; 1657c478bd9Sstevel@tonic-gate tc->t_startc = cb->c_cc[VSTART]; 1667c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 1677c478bd9Sstevel@tonic-gate break; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate case TCSETAF: 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * Flush the driver's queue, and send an M_FLUSH upstream 1737c478bd9Sstevel@tonic-gate * to flush everybody above us. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 1767c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHR); 1777c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate case TCSETAW: 1807c478bd9Sstevel@tonic-gate case TCSETA: { 1817c478bd9Sstevel@tonic-gate struct termio *cb; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (struct termio)) != 0) { 1847c478bd9Sstevel@tonic-gate *errorp = -1; 1857c478bd9Sstevel@tonic-gate break; 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * The only information we look at are the iflag word 1907c478bd9Sstevel@tonic-gate * and the cflag word. Don't touch the unset portions. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate cb = (struct termio *)mp->b_cont->b_rptr; 1937c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 1947c478bd9Sstevel@tonic-gate tc->t_iflag = (tc->t_iflag & 0xffff0000 | cb->c_iflag); 1957c478bd9Sstevel@tonic-gate tc->t_cflag = (tc->t_cflag & 0xffff0000 | cb->c_cflag); 1967c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 1977c478bd9Sstevel@tonic-gate break; 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate case TIOCSWINSZ: { 2017c478bd9Sstevel@tonic-gate struct winsize *ws; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (struct winsize)) != 0) { 2047c478bd9Sstevel@tonic-gate *errorp = -1; 2057c478bd9Sstevel@tonic-gate break; 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate /* 2097c478bd9Sstevel@tonic-gate * If the window size changed, send a SIGWINCH. 2107c478bd9Sstevel@tonic-gate */ 2117c478bd9Sstevel@tonic-gate ws = (struct winsize *)mp->b_cont->b_rptr; 2127c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 2137c478bd9Sstevel@tonic-gate if (bcmp(&tc->t_size, ws, sizeof (struct winsize)) != 0) { 2147c478bd9Sstevel@tonic-gate tc->t_size = *ws; 2157c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 2167c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_PCSIG, SIGWINCH); 2177c478bd9Sstevel@tonic-gate } else 2187c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 2197c478bd9Sstevel@tonic-gate break; 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* 2237c478bd9Sstevel@tonic-gate * Prevent more opens. 2247c478bd9Sstevel@tonic-gate */ 2257c478bd9Sstevel@tonic-gate case TIOCEXCL: 2267c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 2277c478bd9Sstevel@tonic-gate tc->t_flags |= TS_XCLUDE; 2287c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 2297c478bd9Sstevel@tonic-gate break; 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* 2327c478bd9Sstevel@tonic-gate * Permit more opens. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate case TIOCNXCL: 2357c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 2367c478bd9Sstevel@tonic-gate tc->t_flags &= ~TS_XCLUDE; 2377c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 2387c478bd9Sstevel@tonic-gate break; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* 2417c478bd9Sstevel@tonic-gate * Set or clear the "soft carrier" flag. 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate case TIOCSSOFTCAR: 2447c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (int)) != 0) { 2457c478bd9Sstevel@tonic-gate *errorp = -1; 2467c478bd9Sstevel@tonic-gate break; 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 2507c478bd9Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr) 2517c478bd9Sstevel@tonic-gate tc->t_flags |= TS_SOFTCAR; 2527c478bd9Sstevel@tonic-gate else 2537c478bd9Sstevel@tonic-gate tc->t_flags &= ~TS_SOFTCAR; 2547c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 2557c478bd9Sstevel@tonic-gate break; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * The permission checking has already been done at the stream 2597c478bd9Sstevel@tonic-gate * head, since it has to be done in the context of the process 2607c478bd9Sstevel@tonic-gate * doing the call. 2617c478bd9Sstevel@tonic-gate */ 2627c478bd9Sstevel@tonic-gate case TIOCSTI: { 2637c478bd9Sstevel@tonic-gate mblk_t *bp; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (char)) != 0) { 2667c478bd9Sstevel@tonic-gate *errorp = -1; 2677c478bd9Sstevel@tonic-gate break; 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * Simulate typing of a character at the terminal. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate if ((bp = allocb(1, BPRI_MED)) != NULL) { 2747c478bd9Sstevel@tonic-gate if (!canput(tc->t_readq->q_next)) 2757c478bd9Sstevel@tonic-gate freemsg(bp); 2767c478bd9Sstevel@tonic-gate else { 2777c478bd9Sstevel@tonic-gate *bp->b_wptr++ = *mp->b_cont->b_rptr; 2787c478bd9Sstevel@tonic-gate putnext(tc->t_readq, bp); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate break; 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate /* 2867c478bd9Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 2877c478bd9Sstevel@tonic-gate */ 2887c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned unless we say so */ 2897c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate case TCSETSF: 2947c478bd9Sstevel@tonic-gate case TCSETSW: 2957c478bd9Sstevel@tonic-gate case TCSETS: 2967c478bd9Sstevel@tonic-gate case TCSETAF: 2977c478bd9Sstevel@tonic-gate case TCSETAW: 2987c478bd9Sstevel@tonic-gate case TCSETA: 2997c478bd9Sstevel@tonic-gate case TIOCSWINSZ: 3007c478bd9Sstevel@tonic-gate case TIOCEXCL: 3017c478bd9Sstevel@tonic-gate case TIOCNXCL: 3027c478bd9Sstevel@tonic-gate case TIOCSSOFTCAR: 3037c478bd9Sstevel@tonic-gate case TIOCSTI: 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * We've done all the important work on these already; 3067c478bd9Sstevel@tonic-gate * just reply with an ACK. 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate break; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate case TCGETS: { 3117c478bd9Sstevel@tonic-gate struct termios *cb; 3127c478bd9Sstevel@tonic-gate mblk_t *datap; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate if ((datap = allocb(sizeof (struct termios), 3157c478bd9Sstevel@tonic-gate BPRI_HI)) == NULL) { 3167c478bd9Sstevel@tonic-gate ioctlrespsize = sizeof (struct termios); 3177c478bd9Sstevel@tonic-gate goto allocfailure; 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate cb = (struct termios *)datap->b_wptr; 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * The only information we supply is the cflag word. 3227c478bd9Sstevel@tonic-gate * Our copy of the iflag word is just that, a copy. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate bzero(cb, sizeof (struct termios)); 3257c478bd9Sstevel@tonic-gate cb->c_cflag = tc->t_cflag; 3267c478bd9Sstevel@tonic-gate datap->b_wptr += sizeof (struct termios); 3277c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct termios); 3287c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) 3297c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 3307c478bd9Sstevel@tonic-gate mp->b_cont = datap; 3317c478bd9Sstevel@tonic-gate break; 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate case TCGETA: { 3357c478bd9Sstevel@tonic-gate struct termio *cb; 3367c478bd9Sstevel@tonic-gate mblk_t *datap; 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate if ((datap = allocb(sizeof (struct termio), BPRI_HI)) == NULL) { 3397c478bd9Sstevel@tonic-gate ioctlrespsize = sizeof (struct termio); 3407c478bd9Sstevel@tonic-gate goto allocfailure; 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate cb = (struct termio *)datap->b_wptr; 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * The only information we supply is the cflag word. 3467c478bd9Sstevel@tonic-gate * Our copy of the iflag word is just that, a copy. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate bzero(cb, sizeof (struct termio)); 3497c478bd9Sstevel@tonic-gate cb->c_cflag = tc->t_cflag; 3507c478bd9Sstevel@tonic-gate datap->b_wptr += sizeof (struct termio); 3517c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct termio); 3527c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) 3537c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 3547c478bd9Sstevel@tonic-gate mp->b_cont = datap; 3557c478bd9Sstevel@tonic-gate break; 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * Get the "soft carrier" flag. 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate case TIOCGSOFTCAR: { 3627c478bd9Sstevel@tonic-gate mblk_t *datap; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) { 3657c478bd9Sstevel@tonic-gate ioctlrespsize = sizeof (int); 3667c478bd9Sstevel@tonic-gate goto allocfailure; 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate if (tc->t_flags & TS_SOFTCAR) 3697c478bd9Sstevel@tonic-gate *(int *)datap->b_wptr = 1; 3707c478bd9Sstevel@tonic-gate else 3717c478bd9Sstevel@tonic-gate *(int *)datap->b_wptr = 0; 3727c478bd9Sstevel@tonic-gate datap->b_wptr += sizeof (int); 3737c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (int); 3747c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) 3757c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 3767c478bd9Sstevel@tonic-gate mp->b_cont = datap; 3777c478bd9Sstevel@tonic-gate break; 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate case TIOCGWINSZ: { 3817c478bd9Sstevel@tonic-gate mblk_t *datap; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate if ((datap = allocb(sizeof (struct winsize), 3847c478bd9Sstevel@tonic-gate BPRI_HI)) == NULL) { 3857c478bd9Sstevel@tonic-gate ioctlrespsize = sizeof (struct winsize); 3867c478bd9Sstevel@tonic-gate goto allocfailure; 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate /* 3897c478bd9Sstevel@tonic-gate * Return the current size. 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate *(struct winsize *)datap->b_wptr = tc->t_size; 3927c478bd9Sstevel@tonic-gate datap->b_wptr += sizeof (struct winsize); 3937c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct winsize); 3947c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) 3957c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 3967c478bd9Sstevel@tonic-gate mp->b_cont = datap; 3977c478bd9Sstevel@tonic-gate break; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate default: 4017c478bd9Sstevel@tonic-gate *errorp = -1; /* we don't understand it, maybe they do */ 4027c478bd9Sstevel@tonic-gate break; 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate return (0); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate allocfailure: 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 4097c478bd9Sstevel@tonic-gate tmp = tc->t_iocpending; 4107c478bd9Sstevel@tonic-gate tc->t_iocpending = mp; /* hold this ioctl */ 4117c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * We needed to allocate something to handle this "ioctl", but 4147c478bd9Sstevel@tonic-gate * couldn't; save this "ioctl" and arrange to get called back when 4157c478bd9Sstevel@tonic-gate * it's more likely that we can get what we need. 4167c478bd9Sstevel@tonic-gate * If there's already one being saved, throw it out, since it 4177c478bd9Sstevel@tonic-gate * must have timed out. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate if (tmp != NULL) 4207c478bd9Sstevel@tonic-gate freemsg(tmp); 4217c478bd9Sstevel@tonic-gate return (ioctlrespsize); 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 424*19d32b9aSRobert Mustacchi #define NFIELDS 21 /* 16 control characters + 4 sets of modes */ 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * Init routine run from main at boot time. 4287c478bd9Sstevel@tonic-gate * Creates a property in the "options" node that is 4297c478bd9Sstevel@tonic-gate * the default set of termios modes upon driver open. 4307c478bd9Sstevel@tonic-gate * If the property already existed, then it was 4317c478bd9Sstevel@tonic-gate * defined in the options.conf file. In this case we 4327c478bd9Sstevel@tonic-gate * need to convert this string (stty -g style) to an 4337c478bd9Sstevel@tonic-gate * actual termios structure and store the new property 4347c478bd9Sstevel@tonic-gate * value. 4357c478bd9Sstevel@tonic-gate */ 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate void 4387c478bd9Sstevel@tonic-gate ttyinit() 4397c478bd9Sstevel@tonic-gate { 4407c478bd9Sstevel@tonic-gate dev_info_t *dip; 4417c478bd9Sstevel@tonic-gate struct termios new_termios; 4427c478bd9Sstevel@tonic-gate struct termios *tp; 4437c478bd9Sstevel@tonic-gate char *property = "ttymodes"; 4447c478bd9Sstevel@tonic-gate char **modesp, *cp; 4457c478bd9Sstevel@tonic-gate int i; 4467c478bd9Sstevel@tonic-gate uint_t val; 4477c478bd9Sstevel@tonic-gate uint_t len; 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * If the termios defaults were NOT set up by the 4527c478bd9Sstevel@tonic-gate * user via the options.conf file, create it using the 4537c478bd9Sstevel@tonic-gate * "sane" set of termios modes. 4547c478bd9Sstevel@tonic-gate * Note that if the property had been created via the 4557c478bd9Sstevel@tonic-gate * options.conf file, it would have been created as 4567c478bd9Sstevel@tonic-gate * a string property. Since we would like to store 4577c478bd9Sstevel@tonic-gate * a structure (termios) in this property, we need 4587c478bd9Sstevel@tonic-gate * to change the property type to byte array. 4597c478bd9Sstevel@tonic-gate */ 4607c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ddi_root_node(), 0, 4617c478bd9Sstevel@tonic-gate property, (char ***)&modesp, &len) != DDI_PROP_SUCCESS) { 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL) { 4647c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, 4657c478bd9Sstevel@tonic-gate "ttyinit: Can't find options node!\n"); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * Create the property. 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, dip, 4717c478bd9Sstevel@tonic-gate property, (uchar_t *)&default_termios, 4727c478bd9Sstevel@tonic-gate sizeof (struct termios)) != DDI_PROP_SUCCESS) { 4737c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "ttyinit: can't create %s property\n", 4747c478bd9Sstevel@tonic-gate property); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate return; 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate /* 4807c478bd9Sstevel@tonic-gate * This property was already set in the options.conf 4817c478bd9Sstevel@tonic-gate * file. We must convert it from a "stty -g" string 4827c478bd9Sstevel@tonic-gate * to an actual termios structure. 4837c478bd9Sstevel@tonic-gate */ 4847c478bd9Sstevel@tonic-gate bzero(&new_termios, sizeof (struct termios)); 4857c478bd9Sstevel@tonic-gate tp = &new_termios; 4867c478bd9Sstevel@tonic-gate cp = *modesp; 4877c478bd9Sstevel@tonic-gate for (i = 0; i < NFIELDS; i++) { 4887c478bd9Sstevel@tonic-gate /* 4897c478bd9Sstevel@tonic-gate * Check for bad field/string. 4907c478bd9Sstevel@tonic-gate */ 4917c478bd9Sstevel@tonic-gate if (termioval(&cp, &val, *modesp+strlen(*modesp)) == -1) { 4927c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 4937c478bd9Sstevel@tonic-gate "ttyinit: property '%s' %s\n", property, 4947c478bd9Sstevel@tonic-gate "set incorrectly, using sane value"); 4957c478bd9Sstevel@tonic-gate tp = &default_termios; 4967c478bd9Sstevel@tonic-gate break; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate switch (i) { 4997c478bd9Sstevel@tonic-gate case 0: 5007c478bd9Sstevel@tonic-gate new_termios.c_iflag = (tcflag_t)val; 5017c478bd9Sstevel@tonic-gate break; 5027c478bd9Sstevel@tonic-gate case 1: 5037c478bd9Sstevel@tonic-gate new_termios.c_oflag = (tcflag_t)val; 5047c478bd9Sstevel@tonic-gate break; 5057c478bd9Sstevel@tonic-gate case 2: 5067c478bd9Sstevel@tonic-gate new_termios.c_cflag = (tcflag_t)val; 5077c478bd9Sstevel@tonic-gate break; 5087c478bd9Sstevel@tonic-gate case 3: 5097c478bd9Sstevel@tonic-gate new_termios.c_lflag = (tcflag_t)val; 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate default: 5127c478bd9Sstevel@tonic-gate new_termios.c_cc[i - 4] = (cc_t)val; 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL) { 5167c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "ttyinit: Can't find options node!\n"); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate /* 5207c478bd9Sstevel@tonic-gate * We need to create ttymode property as a byte array 5217c478bd9Sstevel@tonic-gate * since it will be interpreted as a termios struct. 5227c478bd9Sstevel@tonic-gate * The property was created as a string by default. 5237c478bd9Sstevel@tonic-gate * So remove the old property and add the new one - 5247c478bd9Sstevel@tonic-gate * otherwise we end up with two ttymodes properties. 5257c478bd9Sstevel@tonic-gate */ 5267c478bd9Sstevel@tonic-gate if (e_ddi_prop_remove(DDI_DEV_T_NONE, dip, property) 5277c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 5287c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ttyinit: cannot remove '%s' property\n", 5297c478bd9Sstevel@tonic-gate property); 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * Store the new defaults. Since, this property was 5337c478bd9Sstevel@tonic-gate * autoconfig'ed, we must use e_ddi_prop_update_byte_array(). 5347c478bd9Sstevel@tonic-gate */ 5357c478bd9Sstevel@tonic-gate if (e_ddi_prop_update_byte_array(DDI_DEV_T_NONE, dip, property, 5367c478bd9Sstevel@tonic-gate (uchar_t *)tp, sizeof (struct termios)) != DDI_PROP_SUCCESS) { 5377c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "ttyinit: cannot modify '%s' property\n", 5387c478bd9Sstevel@tonic-gate property); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate ddi_prop_free(modesp); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* 5447c478bd9Sstevel@tonic-gate * Convert hex string representation of termios field 5457c478bd9Sstevel@tonic-gate * to a uint_t. Increments string pointer to the next 5467c478bd9Sstevel@tonic-gate * field, and assigns value. Returns -1 if no more fields 5477c478bd9Sstevel@tonic-gate * or an error. 5487c478bd9Sstevel@tonic-gate */ 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate static int 5517c478bd9Sstevel@tonic-gate termioval(char **sp, uint_t *valp, char *ep) 5527c478bd9Sstevel@tonic-gate { 5537c478bd9Sstevel@tonic-gate char *s = *sp; 5547c478bd9Sstevel@tonic-gate uint_t digit; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate if (s == 0) 5577c478bd9Sstevel@tonic-gate return (-1); 5587c478bd9Sstevel@tonic-gate *valp = 0; 5597c478bd9Sstevel@tonic-gate while (s < ep) { 5607c478bd9Sstevel@tonic-gate if (*s >= '0' && *s <= '9') 5617c478bd9Sstevel@tonic-gate digit = *s++ - '0'; 5627c478bd9Sstevel@tonic-gate else if (*s >= 'a' && *s <= 'f') 5637c478bd9Sstevel@tonic-gate digit = *s++ - 'a' + 10; 5647c478bd9Sstevel@tonic-gate else if (*s >= 'A' && *s <= 'F') 5657c478bd9Sstevel@tonic-gate digit = *s++ - 'A' + 10; 5667c478bd9Sstevel@tonic-gate else if (*s == ':' || *s == '\0') 5677c478bd9Sstevel@tonic-gate break; 5687c478bd9Sstevel@tonic-gate else 5697c478bd9Sstevel@tonic-gate return (-1); 5707c478bd9Sstevel@tonic-gate *valp = (*valp * 16) + digit; 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate /* 5737c478bd9Sstevel@tonic-gate * Null string or empty field. 5747c478bd9Sstevel@tonic-gate */ 5757c478bd9Sstevel@tonic-gate if (s == *sp) 5767c478bd9Sstevel@tonic-gate return (-1); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate if (s < ep && *s == ':') 5797c478bd9Sstevel@tonic-gate s++; 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate *sp = s; 5827c478bd9Sstevel@tonic-gate return (0); 5837c478bd9Sstevel@tonic-gate } 584