Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / ptem.c
blobe4dc15a3ac4f67149e79c472fd65d996ea469088
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
33 * Description:
35 * The PTEM streams module is used as a pseudo driver emulator. Its purpose
36 * is to emulate the ioctl() functions of a terminal device driver.
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/stream.h>
42 #include <sys/stropts.h>
43 #include <sys/strsun.h>
44 #include <sys/termio.h>
45 #include <sys/pcb.h>
46 #include <sys/signal.h>
47 #include <sys/cred.h>
48 #include <sys/strtty.h>
49 #include <sys/errno.h>
50 #include <sys/cmn_err.h>
51 #include <sys/jioctl.h>
52 #include <sys/ptem.h>
53 #include <sys/ptms.h>
54 #include <sys/debug.h>
55 #include <sys/kmem.h>
56 #include <sys/ddi.h>
57 #include <sys/sunddi.h>
58 #include <sys/conf.h>
59 #include <sys/modctl.h>
61 extern struct streamtab pteminfo;
63 static struct fmodsw fsw = {
64 "ptem",
65 &pteminfo,
66 D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
69 static struct modlstrmod modlstrmod = {
70 &mod_strmodops, "pty hardware emulator", &fsw
73 static struct modlinkage modlinkage = {
74 MODREV_1, &modlstrmod, NULL
77 int
78 _init()
80 return (mod_install(&modlinkage));
83 int
84 _fini()
86 return (mod_remove(&modlinkage));
89 int
90 _info(struct modinfo *modinfop)
92 return (mod_info(&modlinkage, modinfop));
96 * stream data structure definitions
98 static int ptemopen(queue_t *, dev_t *, int, int, cred_t *);
99 static int ptemclose(queue_t *, int, cred_t *);
100 static void ptemrput(queue_t *, mblk_t *);
101 static void ptemwput(queue_t *, mblk_t *);
102 static void ptemwsrv(queue_t *);
104 static struct module_info ptem_info = {
105 0xabcd,
106 "ptem",
108 _TTY_BUFSIZ,
109 _TTY_BUFSIZ,
113 static struct qinit ptemrinit = {
114 (int (*)()) ptemrput,
115 NULL,
116 ptemopen,
117 ptemclose,
118 NULL,
119 &ptem_info,
120 NULL
123 static struct qinit ptemwinit = {
124 (int (*)()) ptemwput,
125 (int (*)()) ptemwsrv,
126 ptemopen,
127 ptemclose,
128 nulldev,
129 &ptem_info,
130 NULL
133 struct streamtab pteminfo = {
134 &ptemrinit,
135 &ptemwinit,
136 NULL,
137 NULL
140 static void ptioc(queue_t *, mblk_t *, int);
141 static int ptemwmsg(queue_t *, mblk_t *);
144 * ptemopen - open routine gets called when the module gets pushed onto the
145 * stream.
147 /* ARGSUSED */
148 static int
149 ptemopen(
150 queue_t *q, /* pointer to the read side queue */
151 dev_t *devp, /* pointer to stream tail's dev */
152 int oflag, /* the user open(2) supplied flags */
153 int sflag, /* open state flag */
154 cred_t *credp) /* credentials */
156 struct ptem *ntp; /* ptem entry for this PTEM module */
157 mblk_t *mop; /* an setopts mblk */
158 struct stroptions *sop;
159 struct termios *termiosp;
160 int len;
162 if (sflag != MODOPEN)
163 return (EINVAL);
165 if (q->q_ptr != NULL) {
166 /* It's already attached. */
167 return (0);
171 * Allocate state structure.
173 ntp = kmem_alloc(sizeof (*ntp), KM_SLEEP);
176 * Allocate a message block, used to pass the zero length message for
177 * "stty 0".
179 * NOTE: it's better to find out if such a message block can be
180 * allocated before it's needed than to not be able to
181 * deliver (for possible lack of buffers) when a hang-up
182 * occurs.
184 if ((ntp->dack_ptr = allocb(4, BPRI_MED)) == NULL) {
185 kmem_free(ntp, sizeof (*ntp));
186 return (EAGAIN);
190 * Initialize an M_SETOPTS message to set up hi/lo water marks on
191 * stream head read queue and add controlling tty if not set.
193 mop = allocb(sizeof (struct stroptions), BPRI_MED);
194 if (mop == NULL) {
195 freemsg(ntp->dack_ptr);
196 kmem_free(ntp, sizeof (*ntp));
197 return (EAGAIN);
199 mop->b_datap->db_type = M_SETOPTS;
200 mop->b_wptr += sizeof (struct stroptions);
201 sop = (struct stroptions *)mop->b_rptr;
202 sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
203 sop->so_hiwat = _TTY_BUFSIZ;
204 sop->so_lowat = 256;
207 * Cross-link.
209 ntp->q_ptr = q;
210 q->q_ptr = ntp;
211 WR(q)->q_ptr = ntp;
214 * Get termios defaults. These are stored as
215 * a property in the "options" node.
217 if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 0, "ttymodes",
218 (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
219 len == sizeof (struct termios)) {
221 ntp->cflags = termiosp->c_cflag;
222 kmem_free(termiosp, len);
223 } else {
225 * Gack! Whine about it.
227 cmn_err(CE_WARN, "ptem: Couldn't get ttymodes property!");
229 ntp->wsz.ws_row = 0;
230 ntp->wsz.ws_col = 0;
231 ntp->wsz.ws_xpixel = 0;
232 ntp->wsz.ws_ypixel = 0;
234 ntp->state = 0;
237 * Commit to the open and send the M_SETOPTS off to the stream head.
239 qprocson(q);
240 putnext(q, mop);
242 return (0);
247 * ptemclose - This routine gets called when the module gets popped off of the
248 * stream.
250 /* ARGSUSED */
251 static int
252 ptemclose(queue_t *q, int flag, cred_t *credp)
254 struct ptem *ntp; /* ptem entry for this PTEM module */
256 qprocsoff(q);
257 ntp = (struct ptem *)q->q_ptr;
258 freemsg(ntp->dack_ptr);
259 kmem_free(ntp, sizeof (*ntp));
260 q->q_ptr = WR(q)->q_ptr = NULL;
261 return (0);
266 * ptemrput - Module read queue put procedure.
268 * This is called from the module or driver downstream.
270 static void
271 ptemrput(queue_t *q, mblk_t *mp)
273 struct iocblk *iocp; /* M_IOCTL data */
274 struct copyresp *resp; /* transparent ioctl response struct */
275 int error;
277 switch (mp->b_datap->db_type) {
278 case M_DELAY:
279 case M_READ:
280 freemsg(mp);
281 break;
283 case M_IOCTL:
284 iocp = (struct iocblk *)mp->b_rptr;
286 switch (iocp->ioc_cmd) {
287 case TCSBRK:
289 * Send a break message upstream.
291 * XXX: Shouldn't the argument come into play in
292 * determining whether or not so send an M_BREAK?
293 * It certainly does in the write-side direction.
295 error = miocpullup(mp, sizeof (int));
296 if (error != 0) {
297 miocnak(q, mp, 0, error);
298 break;
300 if (!(*(int *)mp->b_cont->b_rptr)) {
301 if (!putnextctl(q, M_BREAK)) {
303 * Send an NAK reply back
305 miocnak(q, mp, 0, EAGAIN);
306 break;
310 * ACK it.
312 mioc2ack(mp, NULL, 0, 0);
313 qreply(q, mp);
314 break;
316 case JWINSIZE:
317 case TIOCGWINSZ:
318 case TIOCSWINSZ:
319 ptioc(q, mp, RDSIDE);
320 break;
322 case TIOCSIGNAL:
324 * The following subtle logic is due to the fact that
325 * `mp' may be in any one of three distinct formats:
327 * 1. A transparent M_IOCTL with an intptr_t-sized
328 * payload containing the signal number.
330 * 2. An I_STR M_IOCTL with an int-sized payload
331 * containing the signal number.
333 * 3. An M_IOCDATA with an int-sized payload
334 * containing the signal number.
336 if (iocp->ioc_count == TRANSPARENT) {
337 intptr_t sig = *(intptr_t *)mp->b_cont->b_rptr;
339 if (sig < 1 || sig >= NSIG) {
341 * it's transparent with pointer
342 * to the arg
344 mcopyin(mp, NULL, sizeof (int), NULL);
345 qreply(q, mp);
346 break;
349 ptioc(q, mp, RDSIDE);
350 break;
352 case TIOCREMOTE:
353 if (iocp->ioc_count != TRANSPARENT)
354 ptioc(q, mp, RDSIDE);
355 else {
356 mcopyin(mp, NULL, sizeof (int), NULL);
357 qreply(q, mp);
359 break;
361 default:
362 putnext(q, mp);
363 break;
365 break;
367 case M_IOCDATA:
368 resp = (struct copyresp *)mp->b_rptr;
369 if (resp->cp_rval) {
371 * Just free message on failure.
373 freemsg(mp);
374 break;
378 * Only need to copy data for the SET case.
380 switch (resp->cp_cmd) {
382 case TIOCSWINSZ:
383 case TIOCSIGNAL:
384 case TIOCREMOTE:
385 ptioc(q, mp, RDSIDE);
386 break;
388 case JWINSIZE:
389 case TIOCGWINSZ:
390 mp->b_datap->db_type = M_IOCACK;
391 mioc2ack(mp, NULL, 0, 0);
392 qreply(q, mp);
393 break;
395 default:
396 freemsg(mp);
397 break;
399 break;
401 case M_IOCACK:
402 case M_IOCNAK:
404 * We only pass write-side ioctls through to the master that
405 * we've already ACKed or NAKed to the stream head. Thus, we
406 * discard ones arriving from below, since they're redundant
407 * from the point of view of modules above us.
409 freemsg(mp);
410 break;
412 case M_HANGUP:
414 * clear blocked state.
417 struct ptem *ntp = (struct ptem *)q->q_ptr;
418 if (ntp->state & OFLOW_CTL) {
419 ntp->state &= ~OFLOW_CTL;
420 qenable(WR(q));
423 /* FALLTHROUGH */
424 default:
425 putnext(q, mp);
426 break;
432 * ptemwput - Module write queue put procedure.
434 * This is called from the module or stream head upstream.
436 * XXX: This routine is quite lazy about handling allocation failures,
437 * basically just giving up and reporting failure. It really ought to
438 * set up bufcalls and only fail when it's absolutely necessary.
440 static void
441 ptemwput(queue_t *q, mblk_t *mp)
443 struct ptem *ntp = (struct ptem *)q->q_ptr;
444 struct iocblk *iocp; /* outgoing ioctl structure */
445 struct copyresp *resp;
446 unsigned char type = mp->b_datap->db_type;
448 if (type >= QPCTL) {
449 switch (type) {
451 case M_IOCDATA:
452 resp = (struct copyresp *)mp->b_rptr;
453 if (resp->cp_rval) {
455 * Just free message on failure.
457 freemsg(mp);
458 break;
462 * Only need to copy data for the SET case.
464 switch (resp->cp_cmd) {
466 case TIOCSWINSZ:
467 ptioc(q, mp, WRSIDE);
468 break;
470 case JWINSIZE:
471 case TIOCGWINSZ:
472 mioc2ack(mp, NULL, 0, 0);
473 qreply(q, mp);
474 break;
476 default:
477 freemsg(mp);
479 break;
481 case M_FLUSH:
482 if (*mp->b_rptr & FLUSHW) {
483 if ((ntp->state & IS_PTSTTY) &&
484 (*mp->b_rptr & FLUSHBAND))
485 flushband(q, *(mp->b_rptr + 1),
486 FLUSHDATA);
487 else
488 flushq(q, FLUSHDATA);
490 putnext(q, mp);
491 break;
493 case M_READ:
494 freemsg(mp);
495 break;
497 case M_STOP:
499 * Set the output flow control state.
501 ntp->state |= OFLOW_CTL;
502 putnext(q, mp);
503 break;
505 case M_START:
507 * Relieve the output flow control state.
509 ntp->state &= ~OFLOW_CTL;
510 putnext(q, mp);
511 qenable(q);
512 break;
513 default:
514 putnext(q, mp);
515 break;
517 return;
520 * If our queue is nonempty or flow control persists
521 * downstream or module in stopped state, queue this message.
523 if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
525 * Exception: ioctls, except for those defined to
526 * take effect after output has drained, should be
527 * processed immediately.
529 switch (type) {
531 case M_IOCTL:
532 iocp = (struct iocblk *)mp->b_rptr;
533 switch (iocp->ioc_cmd) {
535 * Queue these.
537 case TCSETSW:
538 case TCSETSF:
539 case TCSETAW:
540 case TCSETAF:
541 case TCSBRK:
542 break;
545 * Handle all others immediately.
547 default:
548 (void) ptemwmsg(q, mp);
549 return;
551 break;
553 case M_DELAY: /* tty delays not supported */
554 freemsg(mp);
555 return;
557 case M_DATA:
558 if ((mp->b_wptr - mp->b_rptr) < 0) {
560 * Free all bad length messages.
562 freemsg(mp);
563 return;
564 } else if ((mp->b_wptr - mp->b_rptr) == 0) {
565 if (!(ntp->state & IS_PTSTTY)) {
566 freemsg(mp);
567 return;
571 (void) putq(q, mp);
572 return;
575 * fast path into ptemwmsg to dispose of mp.
577 if (!ptemwmsg(q, mp))
578 (void) putq(q, mp);
582 * ptem write queue service procedure.
584 static void
585 ptemwsrv(queue_t *q)
587 mblk_t *mp;
589 while ((mp = getq(q)) != NULL) {
590 if (!bcanputnext(q, mp->b_band) || !ptemwmsg(q, mp)) {
591 (void) putbq(q, mp);
592 break;
599 * This routine is called from both ptemwput and ptemwsrv to do the
600 * actual work of dealing with mp. ptmewput will have already
601 * dealt with high priority messages.
603 * Return 1 if the message was processed completely and 0 if not.
605 static int
606 ptemwmsg(queue_t *q, mblk_t *mp)
608 struct ptem *ntp = (struct ptem *)q->q_ptr;
609 struct iocblk *iocp; /* outgoing ioctl structure */
610 struct termio *termiop;
611 struct termios *termiosp;
612 mblk_t *dack_ptr; /* disconnect message ACK block */
613 mblk_t *pckt_msgp; /* message sent to the PCKT module */
614 mblk_t *dp; /* ioctl reply data */
615 tcflag_t cflags;
616 int error;
618 switch (mp->b_datap->db_type) {
620 case M_IOCTL:
622 * Note: for each "set" type operation a copy
623 * of the M_IOCTL message is made and passed
624 * downstream. Eventually the PCKT module, if
625 * it has been pushed, should pick up this message.
626 * If the PCKT module has not been pushed the master
627 * side stream head will free it.
629 iocp = (struct iocblk *)mp->b_rptr;
630 switch (iocp->ioc_cmd) {
632 case TCSETAF:
633 case TCSETSF:
635 * Flush the read queue.
637 if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) {
638 miocnak(q, mp, 0, EAGAIN);
639 break;
641 /* FALLTHROUGH */
643 case TCSETA:
644 case TCSETAW:
645 case TCSETS:
646 case TCSETSW:
648 switch (iocp->ioc_cmd) {
649 case TCSETAF:
650 case TCSETA:
651 case TCSETAW:
652 error = miocpullup(mp, sizeof (struct termio));
653 if (error != 0) {
654 miocnak(q, mp, 0, error);
655 goto out;
657 cflags = ((struct termio *)
658 mp->b_cont->b_rptr)->c_cflag;
659 ntp->cflags =
660 (ntp->cflags & 0xffff0000 | cflags);
661 break;
663 case TCSETSF:
664 case TCSETS:
665 case TCSETSW:
666 error = miocpullup(mp, sizeof (struct termios));
667 if (error != 0) {
668 miocnak(q, mp, 0, error);
669 goto out;
671 cflags = ((struct termios *)
672 mp->b_cont->b_rptr)->c_cflag;
673 ntp->cflags = cflags;
674 break;
677 if ((cflags & CBAUD) == B0) {
679 * Hang-up: Send a zero length message.
681 dack_ptr = ntp->dack_ptr;
683 if (dack_ptr) {
684 ntp->dack_ptr = NULL;
686 * Send a zero length message
687 * downstream.
689 putnext(q, dack_ptr);
691 } else {
693 * Make a copy of this message and pass it on
694 * to the PCKT module.
696 if ((pckt_msgp = copymsg(mp)) == NULL) {
697 miocnak(q, mp, 0, EAGAIN);
698 break;
700 putnext(q, pckt_msgp);
703 * Send ACK upstream.
705 mioc2ack(mp, NULL, 0, 0);
706 qreply(q, mp);
707 out:
708 break;
710 case TCGETA:
711 dp = allocb(sizeof (struct termio), BPRI_MED);
712 if (dp == NULL) {
713 miocnak(q, mp, 0, EAGAIN);
714 break;
716 termiop = (struct termio *)dp->b_rptr;
717 termiop->c_cflag = (ushort_t)ntp->cflags;
718 mioc2ack(mp, dp, sizeof (struct termio), 0);
719 qreply(q, mp);
720 break;
722 case TCGETS:
723 dp = allocb(sizeof (struct termios), BPRI_MED);
724 if (dp == NULL) {
725 miocnak(q, mp, 0, EAGAIN);
726 break;
728 termiosp = (struct termios *)dp->b_rptr;
729 termiosp->c_cflag = ntp->cflags;
730 mioc2ack(mp, dp, sizeof (struct termios), 0);
731 qreply(q, mp);
732 break;
734 case TCSBRK:
735 error = miocpullup(mp, sizeof (int));
736 if (error != 0) {
737 miocnak(q, mp, 0, error);
738 break;
742 * Need a copy of this message to pass it on to
743 * the PCKT module.
745 if ((pckt_msgp = copymsg(mp)) == NULL) {
746 miocnak(q, mp, 0, EAGAIN);
747 break;
750 * Send a copy of the M_IOCTL to the PCKT module.
752 putnext(q, pckt_msgp);
755 * TCSBRK meaningful if data part of message is 0
756 * cf. termio(7).
758 if (!(*(int *)mp->b_cont->b_rptr))
759 (void) putnextctl(q, M_BREAK);
761 * ACK the ioctl.
763 mioc2ack(mp, NULL, 0, 0);
764 qreply(q, mp);
765 break;
767 case JWINSIZE:
768 case TIOCGWINSZ:
769 case TIOCSWINSZ:
770 ptioc(q, mp, WRSIDE);
771 break;
773 case TIOCSTI:
775 * Simulate typing of a character at the terminal. In
776 * all cases, we acknowledge the ioctl and pass a copy
777 * of it along for the PCKT module to encapsulate. If
778 * not in remote mode, we also process the ioctl
779 * itself, looping the character given as its argument
780 * back around to the read side.
784 * Need a copy of this message to pass on to the PCKT
785 * module.
787 if ((pckt_msgp = copymsg(mp)) == NULL) {
788 miocnak(q, mp, 0, EAGAIN);
789 break;
791 if ((ntp->state & REMOTEMODE) == 0) {
792 mblk_t *bp;
794 error = miocpullup(mp, sizeof (char));
795 if (error != 0) {
796 freemsg(pckt_msgp);
797 miocnak(q, mp, 0, error);
798 break;
802 * The permission checking has already been
803 * done at the stream head, since it has to be
804 * done in the context of the process doing
805 * the call.
807 if ((bp = allocb(1, BPRI_MED)) == NULL) {
808 freemsg(pckt_msgp);
809 miocnak(q, mp, 0, EAGAIN);
810 break;
813 * XXX: Is EAGAIN really the right response to
814 * flow control blockage?
816 if (!bcanputnext(RD(q), mp->b_band)) {
817 freemsg(bp);
818 freemsg(pckt_msgp);
819 miocnak(q, mp, 0, EAGAIN);
820 break;
822 *bp->b_wptr++ = *mp->b_cont->b_rptr;
823 qreply(q, bp);
826 putnext(q, pckt_msgp);
827 mioc2ack(mp, NULL, 0, 0);
828 qreply(q, mp);
829 break;
831 case PTSSTTY:
832 if (ntp->state & IS_PTSTTY) {
833 miocnak(q, mp, 0, EEXIST);
834 } else {
835 ntp->state |= IS_PTSTTY;
836 mioc2ack(mp, NULL, 0, 0);
837 qreply(q, mp);
839 break;
841 default:
843 * End of the line. The slave driver doesn't see any
844 * ioctls that we don't explicitly pass along to it.
846 miocnak(q, mp, 0, EINVAL);
847 break;
849 break;
851 case M_DELAY: /* tty delays not supported */
852 freemsg(mp);
853 break;
855 case M_DATA:
856 if ((mp->b_wptr - mp->b_rptr) < 0) {
858 * Free all bad length messages.
860 freemsg(mp);
861 break;
862 } else if ((mp->b_wptr - mp->b_rptr) == 0) {
863 if (!(ntp->state & IS_PTSTTY)) {
864 freemsg(mp);
865 break;
868 if (ntp->state & OFLOW_CTL)
869 return (0);
870 /* FALLTHROUGH */
872 default:
873 putnext(q, mp);
874 break;
878 return (1);
882 * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called.
884 static void
885 ptioc(queue_t *q, mblk_t *mp, int qside)
887 struct ptem *tp;
888 struct iocblk *iocp;
889 struct winsize *wb;
890 struct jwinsize *jwb;
891 mblk_t *tmp;
892 mblk_t *pckt_msgp; /* message sent to the PCKT module */
893 int error;
895 iocp = (struct iocblk *)mp->b_rptr;
896 tp = (struct ptem *)q->q_ptr;
898 switch (iocp->ioc_cmd) {
900 case JWINSIZE:
902 * For compatibility: If all zeros, NAK the message for dumb
903 * terminals.
905 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
906 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
907 miocnak(q, mp, 0, EINVAL);
908 return;
911 tmp = allocb(sizeof (struct jwinsize), BPRI_MED);
912 if (tmp == NULL) {
913 miocnak(q, mp, 0, EAGAIN);
914 return;
917 if (iocp->ioc_count == TRANSPARENT)
918 mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp);
919 else
920 mioc2ack(mp, tmp, sizeof (struct jwinsize), 0);
922 jwb = (struct jwinsize *)mp->b_cont->b_rptr;
923 jwb->bytesx = tp->wsz.ws_col;
924 jwb->bytesy = tp->wsz.ws_row;
925 jwb->bitsx = tp->wsz.ws_xpixel;
926 jwb->bitsy = tp->wsz.ws_ypixel;
928 qreply(q, mp);
929 return;
931 case TIOCGWINSZ:
933 * If all zeros NAK the message for dumb terminals.
935 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
936 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
937 miocnak(q, mp, 0, EINVAL);
938 return;
941 tmp = allocb(sizeof (struct winsize), BPRI_MED);
942 if (tmp == NULL) {
943 miocnak(q, mp, 0, EAGAIN);
944 return;
947 mioc2ack(mp, tmp, sizeof (struct winsize), 0);
949 wb = (struct winsize *)mp->b_cont->b_rptr;
950 wb->ws_row = tp->wsz.ws_row;
951 wb->ws_col = tp->wsz.ws_col;
952 wb->ws_xpixel = tp->wsz.ws_xpixel;
953 wb->ws_ypixel = tp->wsz.ws_ypixel;
955 qreply(q, mp);
956 return;
958 case TIOCSWINSZ:
959 error = miocpullup(mp, sizeof (struct winsize));
960 if (error != 0) {
961 miocnak(q, mp, 0, error);
962 return;
965 wb = (struct winsize *)mp->b_cont->b_rptr;
967 * Send a SIGWINCH signal if the row/col information has
968 * changed.
970 if ((tp->wsz.ws_row != wb->ws_row) ||
971 (tp->wsz.ws_col != wb->ws_col) ||
972 (tp->wsz.ws_xpixel != wb->ws_xpixel) ||
973 (tp->wsz.ws_ypixel != wb->ws_xpixel)) {
975 * SIGWINCH is always sent upstream.
977 if (qside == WRSIDE)
978 (void) putnextctl1(RD(q), M_SIG, SIGWINCH);
979 else if (qside == RDSIDE)
980 (void) putnextctl1(q, M_SIG, SIGWINCH);
982 * Message may have come in as an M_IOCDATA; pass it
983 * to the master side as an M_IOCTL.
985 mp->b_datap->db_type = M_IOCTL;
986 if (qside == WRSIDE) {
988 * Need a copy of this message to pass on to
989 * the PCKT module, only if the M_IOCTL
990 * orginated from the slave side.
992 if ((pckt_msgp = copymsg(mp)) == NULL) {
993 miocnak(q, mp, 0, EAGAIN);
994 return;
996 putnext(q, pckt_msgp);
998 tp->wsz.ws_row = wb->ws_row;
999 tp->wsz.ws_col = wb->ws_col;
1000 tp->wsz.ws_xpixel = wb->ws_xpixel;
1001 tp->wsz.ws_ypixel = wb->ws_ypixel;
1004 mioc2ack(mp, NULL, 0, 0);
1005 qreply(q, mp);
1006 return;
1008 case TIOCSIGNAL: {
1010 * This ioctl can emanate from the master side in remote
1011 * mode only.
1013 int sig;
1015 if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) {
1016 error = miocpullup(mp, sizeof (int));
1017 if (error != 0) {
1018 miocnak(q, mp, 0, error);
1019 return;
1023 if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT)
1024 sig = *(int *)mp->b_cont->b_rptr;
1025 else
1026 sig = (int)*(intptr_t *)mp->b_cont->b_rptr;
1028 if (sig < 1 || sig >= NSIG) {
1029 miocnak(q, mp, 0, EINVAL);
1030 return;
1034 * Send an M_PCSIG message up the slave's read side and
1035 * respond back to the master with an ACK or NAK as
1036 * appropriate.
1038 if (putnextctl1(q, M_PCSIG, sig) == 0) {
1039 miocnak(q, mp, 0, EAGAIN);
1040 return;
1043 mioc2ack(mp, NULL, 0, 0);
1044 qreply(q, mp);
1045 return;
1048 case TIOCREMOTE: {
1049 int onoff;
1050 mblk_t *mctlp;
1052 if (DB_TYPE(mp) == M_IOCTL) {
1053 error = miocpullup(mp, sizeof (int));
1054 if (error != 0) {
1055 miocnak(q, mp, 0, error);
1056 return;
1060 onoff = *(int *)mp->b_cont->b_rptr;
1063 * Send M_CTL up using the iocblk format.
1065 mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON);
1066 if (mctlp == NULL) {
1067 miocnak(q, mp, 0, EAGAIN);
1068 return;
1070 mctlp->b_datap->db_type = M_CTL;
1071 putnext(q, mctlp);
1074 * ACK the ioctl.
1076 mioc2ack(mp, NULL, 0, 0);
1077 qreply(q, mp);
1080 * Record state change.
1082 if (onoff)
1083 tp->state |= REMOTEMODE;
1084 else
1085 tp->state &= ~REMOTEMODE;
1086 return;
1089 default:
1090 putnext(q, mp);
1091 return;