17c478bd9Sstevel@tonic-gate /* 219397407SSherry Moore * Copyright 2008 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 /* 137c478bd9Sstevel@tonic-gate * PTY - Stream "pseudo-tty" device. 147c478bd9Sstevel@tonic-gate * This is the "slave" side. 157c478bd9Sstevel@tonic-gate */ 167c478bd9Sstevel@tonic-gate 177c478bd9Sstevel@tonic-gate 187c478bd9Sstevel@tonic-gate #include <sys/param.h> 197c478bd9Sstevel@tonic-gate #include <sys/systm.h> 207c478bd9Sstevel@tonic-gate #include <sys/filio.h> 217c478bd9Sstevel@tonic-gate #include <sys/ioccom.h> 227c478bd9Sstevel@tonic-gate #include <sys/termios.h> 237c478bd9Sstevel@tonic-gate #include <sys/termio.h> 247c478bd9Sstevel@tonic-gate #include <sys/ttold.h> 257c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 267c478bd9Sstevel@tonic-gate #include <sys/stream.h> 277c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 287c478bd9Sstevel@tonic-gate #include <sys/tty.h> 297c478bd9Sstevel@tonic-gate #include <sys/user.h> 307c478bd9Sstevel@tonic-gate #include <sys/conf.h> 317c478bd9Sstevel@tonic-gate #include <sys/file.h> 327c478bd9Sstevel@tonic-gate #include <sys/vnode.h> /* 1/0 on the vomit meter */ 337c478bd9Sstevel@tonic-gate #include <sys/proc.h> 347c478bd9Sstevel@tonic-gate #include <sys/uio.h> 357c478bd9Sstevel@tonic-gate #include <sys/errno.h> 367c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 377c478bd9Sstevel@tonic-gate #include <sys/poll.h> 387c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 397c478bd9Sstevel@tonic-gate #include <sys/debug.h> 407c478bd9Sstevel@tonic-gate #include <sys/procset.h> 417c478bd9Sstevel@tonic-gate #include <sys/cred.h> 427c478bd9Sstevel@tonic-gate #include <sys/ptyvar.h> 437c478bd9Sstevel@tonic-gate #include <sys/suntty.h> 447c478bd9Sstevel@tonic-gate #include <sys/stat.h> 457c478bd9Sstevel@tonic-gate #include <sys/policy.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include <sys/conf.h> 487c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 497c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate extern void gsignal(int pid, int sig); 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate extern int npty; /* number of pseudo-ttys configured in */ 547c478bd9Sstevel@tonic-gate extern struct pty *pty_softc; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate extern struct pollhead ptcph; /* poll head for ptcpoll() use */ 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #define IFLAGS (CS7|CREAD|PARENB) 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * Most of these should be "void", but the people who defined the "streams" 637c478bd9Sstevel@tonic-gate * data structure for S5 didn't understand data types. 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* 677c478bd9Sstevel@tonic-gate * Slave side. This is a streams device. 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate static int ptslopen(queue_t *, dev_t *, int flag, int, cred_t *); 707c478bd9Sstevel@tonic-gate static int ptslclose(queue_t *, int, cred_t *); 717c478bd9Sstevel@tonic-gate static int ptslrserv(queue_t *); 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * To save instructions, since STREAMS ignores the return value 757c478bd9Sstevel@tonic-gate * from this function, it is defined as void here. Kind of icky, but... 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate static void ptslwput(queue_t *q, mblk_t *mp); 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate static struct module_info ptslm_info = { 817c478bd9Sstevel@tonic-gate 0, 827c478bd9Sstevel@tonic-gate "ptys", 837c478bd9Sstevel@tonic-gate 0, 847c478bd9Sstevel@tonic-gate INFPSZ, 857c478bd9Sstevel@tonic-gate 2048, 867c478bd9Sstevel@tonic-gate 200 877c478bd9Sstevel@tonic-gate }; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate static struct qinit ptslrinit = { 907c478bd9Sstevel@tonic-gate putq, 917c478bd9Sstevel@tonic-gate ptslrserv, 927c478bd9Sstevel@tonic-gate ptslopen, 937c478bd9Sstevel@tonic-gate ptslclose, 947c478bd9Sstevel@tonic-gate NULL, 957c478bd9Sstevel@tonic-gate &ptslm_info, 967c478bd9Sstevel@tonic-gate NULL 977c478bd9Sstevel@tonic-gate }; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate static struct qinit ptslwinit = { 1007c478bd9Sstevel@tonic-gate (int (*)())ptslwput, 1017c478bd9Sstevel@tonic-gate NULL, 1027c478bd9Sstevel@tonic-gate NULL, 1037c478bd9Sstevel@tonic-gate NULL, 1047c478bd9Sstevel@tonic-gate NULL, 1057c478bd9Sstevel@tonic-gate &ptslm_info, 1067c478bd9Sstevel@tonic-gate NULL 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate struct streamtab ptysinfo = { 1107c478bd9Sstevel@tonic-gate &ptslrinit, 1117c478bd9Sstevel@tonic-gate &ptslwinit, 1127c478bd9Sstevel@tonic-gate NULL, 1137c478bd9Sstevel@tonic-gate NULL 1147c478bd9Sstevel@tonic-gate }; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate static void ptslreioctl(void *); 1177c478bd9Sstevel@tonic-gate static void ptslioctl(struct pty *, queue_t *, mblk_t *); 1187c478bd9Sstevel@tonic-gate static void pt_sendstop(struct pty *); 1197c478bd9Sstevel@tonic-gate static void ptcpollwakeup(struct pty *, int); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate static int ptsl_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 1237c478bd9Sstevel@tonic-gate static int ptsl_attach(dev_info_t *, ddi_attach_cmd_t); 1247c478bd9Sstevel@tonic-gate static dev_info_t *ptsl_dip; /* for dev-to-dip conversions */ 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(ptsl_ops, nulldev, nulldev, 12719397407SSherry Moore ptsl_attach, nodev, nodev, ptsl_info, D_MP, &ptysinfo, 12819397407SSherry Moore ddi_quiesce_not_supported); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate #include <sys/types.h> 1317c478bd9Sstevel@tonic-gate #include <sys/conf.h> 1327c478bd9Sstevel@tonic-gate #include <sys/param.h> 1337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 1347c478bd9Sstevel@tonic-gate #include <sys/errno.h> 1357c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate char _depends_on[] = "drv/ptc"; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1447c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 14519397407SSherry Moore "tty pseudo driver slave 'ptsl'", 1467c478bd9Sstevel@tonic-gate &ptsl_ops, /* driver ops */ 1477c478bd9Sstevel@tonic-gate }; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1507c478bd9Sstevel@tonic-gate MODREV_1, 1517c478bd9Sstevel@tonic-gate &modldrv, 1527c478bd9Sstevel@tonic-gate NULL 1537c478bd9Sstevel@tonic-gate }; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate int 1567c478bd9Sstevel@tonic-gate _init(void) 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate int 1627c478bd9Sstevel@tonic-gate _fini(void) 1637c478bd9Sstevel@tonic-gate { 1647c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate int 1687c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1697c478bd9Sstevel@tonic-gate { 1707c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate static char *tty_banks = PTY_BANKS; 1747c478bd9Sstevel@tonic-gate static char *tty_digits = PTY_DIGITS; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1777c478bd9Sstevel@tonic-gate static int 1787c478bd9Sstevel@tonic-gate ptsl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1797c478bd9Sstevel@tonic-gate { 1807c478bd9Sstevel@tonic-gate char name[8]; 1817c478bd9Sstevel@tonic-gate int tty_num; 1827c478bd9Sstevel@tonic-gate char *tty_digit = tty_digits; 1837c478bd9Sstevel@tonic-gate char *tty_bank = tty_banks; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate for (tty_num = 0; tty_num < npty; tty_num++) { 1867c478bd9Sstevel@tonic-gate (void) sprintf(name, "tty%c%c", *tty_bank, *tty_digit); 1877c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, name, S_IFCHR, 18819397407SSherry Moore tty_num, DDI_PSEUDO, NULL) == DDI_FAILURE) { 1897c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1907c478bd9Sstevel@tonic-gate return (-1); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate if (*(++tty_digit) == '\0') { 1937c478bd9Sstevel@tonic-gate tty_digit = tty_digits; 1947c478bd9Sstevel@tonic-gate if (*(++tty_bank) == '\0') 1957c478bd9Sstevel@tonic-gate break; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate ptsl_dip = devi; 1997c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2037c478bd9Sstevel@tonic-gate static int 2047c478bd9Sstevel@tonic-gate ptsl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 2057c478bd9Sstevel@tonic-gate void **result) 2067c478bd9Sstevel@tonic-gate { 2077c478bd9Sstevel@tonic-gate int error; 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate switch (infocmd) { 2107c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2117c478bd9Sstevel@tonic-gate if (ptsl_dip == NULL) { 2127c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 2137c478bd9Sstevel@tonic-gate } else { 2147c478bd9Sstevel@tonic-gate *result = (void *)ptsl_dip; 2157c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate break; 2187c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2197c478bd9Sstevel@tonic-gate *result = (void *)0; 2207c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 2217c478bd9Sstevel@tonic-gate break; 2227c478bd9Sstevel@tonic-gate default: 2237c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate return (error); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * Open the slave side of a pty. 2317c478bd9Sstevel@tonic-gate */ 2327c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2337c478bd9Sstevel@tonic-gate static int 2347c478bd9Sstevel@tonic-gate ptslopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *cred) 2357c478bd9Sstevel@tonic-gate { 2367c478bd9Sstevel@tonic-gate minor_t unit; 2377c478bd9Sstevel@tonic-gate dev_t dev = *devp; 2387c478bd9Sstevel@tonic-gate struct pty *pty; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate unit = getminor(dev); 2417c478bd9Sstevel@tonic-gate if (unit >= npty) 2427c478bd9Sstevel@tonic-gate return (ENXIO); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate pty = &pty_softc[unit]; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 2477c478bd9Sstevel@tonic-gate /* 2487c478bd9Sstevel@tonic-gate * Block waiting for controller to open, unless this is a no-delay 2497c478bd9Sstevel@tonic-gate * open. 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate again: 2527c478bd9Sstevel@tonic-gate if (pty->pt_ttycommon.t_writeq == NULL) { 2537c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_iflag = 0; 2547c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_cflag = (B38400 << IBSHIFT)|B38400|IFLAGS; 2557c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = NULL; 2567c478bd9Sstevel@tonic-gate pty->pt_wbufcid = 0; 2577c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_row = 0; 2587c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_col = 0; 2597c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_xpixel = 0; 2607c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_size.ws_ypixel = 0; 2617c478bd9Sstevel@tonic-gate } else if ((pty->pt_ttycommon.t_flags & TS_XCLUDE) && 2627c478bd9Sstevel@tonic-gate secpolicy_excl_open(cred) != 0) { 2637c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 2647c478bd9Sstevel@tonic-gate return (EBUSY); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate if (!(flag & (FNONBLOCK|FNDELAY)) && 2677c478bd9Sstevel@tonic-gate !(pty->pt_ttycommon.t_cflag & CLOCAL)) { 2687c478bd9Sstevel@tonic-gate if (!(pty->pt_flags & PF_CARR_ON)) { 2697c478bd9Sstevel@tonic-gate pty->pt_flags |= PF_WOPEN; 2707c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&pty->pt_cv_flags, &pty->ptc_lock)) { 2717c478bd9Sstevel@tonic-gate pty->pt_flags &= ~PF_WOPEN; 2727c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 2737c478bd9Sstevel@tonic-gate return (EINTR); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate goto again; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate pty->pt_sdev = dev; 2807c478bd9Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = pty; 2817c478bd9Sstevel@tonic-gate pty->pt_flags &= ~PF_SLAVEGONE; 2827c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_readq = pty->pt_ttycommon.t_writeq = NULL; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * Slave is ready to accept messages but master still can't send 2867c478bd9Sstevel@tonic-gate * messages to the slave queue since it is not plumbed 2877c478bd9Sstevel@tonic-gate * yet. So do qprocson() and finish slave initialization. 2887c478bd9Sstevel@tonic-gate */ 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate qprocson(q); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* 2957c478bd9Sstevel@tonic-gate * Now it is safe to send messages to q, so wakeup master possibly 2967c478bd9Sstevel@tonic-gate * waiting for slave queue to finish open. 2977c478bd9Sstevel@tonic-gate */ 2987c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 299*3f7d78f0SAnil udupa /* 300*3f7d78f0SAnil udupa * queue has already been setup with a pointer to 301*3f7d78f0SAnil udupa * the stream head that is being referenced 302*3f7d78f0SAnil udupa */ 303*3f7d78f0SAnil udupa pty->pt_vnode = strq2vp(q); 304*3f7d78f0SAnil udupa VN_RELE(pty->pt_vnode); 3057c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_readq = q; 3067c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_writeq = WR(q); 3077c478bd9Sstevel@tonic-gate /* tell master device that slave is ready for writing */ 3087c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_CARR_ON) 3097c478bd9Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_readq); 3107c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate return (0); 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate static int 3167c478bd9Sstevel@tonic-gate ptslclose(queue_t *q, int flag, cred_t *cred) 3177c478bd9Sstevel@tonic-gate { 3187c478bd9Sstevel@tonic-gate struct pty *pty; 3197c478bd9Sstevel@tonic-gate bufcall_id_t pt_wbufcid = 0; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate #ifdef lint 3227c478bd9Sstevel@tonic-gate flag = flag; 3237c478bd9Sstevel@tonic-gate cred = cred; 3247c478bd9Sstevel@tonic-gate #endif 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate if ((pty = (struct pty *)q->q_ptr) == NULL) 3277c478bd9Sstevel@tonic-gate return (ENODEV); /* already been closed once */ 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * Prevent the queues from being uses by master device. 3317c478bd9Sstevel@tonic-gate * This should be done before qprocsoff or writer may attempt 3327c478bd9Sstevel@tonic-gate * to use the slave queue after qprocsoff removed it from the stream and 3337c478bd9Sstevel@tonic-gate * before entering mutex_enter(). 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 3367c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_readq = NULL; 3377c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_writeq = NULL; 3387c478bd9Sstevel@tonic-gate while (pty->pt_flags & PF_IOCTL) { 3397c478bd9Sstevel@tonic-gate pty->pt_flags |= PF_WAIT; 3407c478bd9Sstevel@tonic-gate cv_wait(&pty->pt_cv_flags, &pty->ptc_lock); 3417c478bd9Sstevel@tonic-gate } 342*3f7d78f0SAnil udupa pty->pt_vnode = NULL; 343*3f7d78f0SAnil udupa mutex_exit(&pty->ptc_lock); 344*3f7d78f0SAnil udupa 345*3f7d78f0SAnil udupa qprocsoff(q); 3467c478bd9Sstevel@tonic-gate 347*3f7d78f0SAnil udupa mutex_enter(&pty->ptc_lock); 3487c478bd9Sstevel@tonic-gate /* 3497c478bd9Sstevel@tonic-gate * ptc_lock mutex is not dropped across 3507c478bd9Sstevel@tonic-gate * the call to the routine ttycommon_close 3517c478bd9Sstevel@tonic-gate */ 3527c478bd9Sstevel@tonic-gate ttycommon_close(&pty->pt_ttycommon); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate /* 3557c478bd9Sstevel@tonic-gate * Cancel outstanding "bufcall" request. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate if (pty->pt_wbufcid) { 3587c478bd9Sstevel@tonic-gate pt_wbufcid = pty->pt_wbufcid; 3597c478bd9Sstevel@tonic-gate pty->pt_wbufcid = 0; 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * Clear out all the slave-side state. 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate pty->pt_flags &= ~(PF_WOPEN|PF_STOPPED|PF_NOSTOP); 3667c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_CARR_ON) { 3677c478bd9Sstevel@tonic-gate pty->pt_flags |= PF_SLAVEGONE; /* let the controller know */ 3687c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); /* wake up readers/selectors */ 3697c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, FWRITE); /* wake up writers/selectors */ 3707c478bd9Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_flags); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate pty->pt_sdev = 0; 3737c478bd9Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL; 3747c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate if (pt_wbufcid) 3777c478bd9Sstevel@tonic-gate unbufcall(pt_wbufcid); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate return (0); 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * Put procedure for write queue. 3847c478bd9Sstevel@tonic-gate * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here; 3857c478bd9Sstevel@tonic-gate * queue up M_DATA messages for processing by the controller "read" 3867c478bd9Sstevel@tonic-gate * routine; discard everything else. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate static void 3897c478bd9Sstevel@tonic-gate ptslwput(queue_t *q, mblk_t *mp) 3907c478bd9Sstevel@tonic-gate { 3917c478bd9Sstevel@tonic-gate struct pty *pty; 3927c478bd9Sstevel@tonic-gate mblk_t *bp; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate pty = (struct pty *)q->q_ptr; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate case M_STOP: 4017c478bd9Sstevel@tonic-gate if (!(pty->pt_flags & PF_STOPPED)) { 4027c478bd9Sstevel@tonic-gate pty->pt_flags |= PF_STOPPED; 4037c478bd9Sstevel@tonic-gate pty->pt_send |= TIOCPKT_STOP; 4047c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate freemsg(mp); 4077c478bd9Sstevel@tonic-gate break; 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate case M_START: 4107c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_STOPPED) { 4117c478bd9Sstevel@tonic-gate pty->pt_flags &= ~PF_STOPPED; 4127c478bd9Sstevel@tonic-gate pty->pt_send = TIOCPKT_START; 4137c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, FREAD); /* permit controller to read */ 4167c478bd9Sstevel@tonic-gate freemsg(mp); 4177c478bd9Sstevel@tonic-gate break; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate case M_IOCTL: 4207c478bd9Sstevel@tonic-gate ptslioctl(pty, q, mp); 4217c478bd9Sstevel@tonic-gate break; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate case M_FLUSH: 4247c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 4257c478bd9Sstevel@tonic-gate /* 4267c478bd9Sstevel@tonic-gate * Set the "flush write" flag, so that we 4277c478bd9Sstevel@tonic-gate * notify the controller if they're in packet 4287c478bd9Sstevel@tonic-gate * or user control mode. 4297c478bd9Sstevel@tonic-gate */ 4307c478bd9Sstevel@tonic-gate if (!(pty->pt_send & TIOCPKT_FLUSHWRITE)) { 4317c478bd9Sstevel@tonic-gate pty->pt_send |= TIOCPKT_FLUSHWRITE; 4327c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate /* 4357c478bd9Sstevel@tonic-gate * Flush our write queue. 4367c478bd9Sstevel@tonic-gate */ 4377c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */ 4387c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; /* it has been flushed */ 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 4417c478bd9Sstevel@tonic-gate /* 4427c478bd9Sstevel@tonic-gate * Set the "flush read" flag, so that we 4437c478bd9Sstevel@tonic-gate * notify the controller if they're in packet 4447c478bd9Sstevel@tonic-gate * mode. 4457c478bd9Sstevel@tonic-gate */ 4467c478bd9Sstevel@tonic-gate if (!(pty->pt_send & TIOCPKT_FLUSHREAD)) { 4477c478bd9Sstevel@tonic-gate pty->pt_send |= TIOCPKT_FLUSHREAD; 4487c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 4517c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 4527c478bd9Sstevel@tonic-gate qreply(q, mp); /* give the read queues a crack at it */ 4537c478bd9Sstevel@tonic-gate return; 4547c478bd9Sstevel@tonic-gate } else 4557c478bd9Sstevel@tonic-gate freemsg(mp); 4567c478bd9Sstevel@tonic-gate break; 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate case M_DATA: 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * Throw away any leading zero-length blocks, and queue it up 4617c478bd9Sstevel@tonic-gate * for the controller to read. 4627c478bd9Sstevel@tonic-gate */ 4637c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_CARR_ON) { 4647c478bd9Sstevel@tonic-gate bp = mp; 4657c478bd9Sstevel@tonic-gate while ((bp->b_wptr - bp->b_rptr) == 0) { 4667c478bd9Sstevel@tonic-gate mp = bp->b_cont; 4677c478bd9Sstevel@tonic-gate freeb(bp); 4687c478bd9Sstevel@tonic-gate if (mp == NULL) { 4697c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 4707c478bd9Sstevel@tonic-gate return; /* damp squib of a message */ 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate bp = mp; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate (void) putq(q, mp); 4757c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, FREAD); /* soup's on! */ 4767c478bd9Sstevel@tonic-gate } else 4777c478bd9Sstevel@tonic-gate freemsg(mp); /* nobody listening */ 4787c478bd9Sstevel@tonic-gate break; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate case M_CTL: 4817c478bd9Sstevel@tonic-gate if ((*(int *)mp->b_rptr) == MC_CANONQUERY) { 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * We're being asked whether we do canonicalization 4847c478bd9Sstevel@tonic-gate * or not. Send a reply back up indicating whether 4857c478bd9Sstevel@tonic-gate * we do or not. 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate (void) putctl1(RD(q), M_CTL, 4887c478bd9Sstevel@tonic-gate (pty->pt_flags & PF_REMOTE) ? 48919397407SSherry Moore MC_NOCANON : MC_DOCANON); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate freemsg(mp); 4927c478bd9Sstevel@tonic-gate break; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate default: 4957c478bd9Sstevel@tonic-gate /* 4967c478bd9Sstevel@tonic-gate * "No, I don't want a subscription to Chain Store Age, 4977c478bd9Sstevel@tonic-gate * thank you anyway." 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate freemsg(mp); 5007c478bd9Sstevel@tonic-gate break; 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* 5067c478bd9Sstevel@tonic-gate * Retry an "ioctl", now that "bufcall" claims we may be able to allocate 5077c478bd9Sstevel@tonic-gate * the buffer we need. 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate static void 5107c478bd9Sstevel@tonic-gate ptslreioctl(void *arg) 5117c478bd9Sstevel@tonic-gate { 5127c478bd9Sstevel@tonic-gate struct pty *pty = arg; 5137c478bd9Sstevel@tonic-gate queue_t *q; 5147c478bd9Sstevel@tonic-gate mblk_t *mp; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 5177c478bd9Sstevel@tonic-gate /* 5187c478bd9Sstevel@tonic-gate * The bufcall is no longer pending. 5197c478bd9Sstevel@tonic-gate */ 5207c478bd9Sstevel@tonic-gate if (pty->pt_wbufcid == 0) { 5217c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5227c478bd9Sstevel@tonic-gate return; 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate pty->pt_wbufcid = 0; 5267c478bd9Sstevel@tonic-gate if ((q = pty->pt_ttycommon.t_writeq) == NULL) { 5277c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5287c478bd9Sstevel@tonic-gate return; 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate if ((mp = pty->pt_ttycommon.t_iocpending) != NULL) { 5317c478bd9Sstevel@tonic-gate /* It's not pending any more. */ 5327c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = NULL; 5337c478bd9Sstevel@tonic-gate ptslioctl(pty, q, mp); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate /* 5397c478bd9Sstevel@tonic-gate * Process an "ioctl" message sent down to us. 5407c478bd9Sstevel@tonic-gate * Drops pty's ptc_lock mutex and then reacquire 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate static void 5437c478bd9Sstevel@tonic-gate ptslioctl(struct pty *pty, queue_t *q, mblk_t *mp) 5447c478bd9Sstevel@tonic-gate { 5457c478bd9Sstevel@tonic-gate struct iocblk *iocp; 5467c478bd9Sstevel@tonic-gate int cmd; 5477c478bd9Sstevel@tonic-gate size_t datasize; 5487c478bd9Sstevel@tonic-gate int error = 0; 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pty->ptc_lock)); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 5537c478bd9Sstevel@tonic-gate cmd = iocp->ioc_cmd; 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate switch (cmd) { 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate case TIOCSTI: { 5587c478bd9Sstevel@tonic-gate /* 5597c478bd9Sstevel@tonic-gate * The permission checking has already been done at the stream 5607c478bd9Sstevel@tonic-gate * head, since it has to be done in the context of the process 5617c478bd9Sstevel@tonic-gate * doing the call. 5627c478bd9Sstevel@tonic-gate */ 5637c478bd9Sstevel@tonic-gate mblk_t *bp; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (char)); 5667c478bd9Sstevel@tonic-gate if (error != 0) 5677c478bd9Sstevel@tonic-gate goto out; 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * Simulate typing of a character at the terminal. 5717c478bd9Sstevel@tonic-gate */ 5727c478bd9Sstevel@tonic-gate if ((bp = allocb(1, BPRI_MED)) != NULL) { 5737c478bd9Sstevel@tonic-gate *bp->b_wptr++ = *mp->b_cont->b_rptr; 5747c478bd9Sstevel@tonic-gate if (!(pty->pt_flags & PF_REMOTE)) { 5757c478bd9Sstevel@tonic-gate if (!canput(pty->pt_ttycommon.t_readq)) { 5767c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 5777c478bd9Sstevel@tonic-gate ttycommon_qfull(&pty->pt_ttycommon, q); 5787c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 5797c478bd9Sstevel@tonic-gate freemsg(bp); 5807c478bd9Sstevel@tonic-gate error = EAGAIN; 5817c478bd9Sstevel@tonic-gate goto out; 5827c478bd9Sstevel@tonic-gate } else 5837c478bd9Sstevel@tonic-gate (void) putq( 5847c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_readq, bp); 5857c478bd9Sstevel@tonic-gate } else { 5867c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_UCNTL) { 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * XXX - flow control; don't overflow 5897c478bd9Sstevel@tonic-gate * this "queue". 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate if (pty->pt_stuffqfirst != NULL) { 5927c478bd9Sstevel@tonic-gate pty->pt_stuffqlast->b_next = bp; 5937c478bd9Sstevel@tonic-gate bp->b_prev = pty->pt_stuffqlast; 5947c478bd9Sstevel@tonic-gate } else { 5957c478bd9Sstevel@tonic-gate pty->pt_stuffqfirst = bp; 5967c478bd9Sstevel@tonic-gate bp->b_prev = NULL; 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate bp->b_next = NULL; 5997c478bd9Sstevel@tonic-gate pty->pt_stuffqlast = bp; 6007c478bd9Sstevel@tonic-gate pty->pt_stuffqlen++; 6017c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate } else { 6057c478bd9Sstevel@tonic-gate error = EAGAIN; 6067c478bd9Sstevel@tonic-gate goto out; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate /* 6107c478bd9Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 6117c478bd9Sstevel@tonic-gate */ 6127c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 6137c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 6147c478bd9Sstevel@tonic-gate goto out; 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate case TIOCSSIZE: { 6187c478bd9Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 6197c478bd9Sstevel@tonic-gate struct ttysize *tp; 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct ttysize)); 6227c478bd9Sstevel@tonic-gate if (error != 0) 6237c478bd9Sstevel@tonic-gate goto out; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate /* 6267c478bd9Sstevel@tonic-gate * Set the window size, but don't send a SIGWINCH. 6277c478bd9Sstevel@tonic-gate */ 6287c478bd9Sstevel@tonic-gate tp = (struct ttysize *)mp->b_cont->b_rptr; 6297c478bd9Sstevel@tonic-gate tc->t_size.ws_row = tp->ts_lines; 6307c478bd9Sstevel@tonic-gate tc->t_size.ws_col = tp->ts_cols; 6317c478bd9Sstevel@tonic-gate tc->t_size.ws_xpixel = 0; 6327c478bd9Sstevel@tonic-gate tc->t_size.ws_ypixel = 0; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* 6357c478bd9Sstevel@tonic-gate * Send an ACK back. 6367c478bd9Sstevel@tonic-gate */ 6377c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 6387c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 6397c478bd9Sstevel@tonic-gate goto out; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate case TIOCGSIZE: { 6437c478bd9Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 6447c478bd9Sstevel@tonic-gate mblk_t *datap; 6457c478bd9Sstevel@tonic-gate struct ttysize *tp; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate if ((datap = allocb(sizeof (struct ttysize), 6487c478bd9Sstevel@tonic-gate BPRI_HI)) == NULL) { 6497c478bd9Sstevel@tonic-gate if (pty->pt_wbufcid) { 6507c478bd9Sstevel@tonic-gate if (pty->pt_ttycommon.t_iocpending) 6517c478bd9Sstevel@tonic-gate freemsg(pty->pt_ttycommon.t_iocpending); 6527c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = mp; 6537c478bd9Sstevel@tonic-gate return; 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate pty->pt_wbufcid = bufcall(sizeof (struct ttysize), 6567c478bd9Sstevel@tonic-gate BPRI_HI, ptslreioctl, pty); 6577c478bd9Sstevel@tonic-gate if (pty->pt_wbufcid == 0) { 6587c478bd9Sstevel@tonic-gate error = ENOMEM; 6597c478bd9Sstevel@tonic-gate goto out; 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = mp; 6627c478bd9Sstevel@tonic-gate return; 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate /* 6657c478bd9Sstevel@tonic-gate * Return the current size. 6667c478bd9Sstevel@tonic-gate */ 6677c478bd9Sstevel@tonic-gate tp = (struct ttysize *)datap->b_wptr; 6687c478bd9Sstevel@tonic-gate tp->ts_lines = tc->t_size.ws_row; 6697c478bd9Sstevel@tonic-gate tp->ts_cols = tc->t_size.ws_col; 6707c478bd9Sstevel@tonic-gate datap->b_wptr += sizeof (struct ttysize); 6717c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct ttysize); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL) 6747c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 6757c478bd9Sstevel@tonic-gate mp->b_cont = datap; 6767c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 6777c478bd9Sstevel@tonic-gate goto out; 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /* 6817c478bd9Sstevel@tonic-gate * Imported from ttycommon_ioctl routine 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate case TCSETSF: { 6857c478bd9Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 6867c478bd9Sstevel@tonic-gate struct termios *cb; 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct termios)); 6897c478bd9Sstevel@tonic-gate if (error != 0) 6907c478bd9Sstevel@tonic-gate goto out; 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate cb = (struct termios *)mp->b_cont->b_rptr; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 6957c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 6967c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHR); 6977c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 6987c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 6997c478bd9Sstevel@tonic-gate tc->t_iflag = cb->c_iflag; 7007c478bd9Sstevel@tonic-gate tc->t_cflag = cb->c_cflag; 7017c478bd9Sstevel@tonic-gate tc->t_stopc = cb->c_cc[VSTOP]; 7027c478bd9Sstevel@tonic-gate tc->t_startc = cb->c_cc[VSTART]; 7037c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* 7067c478bd9Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 7077c478bd9Sstevel@tonic-gate */ 7087c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 7097c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 7107c478bd9Sstevel@tonic-gate goto ioctldone; 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate case TCSETAF: { 7147c478bd9Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 7157c478bd9Sstevel@tonic-gate struct termios *cb; 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct termios)); 7187c478bd9Sstevel@tonic-gate if (error != 0) 7197c478bd9Sstevel@tonic-gate goto out; 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate cb = (struct termios *)mp->b_cont->b_rptr; 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA); 7247c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 7257c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHR); 7267c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 7277c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 7287c478bd9Sstevel@tonic-gate tc->t_iflag = (tc->t_iflag & 0xffff0000 | cb->c_iflag); 7297c478bd9Sstevel@tonic-gate tc->t_cflag = (tc->t_cflag & 0xffff0000 | cb->c_cflag); 7307c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate /* 7337c478bd9Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 7347c478bd9Sstevel@tonic-gate */ 7357c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 7367c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 7377c478bd9Sstevel@tonic-gate goto ioctldone; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate case TIOCSWINSZ: { 7417c478bd9Sstevel@tonic-gate tty_common_t *tc = &pty->pt_ttycommon; 7427c478bd9Sstevel@tonic-gate struct winsize *ws; 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct winsize)); 7457c478bd9Sstevel@tonic-gate if (error != 0) 7467c478bd9Sstevel@tonic-gate goto out; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate ws = (struct winsize *)mp->b_cont->b_rptr; 7497c478bd9Sstevel@tonic-gate /* 7507c478bd9Sstevel@tonic-gate * If the window size changed, send a SIGWINCH. 7517c478bd9Sstevel@tonic-gate */ 7527c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl); 7537c478bd9Sstevel@tonic-gate if (bcmp(&tc->t_size, ws, sizeof (struct winsize))) { 7547c478bd9Sstevel@tonic-gate tc->t_size = *ws; 7557c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 7567c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 7577c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_PCSIG, SIGWINCH); 7587c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 7597c478bd9Sstevel@tonic-gate } else 7607c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl); 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /* 7637c478bd9Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 7667c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 7677c478bd9Sstevel@tonic-gate goto ioctldone; 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * If they were just trying to drain output, that's OK. 7727c478bd9Sstevel@tonic-gate * If they are actually trying to send a break it's an error. 7737c478bd9Sstevel@tonic-gate */ 7747c478bd9Sstevel@tonic-gate case TCSBRK: 7757c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (int)); 7767c478bd9Sstevel@tonic-gate if (error != 0) 7777c478bd9Sstevel@tonic-gate goto out; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr != 0) { 7807c478bd9Sstevel@tonic-gate /* 7817c478bd9Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message. 7827c478bd9Sstevel@tonic-gate */ 7837c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned */ 7847c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 7857c478bd9Sstevel@tonic-gate } else { 7867c478bd9Sstevel@tonic-gate error = ENOTTY; 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate goto out; 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * The only way in which "ttycommon_ioctl" can fail is if the "ioctl" 7937c478bd9Sstevel@tonic-gate * requires a response containing data to be returned to the user, 7947c478bd9Sstevel@tonic-gate * and no mblk could be allocated for the data. 7957c478bd9Sstevel@tonic-gate * No such "ioctl" alters our state. Thus, we always go ahead and 7967c478bd9Sstevel@tonic-gate * do any state-changes the "ioctl" calls for. If we couldn't allocate 7977c478bd9Sstevel@tonic-gate * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so 7987c478bd9Sstevel@tonic-gate * we just call "bufcall" to request that we be called back when we 7997c478bd9Sstevel@tonic-gate * stand a better chance of allocating the data. 8007c478bd9Sstevel@tonic-gate */ 8017c478bd9Sstevel@tonic-gate if ((datasize = 8027c478bd9Sstevel@tonic-gate ttycommon_ioctl(&pty->pt_ttycommon, q, mp, &error)) != 0) { 8037c478bd9Sstevel@tonic-gate if (pty->pt_wbufcid) { 8047c478bd9Sstevel@tonic-gate if (pty->pt_ttycommon.t_iocpending) 8057c478bd9Sstevel@tonic-gate freemsg(pty->pt_ttycommon.t_iocpending); 8067c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = mp; 8077c478bd9Sstevel@tonic-gate return; 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate pty->pt_wbufcid = bufcall(datasize, BPRI_HI, ptslreioctl, pty); 8107c478bd9Sstevel@tonic-gate if (pty->pt_wbufcid == 0) { 8117c478bd9Sstevel@tonic-gate error = ENOMEM; 8127c478bd9Sstevel@tonic-gate goto out; 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_iocpending = mp; 8157c478bd9Sstevel@tonic-gate return; 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate ioctldone: 8197c478bd9Sstevel@tonic-gate if (error == 0) { 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * "ttycommon_ioctl" did most of the work; we just use the 8227c478bd9Sstevel@tonic-gate * data it set up. 8237c478bd9Sstevel@tonic-gate */ 8247c478bd9Sstevel@tonic-gate switch (cmd) { 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate case TCSETSF: 8277c478bd9Sstevel@tonic-gate case TCSETAF: 8287c478bd9Sstevel@tonic-gate /* 8297c478bd9Sstevel@tonic-gate * Set the "flush read" flag, so that we 8307c478bd9Sstevel@tonic-gate * notify the controller if they're in packet 8317c478bd9Sstevel@tonic-gate * mode. 8327c478bd9Sstevel@tonic-gate */ 8337c478bd9Sstevel@tonic-gate if (!(pty->pt_send & TIOCPKT_FLUSHREAD)) { 8347c478bd9Sstevel@tonic-gate pty->pt_send |= TIOCPKT_FLUSHREAD; 8357c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate case TCSETSW: 8407c478bd9Sstevel@tonic-gate case TCSETAW: 8417c478bd9Sstevel@tonic-gate cmd = TIOCSETP; /* map backwards to old codes */ 8427c478bd9Sstevel@tonic-gate pt_sendstop(pty); 8437c478bd9Sstevel@tonic-gate break; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate case TCSETS: 8467c478bd9Sstevel@tonic-gate case TCSETA: 8477c478bd9Sstevel@tonic-gate cmd = TIOCSETN; /* map backwards to old codes */ 8487c478bd9Sstevel@tonic-gate pt_sendstop(pty); 8497c478bd9Sstevel@tonic-gate break; 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_43UCNTL) { 8547c478bd9Sstevel@tonic-gate if (error < 0) { 8557c478bd9Sstevel@tonic-gate if ((cmd & ~0xff) == _IO('u', 0)) { 8567c478bd9Sstevel@tonic-gate if (cmd & 0xff) { 8577c478bd9Sstevel@tonic-gate pty->pt_ucntl = (uchar_t)cmd & 0xff; 8587c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, FREAD); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate error = 0; /* XXX */ 8617c478bd9Sstevel@tonic-gate goto out; 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate error = ENOTTY; 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate } else { 8667c478bd9Sstevel@tonic-gate if ((pty->pt_flags & PF_UCNTL) && 8677c478bd9Sstevel@tonic-gate (cmd & (IOC_INOUT | 0xff00)) == (IOC_IN|('t'<<8)) && 8687c478bd9Sstevel@tonic-gate (cmd & 0xff)) { 8697c478bd9Sstevel@tonic-gate pty->pt_ucntl = (uchar_t)cmd & 0xff; 8707c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, FREAD); 8717c478bd9Sstevel@tonic-gate goto out; 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate if (error < 0) 8747c478bd9Sstevel@tonic-gate error = ENOTTY; 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate out: 8787c478bd9Sstevel@tonic-gate if (error != 0) { 8797c478bd9Sstevel@tonic-gate ((struct iocblk *)mp->b_rptr)->ioc_error = error; 8807c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCNAK; 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 8847c478bd9Sstevel@tonic-gate qreply(q, mp); 8857c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate /* 8897c478bd9Sstevel@tonic-gate * Service routine for read queue. 8907c478bd9Sstevel@tonic-gate * Just wakes the controller side up so it can write some more data 8917c478bd9Sstevel@tonic-gate * to that queue. 8927c478bd9Sstevel@tonic-gate */ 8937c478bd9Sstevel@tonic-gate static int 8947c478bd9Sstevel@tonic-gate ptslrserv(queue_t *q) 8957c478bd9Sstevel@tonic-gate { 8967c478bd9Sstevel@tonic-gate struct pty *pty = (struct pty *)q->q_ptr; 8977c478bd9Sstevel@tonic-gate mblk_t *mp; 8987c478bd9Sstevel@tonic-gate mblk_t *head = NULL, *tail = NULL; 8997c478bd9Sstevel@tonic-gate /* 9007c478bd9Sstevel@tonic-gate * Build up the link list of messages, then drop 9017c478bd9Sstevel@tonic-gate * drop the lock and do putnext() 9027c478bd9Sstevel@tonic-gate */ 9037c478bd9Sstevel@tonic-gate mutex_enter(&pty->ptc_lock); 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 9067c478bd9Sstevel@tonic-gate if ((mp->b_datap->db_type < QPCTL) && !canputnext(q)) { 9077c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 9087c478bd9Sstevel@tonic-gate break; 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate if (!head) { 9117c478bd9Sstevel@tonic-gate head = mp; 9127c478bd9Sstevel@tonic-gate tail = mp; 9137c478bd9Sstevel@tonic-gate } else { 9147c478bd9Sstevel@tonic-gate tail->b_next = mp; 9157c478bd9Sstevel@tonic-gate tail = mp; 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate if (q->q_count <= q->q_lowat) 9207c478bd9Sstevel@tonic-gate ptcpollwakeup((struct pty *)q->q_ptr, FWRITE); 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate mutex_exit(&pty->ptc_lock); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate while (head) { 9257c478bd9Sstevel@tonic-gate mp = head; 9267c478bd9Sstevel@tonic-gate head = mp->b_next; 9277c478bd9Sstevel@tonic-gate mp->b_next = NULL; 9287c478bd9Sstevel@tonic-gate putnext(q, mp); 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate return (0); 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate static void 9357c478bd9Sstevel@tonic-gate pt_sendstop(struct pty *pty) 9367c478bd9Sstevel@tonic-gate { 9377c478bd9Sstevel@tonic-gate int stop; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pty->ptc_lock)); 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate if ((pty->pt_ttycommon.t_cflag&CBAUD) == 0) { 9427c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_CARR_ON) { 9437c478bd9Sstevel@tonic-gate /* 9447c478bd9Sstevel@tonic-gate * Let the controller know, then wake up 9457c478bd9Sstevel@tonic-gate * readers/selectors and writers/selectors. 9467c478bd9Sstevel@tonic-gate */ 9477c478bd9Sstevel@tonic-gate pty->pt_flags |= PF_SLAVEGONE; 9487c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); 9497c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, FWRITE); 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate stop = (pty->pt_ttycommon.t_iflag & IXON) && 9547c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_stopc == CTRL('s') && 9557c478bd9Sstevel@tonic-gate pty->pt_ttycommon.t_startc == CTRL('q'); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_NOSTOP) { 9587c478bd9Sstevel@tonic-gate if (stop) { 9597c478bd9Sstevel@tonic-gate pty->pt_send &= ~TIOCPKT_NOSTOP; 9607c478bd9Sstevel@tonic-gate pty->pt_send |= TIOCPKT_DOSTOP; 9617c478bd9Sstevel@tonic-gate pty->pt_flags &= ~PF_NOSTOP; 9627c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate } else { 9657c478bd9Sstevel@tonic-gate if (!stop) { 9667c478bd9Sstevel@tonic-gate pty->pt_send &= ~TIOCPKT_DOSTOP; 9677c478bd9Sstevel@tonic-gate pty->pt_send |= TIOCPKT_NOSTOP; 9687c478bd9Sstevel@tonic-gate pty->pt_flags |= PF_NOSTOP; 9697c478bd9Sstevel@tonic-gate ptcpollwakeup(pty, 0); 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate /* 9757c478bd9Sstevel@tonic-gate * Wake up controller side. "flag" is 0 if a special packet or 9767c478bd9Sstevel@tonic-gate * user control mode message has been queued up (this data is readable, 9777c478bd9Sstevel@tonic-gate * so we also treat it as a regular data event; should we send SIGIO, 9787c478bd9Sstevel@tonic-gate * though?), FREAD if regular data has been queued up, or FWRITE if 9797c478bd9Sstevel@tonic-gate * the slave's read queue has drained sufficiently to allow writing. 9807c478bd9Sstevel@tonic-gate */ 9817c478bd9Sstevel@tonic-gate static void 9827c478bd9Sstevel@tonic-gate ptcpollwakeup(struct pty *pty, int flag) 9837c478bd9Sstevel@tonic-gate { 9847c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pty->ptc_lock)); 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate if (flag == 0) { 9877c478bd9Sstevel@tonic-gate /* 9887c478bd9Sstevel@tonic-gate * "Exceptional condition" occurred. This means that 9897c478bd9Sstevel@tonic-gate * a "read" is now possible, so do a "read" wakeup. 9907c478bd9Sstevel@tonic-gate */ 9917c478bd9Sstevel@tonic-gate flag = FREAD; 9927c478bd9Sstevel@tonic-gate pollwakeup(&ptcph, POLLIN | POLLRDBAND); 9937c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_ASYNC) 9947c478bd9Sstevel@tonic-gate gsignal(pty->pt_pgrp, SIGURG); 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate if (flag & FREAD) { 9977c478bd9Sstevel@tonic-gate /* 9987c478bd9Sstevel@tonic-gate * Wake up the parent process as there is regular 9997c478bd9Sstevel@tonic-gate * data to read from slave's write queue 10007c478bd9Sstevel@tonic-gate */ 10017c478bd9Sstevel@tonic-gate pollwakeup(&ptcph, POLLIN | POLLRDNORM); 10027c478bd9Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_writeq); 10037c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_ASYNC) 10047c478bd9Sstevel@tonic-gate gsignal(pty->pt_pgrp, SIGIO); 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate if (flag & FWRITE) { 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * Wake up the parent process to write 10097c478bd9Sstevel@tonic-gate * data into slave's read queue as the 10107c478bd9Sstevel@tonic-gate * read queue has drained enough 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate pollwakeup(&ptcph, POLLOUT | POLLWRNORM); 10137c478bd9Sstevel@tonic-gate cv_broadcast(&pty->pt_cv_readq); 10147c478bd9Sstevel@tonic-gate if (pty->pt_flags & PF_ASYNC) 10157c478bd9Sstevel@tonic-gate gsignal(pty->pt_pgrp, SIGIO); 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate } 1018