/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
/*
* Module to intercept old V7 and 4BSD "ioctl" calls.
*/
#include <sys/ttcompat.h>
/*
* This is the loadable module wrapper.
*/
/* See os/streamio.c */
extern int sgttyb_handling;
"ttcompat",
&ttcoinfo,
};
/*
* Module linkage information for the kernel.
*/
"alt ioctl calls",
&fsw
};
};
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
return (mod_remove(&modlinkage));
}
int
{
}
0,
"ttcompat",
0,
2048,
128
};
(int (*)())ttcompatrput,
NULL,
NULL,
};
42,
"ttcompat",
0,
300,
200
};
(int (*)())ttcompatwput,
NULL,
NULL,
};
NULL,
};
/*
* This is the termios structure that is used to reset terminal settings
* when the underlying device is an instance of zcons. It came from
*/
0, 0, 0, 0, 0, 0, 0
};
/*
* Open - get the current modes and translate them to the V7/4BSD equivalent.
*/
/*ARGSUSED*/
static int
{
int error;
/* fail open if TIOCEXCL was done and its not privileged */
secpolicy_excl_open(crp) != 0) {
return (EBUSY);
}
return (0); /* already attached */
}
tp->t_new_lflags = 0;
tp->t_bufcallid = 0;
qprocson(q);
/*
* Determine if the underlying device is a zcons instance. If so,
* then issue a termios ioctl to reset the terminal settings.
*/
ddi_name_to_major("zcons"))
return (0);
/*
* Create the ioctl message.
*/
goto common_error;
}
goto common_error;
}
/*
* Send the ioctl message on its merry way toward the driver.
* Set some state beforehand so we can properly wait for
* an acknowledgement.
*/
/*
* Wait for an acknowledgement. A NAK is treated as an error.
* The presence of the TS_TIOCNAK flag indicates that a NAK was
* received.
*/
if (qwait_sig(q) == 0) {
goto common_error;
}
}
return (0);
qprocsoff(q);
return (error);
}
/* ARGSUSED1 */
static int
{
/* Dump the state structure, then unlink it */
qprocsoff(q);
if (tp->t_bufcallid != 0) {
tp->t_bufcallid = 0;
}
return (0);
}
/*
* Put procedure for input from driver end of stream (read queue).
* Most messages just get passed to the next guy up; we intercept
* "ioctl" replies, and if it's an "ioctl" whose reply we plan to do
* something with, we do it.
*/
static void
{
case M_IOCACK:
ttcompat_ioctl_ack(q, mp);
break;
case M_IOCNAK:
ttcompat_ioctl_nak(q, mp);
break;
default:
break;
}
}
/*
* Line discipline output queue put procedure: speeds M_IOCTL
* messages.
*/
static void
{
/*
* Process some M_IOCTL messages here; pass everything else down.
*/
default:
return;
case M_IOCTL:
default:
/* these are ioctls with no arguments or are known to stream head */
/* process them right away */
return;
case TIOCSETN:
case TIOCSLTC:
case TIOCSETC:
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
case TIOCFLUSH:
return;
}
case TIOCSETN:
break;
case TIOCSLTC:
break;
case TIOCSETC:
break;
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
case TIOCFLUSH:
break;
default:
break;
}
return;
} /* switch ioc_cmd */
case M_IOCDATA:
default:
return;
case TIOCSETN:
case TIOCSLTC:
case TIOCSETC:
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
case TIOCFLUSH:
return;
}
/* make it look like an ioctl */
return;
case TIOCGLTC:
case TIOCLGET:
case TIOCGETC:
return;
}
return;
} /* switch cp_cmd */
} /* end message switch */
}
/*
* Retry an "ioctl", now that "bufcall" claims we may be able to allocate
* the buffer we need.
*/
static void
{
tp->t_bufcallid = 0;
}
}
/*
* Handle old-style "ioctl" messages; pass the rest down unmolested.
*/
static void
{
int error;
/*
* Most of the miocpullup()'s below aren't needed because the
* ioctls in question are actually transparent M_IOCDATA messages
* dummied to look like M_IOCTL messages. However, for clarity and
* robustness against future changes, we've included them anyway.
*/
/*
* "get"-style calls that get translated data from the "termios"
* structure. Save the existing code and pass it down as a TCGETS.
*/
case TIOCGETC:
case TIOCLGET:
case TIOCGLTC:
return;
}
/*
* We can get here with t_arg != 0, iff the stream head
* has for some reason given up on the ioctl in progress.
* The most likely cause is an interrupted ioctl syscall.
* We will behave robustly because (given our perimeter)
* the ttcompat_state_t will get set up for the new ioctl,
* and when the response we were waiting for appears it
* will be passed on to the stream head which will discard
* it as non-current.
*/
/* free the data buffer - it might not be sufficient */
/* driver will allocate one for termios size */
/* FALLTHRU */
case TIOCGETP:
goto dogets;
/*
* "set"-style calls that set translated data into a "termios"
* structure. Set our idea of the new state from the value
* given to us. We then have to get the current state, so we
* turn this guy into a TCGETS and pass it down. When the
* ACK comes back, we modify the state we got back and shove it
* back down as the appropriate type of TCSETS.
*/
case TIOCSETP:
case TIOCSETN:
if (error != 0) {
return;
}
goto dogets;
case TIOCSETC:
if (error != 0) {
return;
}
goto dogets;
case TIOCSLTC:
if (error != 0) {
return;
}
goto dogets;
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
if (error != 0) {
return;
}
goto dogets;
/*
* "set"-style call that sets a particular bit in a "termios"
* structure. We then have to get the current state, so we
* turn this guy into a TCGETS and pass it down. When the
* ACK comes back, we modify the state we got back and shove it
* back down as the appropriate type of TCSETS.
*/
case TIOCHPCL:
break;
/*
* "set"-style call that sets DTR. Pretend that it was a TIOCMBIS
* with TIOCM_DTR set.
*/
case TIOCSDTR: {
goto allocfailure;
break;
}
/*
* "set"-style call that clears DTR. Pretend that it was a TIOCMBIC
* with TIOCM_DTR set.
*/
case TIOCCDTR: {
goto allocfailure;
break;
}
/*
* Translate into the S5 form of TCFLSH.
*/
case TIOCFLUSH: {
int flags;
if (error != 0) {
return;
}
case 0:
break;
case FREAD:
flags = 0; /* flush read */
break;
case FWRITE:
break;
}
break;
}
/*
* Turn into a TCXONC.
*/
case TIOCSTOP: {
goto allocfailure;
break;
}
case TIOCSTART: {
goto allocfailure;
break;
}
case TIOCSETD:
case TIOCGETD:
case DIOCSETP:
case DIOCGETP:
case LDOPEN:
case LDCLOSE:
case LDCHG:
case LDSETT:
case LDGETT:
/*
* All of these ioctls are just ACK'd, except for
* TIOCSETD, which must be for line discipline zero.
*/
}
return;
case IOCTYPE:
return;
case TIOCEXCL:
/* check for binary value of XCLUDE flag ???? */
return;
case TIOCNXCL:
return;
}
/*
* We don't reply to most calls, we just pass them down,
* possibly after modifying the arguments.
*/
return;
/*
* We needed to allocate something to handle this "ioctl", but
* couldn't; save this "ioctl" and arrange to get called back when
* it's more likely that we can get what we need.
* If there's already one being saved, throw it out, since it
* must have timed out.
*/
if (tp->t_bufcallid != 0)
ttcompat_reioctl, q);
}
/*
* Called when an M_IOCACK message is seen on the read queue; if this
* is the response we were waiting for, we either:
* modify the data going up (if the "ioctl" read data); since in all
* cases, the old-style returned information is smaller than or the same
* size as the new-style returned information, we just overwrite the old
* stuff with the new stuff (beware of changing structure sizes, in case
* you invalidate this)
* or
* take this data, modify it appropriately, and send it back down (if
* the "ioctl" wrote data).
* In either case, we cancel the "wait"; the final response to a "write"
* ioctl goes back up to the user.
* If this wasn't the response we were waiting for, just pass it up.
*/
static void
{
/*
* This isn't the reply we're looking for. Move along.
*/
return;
}
case TIOCGETP: {
/* recycle the reply's buffer */
/*
* This is used for TIOCGETP handling of sg_ispeed and
* sg_ospeed. If the current speed is over 38400 (the
* sgttyb limit), then we report 38400. Note that
* when "compatibility with old releases" is enabled
* (sgttyb_handling == 0), then t_[io]speed will have
* garbled nonsense, as in prior releases. (See
* to_compat() below).
*/
/* you are lucky - stream head knows how to copy you out */
return;
}
case TIOCGETC:
/* recycle the reply's buffer */
sizeof (struct tchars));
break;
case TIOCGLTC:
/* recycle the reply's buffer */
sizeof (struct ltchars));
break;
case TIOCLGET:
/* recycle the reply's buffer */
break;
case TIOCSETP:
case TIOCSETN:
/*
* Get the current state from the GETS data, and
* update it.
*/
/*
* For new-style handling, we ignore requests to set
* B38400 when the current speed is over B38400. This
* means that we change the speed as requested if:
* old style (sgttyb_handling == 0) is requested
* the requested new speed isn't B38400
* the current speed is at or below B38400
* Note that when old style is requested, both speeds
* in t_curstate are set to <= B38400 by to_compat, so
* the first test isn't needed here.
* Also note that we silently allow the user to set
* speeds above B38400 through this interface,
* regardless of the style setting. This allows
* greater compatibility with current BSD releases.
*/
/*
* Replace the data that came up with the updated data.
*/
/*
* Send it back down as a TCSETS or TCSETSF.
*/
goto senddown;
case TIOCSETC:
/*
* Get the current state from the GETS data, and
* update it.
*/
/*
* Replace the data that came up with the updated data.
*/
/*
* Send it back down as a TCSETS.
*/
goto senddown;
case TIOCSLTC:
/*
* Get the current state from the GETS data, and
* update it.
*/
/*
* Replace the data that came up with the updated data.
*/
/*
* Send it back down as a TCSETS.
*/
goto senddown;
case TIOCLBIS:
/*
* Get the current state from the GETS data, and
* update it.
*/
/*
* Replace the data that came up with the updated data.
*/
/*
* Send it back down as a TCSETS.
*/
goto senddown;
case TIOCLBIC:
/*
* Get the current state from the GETS data, and
* update it.
*/
/*
* Replace the data that came up with the updated data.
*/
/*
* Send it back down as a TCSETS.
*/
goto senddown;
case TIOCLSET:
/*
* Get the current state from the GETS data, and
* update it.
*/
/*
* Replace the data that came up with the updated data.
*/
/*
* Send it back down as a TCSETS.
*/
goto senddown;
case TIOCHPCL:
/*
* Replace the data that came up with the updated data.
*/
/*
* Send it back down as a TCSETS.
*/
goto senddown;
case TCSETSF:
/*
* We're acknowledging the terminal reset ioctl that we sent
* when the module was opened.
*/
return;
default:
}
/*
* All the calls that return something return 0.
*/
/* copy out the data - ioctl transparency */
return;
/*
* Send a "get state" reply back down, with suitably-modified
* state, as a "set state" "ioctl".
*/
}
/* Called from ttcompatrput M_IOCACK processing. */
/* Copies out the data using M_COPYOUT messages */
static void
{
case TIOCGLTC:
break;
case TIOCGETC:
break;
case TIOCLGET:
break;
default:
"ttcompat: Unknown ioctl to copyout\n");
break;
}
}
/*
* Called when an M_IOCNAK message is seen on the read queue; if this is
* the response we were waiting for, cancel the wait. Pass the reply up;
* if we were waiting for this response, we can't complete the "ioctl" and
* the NAK will tell that to the guy above us.
* If this wasn't the response we were waiting for, just pass it up.
*/
static void
{
}
}
static void
{
} else {
}
} else {
}
/* hang up if ispeed=0 */
}
/* is this useful? */
}
case O_CR1:
break;
case O_CR2:
break;
}
} else {
}
/*
* When going into RAW mode, the special characters controlled by the
* POSIX IEXTEN bit no longer apply; when leaving, they do.
*/
} else {
else {
/* XXX - what about 8 bits plus parity? */
else {
case 0:
break;
case O_EVENP:
break;
case O_ODDP:
break;
break;
}
}
}
}
case O_TAB1:
break;
case O_TAB2:
break;
case O_XTABS:
break;
}
} else {
}
}
static void
{
if (sgttyb_handling > 0) {
}
else {
}
else {
} else {
else
}
else
}
else
else
}
case CR2:
break;
case CR3:
break;
}
} else {
}
case TAB1:
break;
case TAB2:
break;
case XTABS:
break;
}
} else {
}
}