4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
40 * Module to intercept old V7 and 4BSD "ioctl" calls.
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/signal.h>
47 #include <sys/termios.h>
48 #include <sys/ttold.h>
49 #include <sys/cmn_err.h>
50 #include <sys/stream.h>
51 #include <sys/stropts.h>
52 #include <sys/strsubr.h>
53 #include <sys/strsun.h>
54 #include <sys/errno.h>
55 #include <sys/debug.h>
56 #include <sys/ttcompat.h>
58 #include <sys/sunddi.h>
60 #include <sys/policy.h>
63 * This is the loadable module wrapper.
66 #include <sys/modctl.h>
68 /* See os/streamio.c */
69 extern int sgttyb_handling
;
71 static struct streamtab ttcoinfo
;
73 static struct fmodsw fsw
= {
80 * Module linkage information for the kernel.
83 static struct modlstrmod modlstrmod
= {
89 static struct modlinkage modlinkage
= {
90 MODREV_1
, &modlstrmod
, NULL
96 return (mod_install(&modlinkage
));
102 return (mod_remove(&modlinkage
));
106 _info(struct modinfo
*modinfop
)
108 return (mod_info(&modlinkage
, modinfop
));
111 static int ttcompatopen(queue_t
*, dev_t
*, int, int, cred_t
*);
112 static int ttcompatclose(queue_t
*, int, cred_t
*);
113 static void ttcompatrput(queue_t
*, mblk_t
*);
114 static void ttcompatwput(queue_t
*, mblk_t
*);
116 static struct module_info ttycompatmiinfo
= {
125 static struct qinit ttycompatrinit
= {
126 (int (*)())ttcompatrput
,
134 static struct module_info ttycompatmoinfo
= {
143 static struct qinit ttycompatwinit
= {
144 (int (*)())ttcompatwput
,
152 static struct streamtab ttcoinfo
= {
160 * This is the termios structure that is used to reset terminal settings
161 * when the underlying device is an instance of zcons. It came from
162 * cmd/init/init.c and should be kept in-sync with dflt_termios found therein.
164 static const struct termios base_termios
= {
165 BRKINT
|ICRNL
|IXON
|IMAXBEL
, /* iflag */
166 OPOST
|ONLCR
|TAB3
, /* oflag */
167 CS8
|CREAD
|B9600
, /* cflag */
168 ISIG
|ICANON
|ECHO
|ECHOE
|ECHOK
|ECHOCTL
|ECHOKE
|IEXTEN
, /* lflag */
169 CINTR
, CQUIT
, CERASE
, CKILL
, CEOF
, 0, 0, 0, 0, 0, 0, 0, /* c_cc vals */
174 static void ttcompat_do_ioctl(ttcompat_state_t
*, queue_t
*, mblk_t
*);
175 static void ttcompat_ioctl_ack(queue_t
*, mblk_t
*);
176 static void ttcopyout(queue_t
*, mblk_t
*);
177 static void ttcompat_ioctl_nak(queue_t
*, mblk_t
*);
178 static void from_compat(compat_state_t
*, struct termios
*);
179 static void to_compat(struct termios
*, compat_state_t
*);
182 * Open - get the current modes and translate them to the V7/4BSD equivalent.
186 ttcompatopen(queue_t
*q
, dev_t
*devp
, int oflag
, int sflag
, cred_t
*crp
)
188 ttcompat_state_t
*tp
;
194 if (q
->q_ptr
!= NULL
) {
195 tp
= (ttcompat_state_t
*)q
->q_ptr
;
196 /* fail open if TIOCEXCL was done and its not privileged */
197 if ((tp
->t_new_lflags
& XCLUDE
) &&
198 secpolicy_excl_open(crp
) != 0) {
201 return (0); /* already attached */
203 tp
= kmem_zalloc(sizeof (ttcompat_state_t
), KM_SLEEP
);
204 tp
->t_iocpending
= NULL
;
208 tp
->t_new_lflags
= 0;
209 tp
->t_curstate
.t_flags
= 0;
210 tp
->t_curstate
.t_ispeed
= B0
;
211 tp
->t_curstate
.t_ospeed
= B0
;
212 tp
->t_curstate
.t_erase
= '\0';
213 tp
->t_curstate
.t_kill
= '\0';
214 tp
->t_curstate
.t_intrc
= '\0';
215 tp
->t_curstate
.t_quitc
= '\0';
216 tp
->t_curstate
.t_startc
= '\0';
217 tp
->t_curstate
.t_stopc
= '\0';
218 tp
->t_curstate
.t_eofc
= '\0';
219 tp
->t_curstate
.t_brkc
= '\0';
220 tp
->t_curstate
.t_suspc
= '\0';
221 tp
->t_curstate
.t_dsuspc
= '\0';
222 tp
->t_curstate
.t_rprntc
= '\0';
223 tp
->t_curstate
.t_flushc
= '\0';
224 tp
->t_curstate
.t_werasc
= '\0';
225 tp
->t_curstate
.t_lnextc
= '\0';
226 tp
->t_curstate
.t_xflags
= 0;
235 * Determine if the underlying device is a zcons instance. If so,
236 * then issue a termios ioctl to reset the terminal settings.
238 if (getmajor(q
->q_stream
->sd_vnode
->v_rdev
) !=
239 ddi_name_to_major("zcons"))
243 * Create the ioctl message.
245 if ((mp
= mkiocb(TCSETSF
)) == NULL
) {
249 if ((datamp
= allocb(sizeof (struct termios
), BPRI_HI
)) == NULL
) {
254 iocb
= (struct iocblk
*)mp
->b_rptr
;
255 iocb
->ioc_count
= sizeof (struct termios
);
256 bcopy(&base_termios
, datamp
->b_rptr
, sizeof (struct termios
));
257 datamp
->b_wptr
+= sizeof (struct termios
);
261 * Send the ioctl message on its merry way toward the driver.
262 * Set some state beforehand so we can properly wait for
263 * an acknowledgement.
265 tp
->t_state
|= TS_IOCWAIT
| TS_TIOCNAK
;
266 tp
->t_iocid
= iocb
->ioc_id
;
267 tp
->t_ioccmd
= TCSETSF
;
271 * Wait for an acknowledgement. A NAK is treated as an error.
272 * The presence of the TS_TIOCNAK flag indicates that a NAK was
275 while (tp
->t_state
& TS_IOCWAIT
) {
276 if (qwait_sig(q
) == 0) {
281 if (!(tp
->t_state
& TS_TIOCNAK
))
287 kmem_free(tp
, sizeof (ttcompat_state_t
));
295 ttcompatclose(queue_t
*q
, int flag
, cred_t
*crp
)
297 ttcompat_state_t
*tp
= (ttcompat_state_t
*)q
->q_ptr
;
300 /* Dump the state structure, then unlink it */
302 if (tp
->t_bufcallid
!= 0) {
303 qunbufcall(q
, tp
->t_bufcallid
);
306 if ((mp
= tp
->t_iocpending
) != NULL
)
308 kmem_free(tp
, sizeof (ttcompat_state_t
));
315 * Put procedure for input from driver end of stream (read queue).
316 * Most messages just get passed to the next guy up; we intercept
317 * "ioctl" replies, and if it's an "ioctl" whose reply we plan to do
318 * something with, we do it.
321 ttcompatrput(queue_t
*q
, mblk_t
*mp
)
323 switch (mp
->b_datap
->db_type
) {
326 ttcompat_ioctl_ack(q
, mp
);
330 ttcompat_ioctl_nak(q
, mp
);
340 * Line discipline output queue put procedure: speeds M_IOCTL
344 ttcompatwput(queue_t
*q
, mblk_t
*mp
)
346 ttcompat_state_t
*tp
;
348 struct copyresp
*csp
;
349 struct iocblk
*iocbp
;
351 tp
= (ttcompat_state_t
*)q
->q_ptr
;
354 * Process some M_IOCTL messages here; pass everything else down.
356 switch (mp
->b_datap
->db_type
) {
363 iocbp
= (struct iocblk
*)mp
->b_rptr
;
365 switch (iocbp
->ioc_cmd
) {
368 /* these are ioctls with no arguments or are known to stream head */
369 /* process them right away */
370 ttcompat_do_ioctl(tp
, q
, mp
);
379 if (iocbp
->ioc_count
!= TRANSPARENT
) {
384 mp
->b_datap
->db_type
= M_COPYIN
;
385 cqp
= (struct copyreq
*)mp
->b_rptr
;
386 cqp
->cq_addr
= (caddr_t
)*(intptr_t *)mp
->b_cont
->b_rptr
;
387 switch (iocbp
->ioc_cmd
) {
389 cqp
->cq_size
= sizeof (struct sgttyb
);
392 cqp
->cq_size
= sizeof (struct ltchars
);
395 cqp
->cq_size
= sizeof (struct tchars
);
401 cqp
->cq_size
= sizeof (int);
407 cqp
->cq_private
= NULL
;
410 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct copyreq
);
411 tp
->t_ioccmd
= iocbp
->ioc_cmd
;
412 tp
->t_state
|= TS_W_IN
;
416 } /* switch ioc_cmd */
418 csp
= (struct copyresp
*)mp
->b_rptr
;
420 switch (csp
->cp_cmd
) {
433 tp
->t_state
&= ~TS_W_IN
;
434 if (csp
->cp_rval
!= 0) { /* failure */
439 /* make it look like an ioctl */
440 mp
->b_datap
->db_type
= M_IOCTL
;
441 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct iocblk
);
442 iocbp
= (struct iocblk
*)mp
->b_rptr
;
443 iocbp
->ioc_count
= MBLKL(mp
->b_cont
);
444 iocbp
->ioc_error
= 0;
446 ttcompat_do_ioctl(tp
, q
, mp
);
452 tp
->t_state
&= ~TS_W_OUT
;
453 if (csp
->cp_rval
!= 0) { /* failure */
458 iocbp
= (struct iocblk
*)mp
->b_rptr
;
459 iocbp
->ioc_count
= 0;
460 iocbp
->ioc_error
= 0;
462 mp
->b_datap
->db_type
= M_IOCACK
;
466 } /* switch cp_cmd */
467 } /* end message switch */
471 * Retry an "ioctl", now that "bufcall" claims we may be able to allocate
472 * the buffer we need.
475 ttcompat_reioctl(void *arg
)
478 ttcompat_state_t
*tp
;
481 tp
= (ttcompat_state_t
*)q
->q_ptr
;
484 if ((mp
= tp
->t_iocpending
) != NULL
) {
485 tp
->t_iocpending
= NULL
; /* not pending any more */
486 ttcompat_do_ioctl(tp
, q
, mp
);
491 * Handle old-style "ioctl" messages; pass the rest down unmolested.
494 ttcompat_do_ioctl(ttcompat_state_t
*tp
, queue_t
*q
, mblk_t
*mp
)
500 * Most of the miocpullup()'s below aren't needed because the
501 * ioctls in question are actually transparent M_IOCDATA messages
502 * dummied to look like M_IOCTL messages. However, for clarity and
503 * robustness against future changes, we've included them anyway.
506 iocp
= (struct iocblk
*)mp
->b_rptr
;
507 switch (iocp
->ioc_cmd
) {
510 * "get"-style calls that get translated data from the "termios"
511 * structure. Save the existing code and pass it down as a TCGETS.
516 if (iocp
->ioc_count
!= TRANSPARENT
) {
517 miocnak(q
, mp
, 0, EINVAL
);
522 * We can get here with t_arg != 0, iff the stream head
523 * has for some reason given up on the ioctl in progress.
524 * The most likely cause is an interrupted ioctl syscall.
525 * We will behave robustly because (given our perimeter)
526 * the ttcompat_state_t will get set up for the new ioctl,
527 * and when the response we were waiting for appears it
528 * will be passed on to the stream head which will discard
531 ASSERT(mp
->b_cont
!= NULL
);
532 tp
->t_arg
= *(intptr_t *)mp
->b_cont
->b_rptr
;
533 /* free the data buffer - it might not be sufficient */
534 /* driver will allocate one for termios size */
543 * "set"-style calls that set translated data into a "termios"
544 * structure. Set our idea of the new state from the value
545 * given to us. We then have to get the current state, so we
546 * turn this guy into a TCGETS and pass it down. When the
547 * ACK comes back, we modify the state we got back and shove it
548 * back down as the appropriate type of TCSETS.
552 error
= miocpullup(mp
, sizeof (struct sgttyb
));
554 miocnak(q
, mp
, 0, error
);
557 tp
->t_new_sgttyb
= *((struct sgttyb
*)mp
->b_cont
->b_rptr
);
561 error
= miocpullup(mp
, sizeof (struct tchars
));
563 miocnak(q
, mp
, 0, error
);
566 tp
->t_new_tchars
= *((struct tchars
*)mp
->b_cont
->b_rptr
);
570 error
= miocpullup(mp
, sizeof (struct ltchars
));
572 miocnak(q
, mp
, 0, error
);
575 tp
->t_new_ltchars
= *((struct ltchars
*)mp
->b_cont
->b_rptr
);
581 error
= miocpullup(mp
, sizeof (int));
583 miocnak(q
, mp
, 0, error
);
586 tp
->t_new_lflags
= *(int *)mp
->b_cont
->b_rptr
;
590 * "set"-style call that sets a particular bit in a "termios"
591 * structure. We then have to get the current state, so we
592 * turn this guy into a TCGETS and pass it down. When the
593 * ACK comes back, we modify the state we got back and shove it
594 * back down as the appropriate type of TCSETS.
598 tp
->t_ioccmd
= iocp
->ioc_cmd
;
599 tp
->t_iocid
= iocp
->ioc_id
;
600 tp
->t_state
|= TS_IOCWAIT
;
601 iocp
->ioc_cmd
= TCGETS
;
602 iocp
->ioc_count
= 0; /* no data returned unless we say so */
606 * "set"-style call that sets DTR. Pretend that it was a TIOCMBIS
607 * with TIOCM_DTR set.
612 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
614 *(int *)datap
->b_wptr
= TIOCM_DTR
;
615 datap
->b_wptr
+= sizeof (int);
616 iocp
->ioc_cmd
= TIOCMBIS
; /* turn it into a TIOCMBIS */
617 if (mp
->b_cont
!= NULL
)
619 mp
->b_cont
= datap
; /* attach the data */
620 iocp
->ioc_count
= sizeof (int); /* in case driver checks */
625 * "set"-style call that clears DTR. Pretend that it was a TIOCMBIC
626 * with TIOCM_DTR set.
631 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
633 *(int *)datap
->b_wptr
= TIOCM_DTR
;
634 datap
->b_wptr
+= sizeof (int);
635 iocp
->ioc_cmd
= TIOCMBIC
; /* turn it into a TIOCMBIC */
636 if (mp
->b_cont
!= NULL
)
638 mp
->b_cont
= datap
; /* attach the data */
639 iocp
->ioc_count
= sizeof (int); /* in case driver checks */
644 * Translate into the S5 form of TCFLSH.
649 error
= miocpullup(mp
, sizeof (int));
651 miocnak(q
, mp
, 0, error
);
654 flags
= *(int *)mp
->b_cont
->b_rptr
;
656 switch (flags
&(FREAD
|FWRITE
)) {
660 flags
= 2; /* flush 'em both */
664 flags
= 0; /* flush read */
668 flags
= 1; /* flush write */
671 iocp
->ioc_cmd
= TCFLSH
; /* turn it into a TCFLSH */
672 *(int *)mp
->b_cont
->b_rptr
= flags
; /* fiddle the arg */
677 * Turn into a TCXONC.
682 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
684 *(int *)datap
->b_wptr
= 0; /* stop */
685 datap
->b_wptr
+= sizeof (int);
686 iocp
->ioc_cmd
= TCXONC
; /* turn it into a XONC */
687 iocp
->ioc_count
= sizeof (int);
688 if (mp
->b_cont
!= NULL
)
690 mp
->b_cont
= datap
; /* attach the data */
697 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
)
699 *(int *)datap
->b_wptr
= 1; /* start */
700 datap
->b_wptr
+= sizeof (int);
701 iocp
->ioc_cmd
= TCXONC
; /* turn it into a XONC */
702 iocp
->ioc_count
= sizeof (int);
703 if (mp
->b_cont
!= NULL
)
705 mp
->b_cont
= datap
; /* attach the data */
718 * All of these ioctls are just ACK'd, except for
719 * TIOCSETD, which must be for line discipline zero.
721 mp
->b_datap
->db_type
= M_IOCACK
;
722 if (iocp
->ioc_cmd
== TIOCSETD
) {
723 iocp
->ioc_error
= miocpullup(mp
, sizeof (uchar_t
));
724 if (iocp
->ioc_error
== 0 && (*mp
->b_cont
->b_rptr
!= 0))
725 mp
->b_datap
->db_type
= M_IOCNAK
;
734 mp
->b_datap
->db_type
= M_IOCACK
;
737 iocp
->ioc_rval
= TIOC
;
741 /* check for binary value of XCLUDE flag ???? */
742 tp
->t_new_lflags
|= XCLUDE
;
743 mp
->b_datap
->db_type
= M_IOCACK
;
750 tp
->t_new_lflags
&= ~XCLUDE
;
751 mp
->b_datap
->db_type
= M_IOCACK
;
760 * We don't reply to most calls, we just pass them down,
761 * possibly after modifying the arguments.
768 * We needed to allocate something to handle this "ioctl", but
769 * couldn't; save this "ioctl" and arrange to get called back when
770 * it's more likely that we can get what we need.
771 * If there's already one being saved, throw it out, since it
772 * must have timed out.
774 if (tp
->t_iocpending
!= NULL
)
775 freemsg(tp
->t_iocpending
);
776 tp
->t_iocpending
= mp
; /* hold this ioctl */
777 if (tp
->t_bufcallid
!= 0)
778 qunbufcall(q
, tp
->t_bufcallid
);
780 tp
->t_bufcallid
= qbufcall(q
, sizeof (struct iocblk
), BPRI_HI
,
781 ttcompat_reioctl
, q
);
785 * Called when an M_IOCACK message is seen on the read queue; if this
786 * is the response we were waiting for, we either:
787 * modify the data going up (if the "ioctl" read data); since in all
788 * cases, the old-style returned information is smaller than or the same
789 * size as the new-style returned information, we just overwrite the old
790 * stuff with the new stuff (beware of changing structure sizes, in case
791 * you invalidate this)
793 * take this data, modify it appropriately, and send it back down (if
794 * the "ioctl" wrote data).
795 * In either case, we cancel the "wait"; the final response to a "write"
796 * ioctl goes back up to the user.
797 * If this wasn't the response we were waiting for, just pass it up.
800 ttcompat_ioctl_ack(queue_t
*q
, mblk_t
*mp
)
802 ttcompat_state_t
*tp
;
806 tp
= (ttcompat_state_t
*)q
->q_ptr
;
807 iocp
= (struct iocblk
*)mp
->b_rptr
;
809 if (!(tp
->t_state
&TS_IOCWAIT
) || iocp
->ioc_id
!= tp
->t_iocid
) {
811 * This isn't the reply we're looking for. Move along.
817 datap
= mp
->b_cont
; /* mblk containing data going up */
819 switch (tp
->t_ioccmd
) {
824 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
825 datap
->b_rptr
= datap
->b_wptr
= datap
->b_datap
->db_base
;
826 /* recycle the reply's buffer */
827 cb
= (struct sgttyb
*)datap
->b_wptr
;
829 * This is used for TIOCGETP handling of sg_ispeed and
830 * sg_ospeed. If the current speed is over 38400 (the
831 * sgttyb limit), then we report 38400. Note that
832 * when "compatibility with old releases" is enabled
833 * (sgttyb_handling == 0), then t_[io]speed will have
834 * garbled nonsense, as in prior releases. (See
835 * to_compat() below).
837 cb
->sg_ispeed
= tp
->t_curstate
.t_ispeed
> B38400
? B38400
:
838 tp
->t_curstate
.t_ispeed
;
839 cb
->sg_ospeed
= tp
->t_curstate
.t_ospeed
> B38400
? B38400
:
840 tp
->t_curstate
.t_ospeed
;
841 cb
->sg_erase
= tp
->t_curstate
.t_erase
;
842 cb
->sg_kill
= tp
->t_curstate
.t_kill
;
843 cb
->sg_flags
= tp
->t_curstate
.t_flags
;
844 datap
->b_wptr
+= sizeof (struct sgttyb
);
845 iocp
->ioc_count
= sizeof (struct sgttyb
);
847 /* you are lucky - stream head knows how to copy you out */
849 tp
->t_state
&= ~TS_IOCWAIT
; /* we got what we wanted */
851 iocp
->ioc_cmd
= tp
->t_ioccmd
;
857 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
858 datap
->b_rptr
= datap
->b_wptr
= datap
->b_datap
->db_base
;
859 /* recycle the reply's buffer */
860 bcopy(&tp
->t_curstate
.t_intrc
, datap
->b_wptr
,
861 sizeof (struct tchars
));
862 datap
->b_wptr
+= sizeof (struct tchars
);
866 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
867 datap
->b_rptr
= datap
->b_wptr
= datap
->b_datap
->db_base
;
868 /* recycle the reply's buffer */
869 bcopy(&tp
->t_curstate
.t_suspc
, datap
->b_wptr
,
870 sizeof (struct ltchars
));
871 datap
->b_wptr
+= sizeof (struct ltchars
);
875 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
876 datap
->b_rptr
= datap
->b_wptr
= datap
->b_datap
->db_base
;
877 /* recycle the reply's buffer */
878 *(int *)datap
->b_wptr
=
879 ((unsigned)tp
->t_curstate
.t_flags
) >> 16;
880 datap
->b_wptr
+= sizeof (int);
886 * Get the current state from the GETS data, and
889 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
890 tp
->t_curstate
.t_erase
= tp
->t_new_sgttyb
.sg_erase
;
891 tp
->t_curstate
.t_kill
= tp
->t_new_sgttyb
.sg_kill
;
893 * For new-style handling, we ignore requests to set
894 * B38400 when the current speed is over B38400. This
895 * means that we change the speed as requested if:
896 * old style (sgttyb_handling == 0) is requested
897 * the requested new speed isn't B38400
898 * the current speed is at or below B38400
899 * Note that when old style is requested, both speeds
900 * in t_curstate are set to <= B38400 by to_compat, so
901 * the first test isn't needed here.
902 * Also note that we silently allow the user to set
903 * speeds above B38400 through this interface,
904 * regardless of the style setting. This allows
905 * greater compatibility with current BSD releases.
907 if (tp
->t_new_sgttyb
.sg_ispeed
!= B38400
||
908 tp
->t_curstate
.t_ispeed
<= B38400
)
909 tp
->t_curstate
.t_ispeed
= tp
->t_new_sgttyb
.sg_ispeed
;
910 if (tp
->t_new_sgttyb
.sg_ospeed
!= B38400
||
911 tp
->t_curstate
.t_ospeed
<= B38400
)
912 tp
->t_curstate
.t_ospeed
= tp
->t_new_sgttyb
.sg_ospeed
;
913 tp
->t_curstate
.t_flags
=
914 (tp
->t_curstate
.t_flags
& 0xffff0000) |
915 (tp
->t_new_sgttyb
.sg_flags
& 0xffff);
918 * Replace the data that came up with the updated data.
920 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
923 * Send it back down as a TCSETS or TCSETSF.
925 iocp
->ioc_cmd
= (tp
->t_ioccmd
== TIOCSETP
) ? TCSETSF
: TCSETS
;
930 * Get the current state from the GETS data, and
933 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
934 bcopy(&tp
->t_new_tchars
,
935 &tp
->t_curstate
.t_intrc
, sizeof (struct tchars
));
938 * Replace the data that came up with the updated data.
940 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
943 * Send it back down as a TCSETS.
945 iocp
->ioc_cmd
= TCSETS
;
950 * Get the current state from the GETS data, and
953 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
954 bcopy(&tp
->t_new_ltchars
,
955 &tp
->t_curstate
.t_suspc
, sizeof (struct ltchars
));
958 * Replace the data that came up with the updated data.
960 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
963 * Send it back down as a TCSETS.
965 iocp
->ioc_cmd
= TCSETS
;
970 * Get the current state from the GETS data, and
973 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
974 tp
->t_curstate
.t_flags
|= (tp
->t_new_lflags
<< 16);
977 * Replace the data that came up with the updated data.
979 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
982 * Send it back down as a TCSETS.
984 iocp
->ioc_cmd
= TCSETS
;
989 * Get the current state from the GETS data, and
992 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
993 tp
->t_curstate
.t_flags
&= ~(tp
->t_new_lflags
<< 16);
996 * Replace the data that came up with the updated data.
998 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
1001 * Send it back down as a TCSETS.
1003 iocp
->ioc_cmd
= TCSETS
;
1008 * Get the current state from the GETS data, and
1011 to_compat((struct termios
*)datap
->b_rptr
, &tp
->t_curstate
);
1012 tp
->t_curstate
.t_flags
&= 0xffff;
1013 tp
->t_curstate
.t_flags
|= (tp
->t_new_lflags
<< 16);
1016 * Replace the data that came up with the updated data.
1018 from_compat(&tp
->t_curstate
, (struct termios
*)datap
->b_rptr
);
1021 * Send it back down as a TCSETS.
1023 iocp
->ioc_cmd
= TCSETS
;
1028 * Replace the data that came up with the updated data.
1030 ((struct termios
*)datap
->b_rptr
)->c_cflag
|= HUPCL
;
1033 * Send it back down as a TCSETS.
1035 iocp
->ioc_cmd
= TCSETS
;
1040 * We're acknowledging the terminal reset ioctl that we sent
1041 * when the module was opened.
1043 tp
->t_state
&= ~(TS_IOCWAIT
| TS_TIOCNAK
);
1048 cmn_err(CE_WARN
, "ttcompat: Unexpected ioctl acknowledgment\n");
1052 * All the calls that return something return 0.
1054 tp
->t_state
&= ~TS_IOCWAIT
; /* we got what we wanted */
1057 /* copy out the data - ioctl transparency */
1058 iocp
->ioc_cmd
= tp
->t_ioccmd
;
1064 * Send a "get state" reply back down, with suitably-modified
1065 * state, as a "set state" "ioctl".
1067 tp
->t_state
&= ~TS_IOCWAIT
;
1068 mp
->b_datap
->db_type
= M_IOCTL
;
1069 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct iocblk
);
1072 /* Called from ttcompatrput M_IOCACK processing. */
1073 /* Copies out the data using M_COPYOUT messages */
1076 ttcopyout(queue_t
*q
, mblk_t
*mp
)
1078 struct copyreq
*cqp
;
1079 ttcompat_state_t
*tp
;
1081 tp
= (ttcompat_state_t
*)q
->q_ptr
;
1083 mp
->b_datap
->db_type
= M_COPYOUT
;
1084 cqp
= (struct copyreq
*)mp
->b_rptr
;
1085 cqp
->cq_addr
= (caddr_t
)tp
->t_arg
; /* retrieve the 3rd argument */
1086 tp
->t_arg
= 0; /* clear it since we don't need it anymore */
1087 switch (tp
->t_ioccmd
) {
1089 cqp
->cq_size
= sizeof (struct ltchars
);
1092 cqp
->cq_size
= sizeof (struct tchars
);
1095 cqp
->cq_size
= sizeof (int);
1099 "ttcompat: Unknown ioctl to copyout\n");
1103 cqp
->cq_private
= NULL
;
1104 tp
->t_state
|= TS_W_OUT
;
1110 * Called when an M_IOCNAK message is seen on the read queue; if this is
1111 * the response we were waiting for, cancel the wait. Pass the reply up;
1112 * if we were waiting for this response, we can't complete the "ioctl" and
1113 * the NAK will tell that to the guy above us.
1114 * If this wasn't the response we were waiting for, just pass it up.
1117 ttcompat_ioctl_nak(queue_t
*q
, mblk_t
*mp
)
1119 ttcompat_state_t
*tp
;
1120 struct iocblk
*iocp
;
1122 iocp
= (struct iocblk
*)mp
->b_rptr
;
1123 tp
= (ttcompat_state_t
*)q
->q_ptr
;
1125 if (tp
->t_state
&TS_IOCWAIT
&& iocp
->ioc_id
== tp
->t_iocid
) {
1126 tp
->t_state
&= ~TS_IOCWAIT
; /* this call isn't going through */
1127 tp
->t_arg
= 0; /* we may have stashed the 3rd argument */
1132 #define FROM_COMPAT_CHAR(to, from) { if ((to = from) == 0377) to = 0; }
1135 from_compat(compat_state_t
*csp
, struct termios
*termiosp
)
1137 termiosp
->c_iflag
= 0;
1138 termiosp
->c_oflag
&= (ONLRET
|ONOCR
);
1140 termiosp
->c_cflag
= (termiosp
->c_cflag
&
1141 (CRTSCTS
|CRTSXOFF
|PAREXT
|LOBLK
|HUPCL
)) | CREAD
;
1143 if (csp
->t_ospeed
> CBAUD
) {
1144 termiosp
->c_cflag
|= ((csp
->t_ospeed
- CBAUD
- 1) & CBAUD
) |
1147 termiosp
->c_cflag
|= csp
->t_ospeed
& CBAUD
;
1150 if (csp
->t_ospeed
!= csp
->t_ispeed
) {
1151 if (csp
->t_ispeed
> (CIBAUD
>> IBSHIFT
)) {
1152 termiosp
->c_cflag
|= CIBAUDEXT
|
1153 (((csp
->t_ispeed
- (CIBAUD
>> IBSHIFT
) - 1) <<
1156 termiosp
->c_cflag
|= (csp
->t_ispeed
<< IBSHIFT
) &
1159 /* hang up if ispeed=0 */
1160 if (csp
->t_ispeed
== 0)
1161 termiosp
->c_cflag
&= ~CBAUD
& ~CBAUDEXT
;
1163 if (csp
->t_ispeed
== B110
|| csp
->t_xflags
& STOPB
)
1164 termiosp
->c_cflag
|= CSTOPB
;
1165 termiosp
->c_lflag
= ECHOK
;
1166 FROM_COMPAT_CHAR(termiosp
->c_cc
[VERASE
], csp
->t_erase
);
1167 FROM_COMPAT_CHAR(termiosp
->c_cc
[VKILL
], csp
->t_kill
);
1168 FROM_COMPAT_CHAR(termiosp
->c_cc
[VINTR
], csp
->t_intrc
);
1169 FROM_COMPAT_CHAR(termiosp
->c_cc
[VQUIT
], csp
->t_quitc
);
1170 FROM_COMPAT_CHAR(termiosp
->c_cc
[VSTART
], csp
->t_startc
);
1171 FROM_COMPAT_CHAR(termiosp
->c_cc
[VSTOP
], csp
->t_stopc
);
1172 termiosp
->c_cc
[VEOL2
] = 0;
1173 FROM_COMPAT_CHAR(termiosp
->c_cc
[VSUSP
], csp
->t_suspc
);
1174 /* is this useful? */
1175 FROM_COMPAT_CHAR(termiosp
->c_cc
[VDSUSP
], csp
->t_dsuspc
);
1176 FROM_COMPAT_CHAR(termiosp
->c_cc
[VREPRINT
], csp
->t_rprntc
);
1177 FROM_COMPAT_CHAR(termiosp
->c_cc
[VDISCARD
], csp
->t_flushc
);
1178 FROM_COMPAT_CHAR(termiosp
->c_cc
[VWERASE
], csp
->t_werasc
);
1179 FROM_COMPAT_CHAR(termiosp
->c_cc
[VLNEXT
], csp
->t_lnextc
);
1180 if (csp
->t_flags
& O_TANDEM
)
1181 termiosp
->c_iflag
|= IXOFF
;
1182 if (csp
->t_flags
& O_LCASE
) {
1183 termiosp
->c_iflag
|= IUCLC
;
1184 termiosp
->c_oflag
|= OLCUC
;
1185 termiosp
->c_lflag
|= XCASE
;
1187 if (csp
->t_flags
& O_ECHO
)
1188 termiosp
->c_lflag
|= ECHO
;
1189 if (csp
->t_flags
& O_CRMOD
) {
1190 termiosp
->c_iflag
|= ICRNL
;
1191 termiosp
->c_oflag
|= ONLCR
;
1192 switch (csp
->t_flags
& O_CRDELAY
) {
1195 termiosp
->c_oflag
|= CR2
;
1199 termiosp
->c_oflag
|= CR3
;
1203 if ((csp
->t_flags
& O_NLDELAY
) == O_NL1
)
1204 termiosp
->c_oflag
|= ONLRET
|CR1
; /* tty37 */
1206 if ((csp
->t_flags
& O_NLDELAY
) == O_NL2
)
1207 termiosp
->c_oflag
|= NL1
;
1209 * When going into RAW mode, the special characters controlled by the
1210 * POSIX IEXTEN bit no longer apply; when leaving, they do.
1212 if (csp
->t_flags
& O_RAW
) {
1213 termiosp
->c_cflag
|= CS8
;
1214 termiosp
->c_iflag
&= ~(ICRNL
|IUCLC
);
1215 termiosp
->c_lflag
&= ~(XCASE
|IEXTEN
);
1217 termiosp
->c_iflag
|= IMAXBEL
|BRKINT
|IGNPAR
;
1218 if (termiosp
->c_cc
[VSTOP
] != 0 && termiosp
->c_cc
[VSTART
] != 0)
1219 termiosp
->c_iflag
|= IXON
;
1220 if (csp
->t_flags
& O_LITOUT
)
1221 termiosp
->c_cflag
|= CS8
;
1223 if (csp
->t_flags
& O_PASS8
)
1224 termiosp
->c_cflag
|= CS8
;
1225 /* XXX - what about 8 bits plus parity? */
1227 switch (csp
->t_flags
& (O_EVENP
|O_ODDP
)) {
1230 termiosp
->c_iflag
|= ISTRIP
;
1231 termiosp
->c_cflag
|= CS8
;
1235 termiosp
->c_iflag
|= INPCK
|ISTRIP
;
1236 termiosp
->c_cflag
|= CS7
|PARENB
;
1240 termiosp
->c_iflag
|= INPCK
|ISTRIP
;
1241 termiosp
->c_cflag
|= CS7
|PARENB
|PARODD
;
1244 case O_EVENP
|O_ODDP
:
1245 termiosp
->c_iflag
|= ISTRIP
;
1246 termiosp
->c_cflag
|= CS7
|PARENB
;
1250 if (!(csp
->t_xflags
& NOPOST
))
1251 termiosp
->c_oflag
|= OPOST
;
1253 termiosp
->c_lflag
|= IEXTEN
;
1254 if (!(csp
->t_xflags
& NOISIG
))
1255 termiosp
->c_lflag
|= ISIG
;
1256 if (!(csp
->t_flags
& O_CBREAK
))
1257 termiosp
->c_lflag
|= ICANON
;
1258 if (csp
->t_flags
& O_CTLECH
)
1259 termiosp
->c_lflag
|= ECHOCTL
;
1261 switch (csp
->t_flags
& O_TBDELAY
) {
1264 termiosp
->c_oflag
|= TAB1
;
1268 termiosp
->c_oflag
|= TAB2
;
1272 termiosp
->c_oflag
|= TAB3
;
1275 if (csp
->t_flags
& O_VTDELAY
)
1276 termiosp
->c_oflag
|= FFDLY
;
1277 if (csp
->t_flags
& O_BSDELAY
)
1278 termiosp
->c_oflag
|= BSDLY
;
1279 if (csp
->t_flags
& O_PRTERA
)
1280 termiosp
->c_lflag
|= ECHOPRT
;
1281 if (csp
->t_flags
& O_CRTERA
)
1282 termiosp
->c_lflag
|= ECHOE
;
1283 if (csp
->t_flags
& O_TOSTOP
)
1284 termiosp
->c_lflag
|= TOSTOP
;
1285 if (csp
->t_flags
& O_FLUSHO
)
1286 termiosp
->c_lflag
|= FLUSHO
;
1287 if (csp
->t_flags
& O_NOHANG
)
1288 termiosp
->c_cflag
|= CLOCAL
;
1289 if (csp
->t_flags
& O_CRTKIL
)
1290 termiosp
->c_lflag
|= ECHOKE
;
1291 if (csp
->t_flags
& O_PENDIN
)
1292 termiosp
->c_lflag
|= PENDIN
;
1293 if (!(csp
->t_flags
& O_DECCTQ
))
1294 termiosp
->c_iflag
|= IXANY
;
1295 if (csp
->t_flags
& O_NOFLSH
)
1296 termiosp
->c_lflag
|= NOFLSH
;
1297 if (termiosp
->c_lflag
& ICANON
) {
1298 FROM_COMPAT_CHAR(termiosp
->c_cc
[VEOF
], csp
->t_eofc
);
1299 FROM_COMPAT_CHAR(termiosp
->c_cc
[VEOL
], csp
->t_brkc
);
1301 termiosp
->c_cc
[VMIN
] = 1;
1302 termiosp
->c_cc
[VTIME
] = 0;
1306 #define TO_COMPAT_CHAR(to, from) { if ((to = from) == 0) to = (uchar_t)0377; }
1309 to_compat(struct termios
*termiosp
, compat_state_t
*csp
)
1311 csp
->t_xflags
&= (NOISIG
|NOPOST
);
1312 csp
->t_ospeed
= termiosp
->c_cflag
& CBAUD
;
1313 csp
->t_ispeed
= (termiosp
->c_cflag
& CIBAUD
) >> IBSHIFT
;
1314 if (sgttyb_handling
> 0) {
1315 if (termiosp
->c_cflag
& CBAUDEXT
)
1316 csp
->t_ospeed
+= CBAUD
+ 1;
1317 if (termiosp
->c_cflag
& CIBAUDEXT
)
1318 csp
->t_ispeed
+= (CIBAUD
>> IBSHIFT
) + 1;
1320 if (csp
->t_ispeed
== 0)
1321 csp
->t_ispeed
= csp
->t_ospeed
;
1322 if ((termiosp
->c_cflag
& CSTOPB
) && csp
->t_ispeed
!= B110
)
1323 csp
->t_xflags
|= STOPB
;
1324 TO_COMPAT_CHAR(csp
->t_erase
, termiosp
->c_cc
[VERASE
]);
1325 TO_COMPAT_CHAR(csp
->t_kill
, termiosp
->c_cc
[VKILL
]);
1326 TO_COMPAT_CHAR(csp
->t_intrc
, termiosp
->c_cc
[VINTR
]);
1327 TO_COMPAT_CHAR(csp
->t_quitc
, termiosp
->c_cc
[VQUIT
]);
1328 TO_COMPAT_CHAR(csp
->t_startc
, termiosp
->c_cc
[VSTART
]);
1329 TO_COMPAT_CHAR(csp
->t_stopc
, termiosp
->c_cc
[VSTOP
]);
1330 TO_COMPAT_CHAR(csp
->t_suspc
, termiosp
->c_cc
[VSUSP
]);
1331 TO_COMPAT_CHAR(csp
->t_dsuspc
, termiosp
->c_cc
[VDSUSP
]);
1332 TO_COMPAT_CHAR(csp
->t_rprntc
, termiosp
->c_cc
[VREPRINT
]);
1333 TO_COMPAT_CHAR(csp
->t_flushc
, termiosp
->c_cc
[VDISCARD
]);
1334 TO_COMPAT_CHAR(csp
->t_werasc
, termiosp
->c_cc
[VWERASE
]);
1335 TO_COMPAT_CHAR(csp
->t_lnextc
, termiosp
->c_cc
[VLNEXT
]);
1336 csp
->t_flags
&= (O_CTLECH
|O_LITOUT
|O_PASS8
|O_ODDP
|O_EVENP
);
1337 if (termiosp
->c_iflag
& IXOFF
)
1338 csp
->t_flags
|= O_TANDEM
;
1339 if (!(termiosp
->c_iflag
&
1340 (IMAXBEL
|BRKINT
|IGNPAR
|PARMRK
|INPCK
|ISTRIP
|
1341 INLCR
|IGNCR
|ICRNL
|IUCLC
|IXON
)) &&
1342 !(termiosp
->c_oflag
& OPOST
) &&
1343 (termiosp
->c_cflag
& (CSIZE
|PARENB
)) == CS8
&&
1344 !(termiosp
->c_lflag
& (ISIG
|ICANON
|XCASE
|IEXTEN
)))
1345 csp
->t_flags
|= O_RAW
;
1347 if (!(termiosp
->c_iflag
& IXON
)) {
1348 csp
->t_startc
= (uchar_t
)0377;
1349 csp
->t_stopc
= (uchar_t
)0377;
1351 if ((termiosp
->c_cflag
& (CSIZE
|PARENB
)) == CS8
&&
1352 !(termiosp
->c_oflag
& OPOST
))
1353 csp
->t_flags
|= O_LITOUT
;
1355 csp
->t_flags
&= ~O_LITOUT
;
1356 if ((termiosp
->c_cflag
& (CSIZE
|PARENB
)) == CS8
) {
1357 if (!(termiosp
->c_iflag
& ISTRIP
))
1358 csp
->t_flags
|= O_PASS8
;
1360 csp
->t_flags
&= ~(O_ODDP
|O_EVENP
|O_PASS8
);
1361 if (termiosp
->c_cflag
& PARODD
)
1362 csp
->t_flags
|= O_ODDP
;
1363 else if (termiosp
->c_iflag
& INPCK
)
1364 csp
->t_flags
|= O_EVENP
;
1366 csp
->t_flags
|= O_ODDP
|O_EVENP
;
1368 if (!(termiosp
->c_oflag
& OPOST
))
1369 csp
->t_xflags
|= NOPOST
;
1371 csp
->t_xflags
&= ~NOPOST
;
1373 if (!(termiosp
->c_lflag
& ISIG
))
1374 csp
->t_xflags
|= NOISIG
;
1376 csp
->t_xflags
&= ~NOISIG
;
1377 if (!(termiosp
->c_lflag
& ICANON
))
1378 csp
->t_flags
|= O_CBREAK
;
1379 if (termiosp
->c_lflag
& ECHOCTL
)
1380 csp
->t_flags
|= O_CTLECH
;
1382 csp
->t_flags
&= ~O_CTLECH
;
1384 if (termiosp
->c_oflag
& OLCUC
)
1385 csp
->t_flags
|= O_LCASE
;
1386 if (termiosp
->c_lflag
&ECHO
)
1387 csp
->t_flags
|= O_ECHO
;
1388 if (termiosp
->c_oflag
& ONLCR
) {
1389 csp
->t_flags
|= O_CRMOD
;
1390 switch (termiosp
->c_oflag
& CRDLY
) {
1393 csp
->t_flags
|= O_CR1
;
1397 csp
->t_flags
|= O_CR2
;
1401 if ((termiosp
->c_oflag
& CR1
) &&
1402 (termiosp
->c_oflag
& ONLRET
))
1403 csp
->t_flags
|= O_NL1
; /* tty37 */
1405 if ((termiosp
->c_oflag
& ONLRET
) && (termiosp
->c_oflag
& NL1
))
1406 csp
->t_flags
|= O_NL2
;
1407 switch (termiosp
->c_oflag
& TABDLY
) {
1410 csp
->t_flags
|= O_TAB1
;
1414 csp
->t_flags
|= O_TAB2
;
1418 csp
->t_flags
|= O_XTABS
;
1421 if (termiosp
->c_oflag
& FFDLY
)
1422 csp
->t_flags
|= O_VTDELAY
;
1423 if (termiosp
->c_oflag
& BSDLY
)
1424 csp
->t_flags
|= O_BSDELAY
;
1425 if (termiosp
->c_lflag
& ECHOPRT
)
1426 csp
->t_flags
|= O_PRTERA
;
1427 if (termiosp
->c_lflag
& ECHOE
)
1428 csp
->t_flags
|= (O_CRTERA
|O_CRTBS
);
1429 if (termiosp
->c_lflag
& TOSTOP
)
1430 csp
->t_flags
|= O_TOSTOP
;
1431 if (termiosp
->c_lflag
& FLUSHO
)
1432 csp
->t_flags
|= O_FLUSHO
;
1433 if (termiosp
->c_cflag
& CLOCAL
)
1434 csp
->t_flags
|= O_NOHANG
;
1435 if (termiosp
->c_lflag
& ECHOKE
)
1436 csp
->t_flags
|= O_CRTKIL
;
1437 if (termiosp
->c_lflag
& PENDIN
)
1438 csp
->t_flags
|= O_PENDIN
;
1439 if (!(termiosp
->c_iflag
& IXANY
))
1440 csp
->t_flags
|= O_DECCTQ
;
1441 if (termiosp
->c_lflag
& NOFLSH
)
1442 csp
->t_flags
|= O_NOFLSH
;
1443 if (termiosp
->c_lflag
& ICANON
) {
1444 TO_COMPAT_CHAR(csp
->t_eofc
, termiosp
->c_cc
[VEOF
]);
1445 TO_COMPAT_CHAR(csp
->t_brkc
, termiosp
->c_cc
[VEOL
]);
1447 termiosp
->c_cc
[VMIN
] = 1;
1448 termiosp
->c_cc
[VTIME
] = 0;