summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrui zang - Sun Microsystems - Beijing China <Aaron.Zang@Sun.COM>2008-09-25 14:01:48 +0800
committerrui zang - Sun Microsystems - Beijing China <Aaron.Zang@Sun.COM>2008-09-25 14:01:48 +0800
commitaecfc01d1bad84e66649703f7fc2926ef70b34ba (patch)
tree30d7ae76f4cff7994f216c9e89819dda18b2ae63
parentf4565e39fe75b2c28258c16bc697741760935002 (diff)
downloadillumos-joyent-aecfc01d1bad84e66649703f7fc2926ef70b34ba.tar.gz
PSARC 2006/591 Virtual Console
PSARC 2008/515 Virtual Console Update 4309501 Need additional local 'terminal' --HG-- rename : usr/src/uts/intel/sys/kd.h => usr/src/uts/common/sys/kd.h
-rw-r--r--usr/src/Makefile.lint1
-rw-r--r--usr/src/Targetdirs1
-rw-r--r--usr/src/cmd/Adm/ttysrch10
-rw-r--r--usr/src/cmd/Makefile1
-rw-r--r--usr/src/cmd/login/login.c37
-rw-r--r--usr/src/cmd/login/login.dfl10
-rw-r--r--usr/src/cmd/login/logindevperm.sh34
-rw-r--r--usr/src/cmd/netadm/iu.ap.sh8
-rw-r--r--usr/src/cmd/sulogin/sulogin.c11
-rw-r--r--usr/src/cmd/svc/milestone/Makefile9
-rw-r--r--usr/src/cmd/svc/milestone/console-login22
-rw-r--r--usr/src/cmd/svc/milestone/make-console-login-xml96
-rw-r--r--usr/src/cmd/svc/milestone/vtdaemon45
-rw-r--r--usr/src/cmd/svc/milestone/vtdaemon.xml110
-rw-r--r--usr/src/cmd/svc/profile/generic_limited_net.xml12
-rw-r--r--usr/src/cmd/svc/profile/generic_open.xml12
-rw-r--r--usr/src/cmd/svc/shell/smf_include.sh14
-rw-r--r--usr/src/cmd/ttymon/tmexpress.c9
-rw-r--r--usr/src/cmd/vt/Makefile57
-rw-r--r--usr/src/cmd/vt/vtdaemon.c1400
-rw-r--r--usr/src/cmd/vt/vtinfo.c59
-rw-r--r--usr/src/cmd/vt/vtxlock.sh85
-rw-r--r--usr/src/lib/libc/port/gen/ttyname.c4
-rw-r--r--usr/src/lib/libdevinfo/devinfo_devperm.c67
-rw-r--r--usr/src/lib/libsecdb/auth_attr.txt2
-rw-r--r--usr/src/lib/libsecdb/help/auths/Makefile2
-rw-r--r--usr/src/lib/libsecdb/help/auths/SmfValueVt.html37
-rw-r--r--usr/src/lib/libsecdb/help/auths/SmfVtStates.html37
-rw-r--r--usr/src/lib/libsecdb/prof_attr.txt2
-rw-r--r--usr/src/pkgdefs/SUNW0on/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWcsd/prototype_com3
-rw-r--r--usr/src/pkgdefs/SUNWcsr/postinstall27
-rw-r--r--usr/src/pkgdefs/SUNWcsr/preinstall13
-rw-r--r--usr/src/pkgdefs/SUNWcsr/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWcsu/prototype_com5
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_com3
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_i3862
-rw-r--r--usr/src/pkgdefs/common_files/i.logindevperm13
-rw-r--r--usr/src/tools/scripts/bfu.sh29
-rw-r--r--usr/src/uts/common/Makefile.files6
-rw-r--r--usr/src/uts/common/fs/dev/sdev_subr.c34
-rw-r--r--usr/src/uts/common/fs/dev/sdev_vtops.c442
-rw-r--r--usr/src/uts/common/fs/namefs/namevfs.c11
-rw-r--r--usr/src/uts/common/io/cons.c3
-rw-r--r--usr/src/uts/common/io/consconfig_dacf.c20
-rw-r--r--usr/src/uts/common/io/kbtrans/kbtrans_streams.c257
-rw-r--r--usr/src/uts/common/io/kbtrans/kbtrans_streams.h12
-rw-r--r--usr/src/uts/common/io/tem.c967
-rw-r--r--usr/src/uts/common/io/tem_safe.c1709
-rw-r--r--usr/src/uts/common/io/vcons.c1308
-rw-r--r--usr/src/uts/common/io/vcons_conf.c116
-rw-r--r--usr/src/uts/common/io/warlock/tem.wlcmd61
-rw-r--r--usr/src/uts/common/io/warlock/wc.wlcmd88
-rw-r--r--usr/src/uts/common/io/warlock/wc_devfs.wlcmd45
-rw-r--r--usr/src/uts/common/io/wscons.c694
-rw-r--r--usr/src/uts/common/os/console.c30
-rw-r--r--usr/src/uts/common/sys/Makefile3
-rw-r--r--usr/src/uts/common/sys/console.h12
-rw-r--r--usr/src/uts/common/sys/fs/sdev_impl.h7
-rw-r--r--usr/src/uts/common/sys/kd.h (renamed from usr/src/uts/intel/sys/kd.h)9
-rw-r--r--usr/src/uts/common/sys/tem.h42
-rw-r--r--usr/src/uts/common/sys/tem_impl.h258
-rw-r--r--usr/src/uts/common/sys/vt.h112
-rw-r--r--usr/src/uts/common/sys/vt_impl.h137
-rw-r--r--usr/src/uts/common/sys/vtdaemon.h51
-rw-r--r--usr/src/uts/intel/Makefile.intel.shared2
-rw-r--r--usr/src/uts/intel/ia32/ml/modstubs.s1
-rw-r--r--usr/src/uts/intel/sys/Makefile2
-rw-r--r--usr/src/uts/intel/tem/Makefile31
-rw-r--r--usr/src/uts/intel/warlock/Makefile5
-rw-r--r--usr/src/uts/intel/wc/Makefile40
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared2
-rw-r--r--usr/src/uts/sparc/ml/modstubs.s1
-rw-r--r--usr/src/uts/sparc/tem/Makefile30
-rw-r--r--usr/src/uts/sparc/warlock/Makefile5
-rw-r--r--usr/src/uts/sparc/wc/Makefile41
76 files changed, 7227 insertions, 1660 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index 018eec7115..0b0b657e11 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -281,6 +281,7 @@ COMMON_SUBDIRS = \
cmd/utmpd \
cmd/valtools \
cmd/vna \
+ cmd/vt \
cmd/wall \
cmd/wbem \
cmd/wc \
diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs
index 31245d9ef6..15c4693142 100644
--- a/usr/src/Targetdirs
+++ b/usr/src/Targetdirs
@@ -71,6 +71,7 @@ ROOT.SYS= \
/dev/pts \
/dev/sad \
/dev/swap \
+ /dev/vt \
/dev/zcons \
/devices \
/devices/pseudo \
diff --git a/usr/src/cmd/Adm/ttysrch b/usr/src/cmd/Adm/ttysrch
index ef3bd2e4ed..b4e2195503 100644
--- a/usr/src/cmd/Adm/ttysrch
+++ b/usr/src/cmd/Adm/ttysrch
@@ -1,13 +1,12 @@
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# 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
# or http://www.opensolaris.org/os/licensing.
@@ -22,8 +21,6 @@
#
# CDDL HEADER END
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# This file is used by ttyname(3C) to minimize search time
# during attempts to determine the name of a terminal device.
#
@@ -56,5 +53,6 @@
# in the /dev/slan directory.
#
/dev/pts
+/dev/vt
/dev/term
/dev/zcons
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index c9b15faf8d..dbabc8ac14 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -417,6 +417,7 @@ COMMON_SUBDIRS= \
volcheck \
volrmmount \
vscan \
+ vt \
w \
wall \
wbem \
diff --git a/usr/src/cmd/login/login.c b/usr/src/cmd/login/login.c
index 16a9a633e0..98e42468e2 100644
--- a/usr/src/cmd/login/login.c
+++ b/usr/src/cmd/login/login.c
@@ -18,6 +18,7 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -1177,22 +1178,42 @@ logins_disabled(char *user_name)
return (FALSE);
}
+#define DEFAULT_CONSOLE "/dev/console"
+
/*
* check_for_console - Checks if we're getting a root login on the
- * console, or a login from the global zone. Exits if not.
+ * console, or a login from the global zone. Exits if not.
*
+ * If CONSOLE is set to /dev/console in /etc/default/login, then root logins
+ * on /dev/vt/# are permitted as well. /dev/vt/# does not exist in non-global
+ * zones, but checking them does no harm.
*/
static void
check_for_console(void)
{
- if (pwd != NULL && pwd->pw_uid == 0 && zflag == B_FALSE) {
- if ((Console != NULL) && (strcmp(ttyn, Console) != 0)) {
- (void) printf("Not on system console\n");
+ const char *consoles[] = { "/dev/console", "/dev/vt/", NULL };
+ int i;
+
+ if (pwd == NULL || pwd->pw_uid != 0 || zflag != B_FALSE ||
+ Console == NULL)
+ return;
- audit_error = ADT_FAIL_VALUE_CONSOLE;
- login_exit(10);
+ if (strcmp(Console, DEFAULT_CONSOLE) == 0) {
+ for (i = 0; consoles[i] != NULL; i ++) {
+ if (strncmp(ttyn, consoles[i],
+ strlen(consoles[i])) == 0)
+ return;
}
+ } else {
+ if (strcmp(ttyn, Console) == 0)
+ return;
}
+
+ (void) printf("Not on system console\n");
+
+ audit_error = ADT_FAIL_VALUE_CONSOLE;
+ login_exit(10);
+
}
/*
@@ -2017,10 +2038,10 @@ update_utmpx_entry(int sublogin)
char *user;
static char *errmsg = "No utmpx entry. "
"You must exec \"login\" from the lowest level \"shell\".";
- int tmplen;
+ int tmplen;
struct utmpx *u = (struct utmpx *)0;
struct utmpx utmpx;
- char *ttyntail;
+ char *ttyntail;
/*
* If we're not a sublogin then
diff --git a/usr/src/cmd/login/login.dfl b/usr/src/cmd/login/login.dfl
index 03cd4d14f2..4b11830230 100644
--- a/usr/src/cmd/login/login.dfl
+++ b/usr/src/cmd/login/login.dfl
@@ -1,14 +1,12 @@
-#ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# 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
# or http://www.opensolaris.org/os/licensing.
@@ -34,6 +32,8 @@
#ULIMIT=0
# If CONSOLE is set, root can only login on that device.
+# If the specified device is /dev/console, then root can also log into
+# any of the currently enabled /dev/vt/# virtual terminal devices.
# Comment this line out to allow remote login by root.
#
CONSOLE=/dev/console
diff --git a/usr/src/cmd/login/logindevperm.sh b/usr/src/cmd/login/logindevperm.sh
index c6e0a09933..7c5025212b 100644
--- a/usr/src/cmd/login/logindevperm.sh
+++ b/usr/src/cmd/login/logindevperm.sh
@@ -20,10 +20,9 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
#
# This is the script that generates the logindevperm file. It is
# architecture-aware, and dumps different stuff for x86 and sparc.
@@ -35,11 +34,9 @@
cat <<EOM
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#pragma ident "%Z%logindevperm %I% %E% SMI"
-#
# /etc/logindevperm - login-based device permissions
#
# If the user is logging in on a device specified in the "console" field
@@ -47,6 +44,11 @@ cat <<EOM
# "devices" field will be set to that of the user. Similarly, the mode
# will be set to the mode specified in the "mode" field.
#
+# If the "console" is "/dev/vt/active" which is a symlink to the current
+# active virtual console (/dev/console, or /dev/vt/#), then the first
+# user to log into any virtual console will get ownership of all the
+# devices until they log out.
+#
# "devices" is a colon-separated list of device names. A device name
# ending in "/*", such as "/dev/fbs/*", specifies all entries (except "."
# and "..") in a directory. A '#' begins a comment and may appear
@@ -58,17 +60,17 @@ cat <<EOM
#
# console mode devices
#
-/dev/console 0600 /dev/mouse:/dev/kbd
-/dev/console 0600 /dev/sound/* # audio devices
-/dev/console 0600 /dev/fbs/* # frame buffers
-/dev/console 0600 /dev/dri/* # dri devices
-/dev/console 0400 /dev/removable-media/dsk/* # removable media
-/dev/console 0400 /dev/removable-media/rdsk/* # removable media
-/dev/console 0400 /dev/hotpluggable/dsk/* # hotpluggable storage
-/dev/console 0400 /dev/hotpluggable/rdsk/* # hotpluggable storage
-/dev/console 0600 /dev/video[0-9]+ # video devices
-/dev/console 0600 /dev/usb/hid[0-9]+ # hid devices should have the same permission with conskbd and consms
-/dev/console 0600 /dev/usb/[0-9a-f]+[.][0-9a-f]+/[0-9]+/* driver=scsa2usb,usb_mid,usbprn,ugen #libusb/ugen devices
+/dev/vt/active 0600 /dev/mouse:/dev/kbd
+/dev/vt/active 0600 /dev/sound/* # audio devices
+/dev/vt/active 0600 /dev/fbs/* # frame buffers
+/dev/vt/active 0600 /dev/dri/* # dri devices
+/dev/vt/active 0400 /dev/removable-media/dsk/* # removable media
+/dev/vt/active 0400 /dev/removable-media/rdsk/* # removable media
+/dev/vt/active 0400 /dev/hotpluggable/dsk/* # hotpluggable storage
+/dev/vt/active 0400 /dev/hotpluggable/rdsk/* # hotpluggable storage
+/dev/vt/active 0600 /dev/video[0-9]+ # video devices
+/dev/vt/active 0600 /dev/usb/hid[0-9]+ # hid devices should have the same permission with conskbd and consms
+/dev/vt/active 0600 /dev/usb/[0-9a-f]+[.][0-9a-f]+/[0-9]+/* driver=scsa2usb,usb_mid,usbprn,ugen #libusb/ugen devices
EOM
case "$MACH" in
diff --git a/usr/src/cmd/netadm/iu.ap.sh b/usr/src/cmd/netadm/iu.ap.sh
index abf930cade..c16b5a0b69 100644
--- a/usr/src/cmd/netadm/iu.ap.sh
+++ b/usr/src/cmd/netadm/iu.ap.sh
@@ -20,22 +20,20 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
# All Rights Reserved
-#ident "%Z%%M% %I% %E% SMI"
-
case "$MACH" in
"i386" )
echo "# /dev/console and /dev/contty autopush setup
#
# major minor lastminor modules
- wc 0 0 ldterm ttcompat
+ wc -1 0 ldterm ttcompat
asy -1 0 ldterm ttcompat
xencons 0 0 ldterm ttcompat
ptsl 0 47 ldterm ttcompat
@@ -52,7 +50,7 @@ case "$MACH" in
#
# major minor lastminor modules
- wc 0 0 ldterm ttcompat
+ wc -1 0 ldterm ttcompat
qcn 0 255 ldterm ttcompat
sgcn 0 0 ldterm ttcompat
zs 0 63 ldterm ttcompat
diff --git a/usr/src/cmd/sulogin/sulogin.c b/usr/src/cmd/sulogin/sulogin.c
index a5bf3c4b99..101f6da055 100644
--- a/usr/src/cmd/sulogin/sulogin.c
+++ b/usr/src/cmd/sulogin/sulogin.c
@@ -74,6 +74,7 @@
#include <auth_list.h>
#include <nss_dbdefs.h>
#include <user_attr.h>
+#include <sys/vt.h>
/*
* Intervals to sleep after failed login
@@ -458,6 +459,16 @@ main_loop(char *devname, boolean_t cttyflag)
}
if ((fd = open(devname, O_RDWR)) < 0)
exit(EXIT_FAILURE);
+
+ /*
+ * In system maintenance mode, all virtual console instances
+ * of the svc:/system/console-login service are not available
+ * any more, and only the system console is available. So here
+ * we always switch to the system console in case at the moment
+ * the active console isn't it.
+ */
+ (void) ioctl(fd, VT_ACTIVATE, 1);
+
if (fd != 0)
(void) dup2(fd, STDIN_FILENO);
if (fd != 1)
diff --git a/usr/src/cmd/svc/milestone/Makefile b/usr/src/cmd/svc/milestone/Makefile
index b084a04e44..fdcff57933 100644
--- a/usr/src/cmd/svc/milestone/Makefile
+++ b/usr/src/cmd/svc/milestone/Makefile
@@ -19,10 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
include ../../Makefile.cmd
@@ -70,7 +69,8 @@ SYSTEMSVCS= \
console-login.xml \
identity.xml \
manifest-import.xml \
- rmtmpfiles.xml
+ rmtmpfiles.xml \
+ vtdaemon.xml
SYSTEMMANIFESTS = $(SYSTEMSVCS:%=$(ROOTSVCSYSTEM)/%)
@@ -107,7 +107,8 @@ SVCMETHOD=\
net-physical \
net-routing-setup \
net-svc \
- rmtmpfiles
+ rmtmpfiles \
+ vtdaemon
$(ROOTSVCMETHOD) := FILEMODE = 0555
diff --git a/usr/src/cmd/svc/milestone/console-login b/usr/src/cmd/svc/milestone/console-login
index 6e4a733d87..c7003b103b 100644
--- a/usr/src/cmd/svc/milestone/console-login
+++ b/usr/src/cmd/svc/milestone/console-login
@@ -21,10 +21,11 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
+# This method script manages all vt logins including system
+# console login.
#
# For modifying parameters passed to ttymon, do not edit
# this script. Instead use svccfg(1m) to modify the SMF
@@ -35,6 +36,15 @@
# svc:/system/console-login> setprop ttymon/terminal_type = "xterm"
# svc:/system/console-login> exit
+. /lib/svc/share/smf_include.sh
+
+if [ "$1" != "default" ]; then
+ if smf_dont_configure_vt; then
+ /usr/sbin/svcadm disable $SMF_FMRI
+ exit $SMF_EXIT_OK
+ fi
+fi
+
getproparg() {
val=`svcprop -p $2 $SMF_FMRI`
[ -n "$val" ] && [ "$val" != "\"\"" ] && echo $1 $val
@@ -44,7 +54,13 @@ args="-g"
val=`svcprop -p ttymon/device $SMF_FMRI`
# if this isn't set, recover a little
-[ -z "$val" ] && val=/dev/console
+[ -z "$val" ] && val="/dev/console"
+
+if [ "$val" = "/dev/vt/1" ]; then
+ echo "ERROR: ttymon/device cannot be configured to /dev/vt/1."
+ exit $SMF_EXIT_ERR_CONFIG
+fi
+
args="$args -d $val"
args="$args `getproparg -l ttymon/label`"
diff --git a/usr/src/cmd/svc/milestone/make-console-login-xml b/usr/src/cmd/svc/milestone/make-console-login-xml
index 07f238ba4d..75948cde6f 100644
--- a/usr/src/cmd/svc/milestone/make-console-login-xml
+++ b/usr/src/cmd/svc/milestone/make-console-login-xml
@@ -21,10 +21,9 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
cat >console-login.xml <<EOF
<?xml version="1.0"?>
@@ -32,8 +31,6 @@ cat >console-login.xml <<EOF
Copyright 2006 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
- ident "%Z%%M% %I% %E% SMI"
-
NOTE: This service manifest is not editable; its contents will
be overwritten by package or patch operations, including
operating system upgrade. Make customizations in a different
@@ -49,10 +46,6 @@ cat >console-login.xml <<EOF
type='service'
version='1'>
- <create_default_instance enabled='true' />
-
- <single_instance/>
-
<dependency
name='fs'
grouping='require_all'
@@ -93,14 +86,23 @@ cat >console-login.xml <<EOF
<exec_method
type='method'
name='start'
- exec='/lib/svc/method/console-login'
- timeout_seconds='0' />
+ exec='/lib/svc/method/console-login %i'
+ timeout_seconds='0'>
+ <method_context>
+ <method_credential user='root' group='root' />
+ </method_context>
+ </exec_method>
<exec_method
type='method'
name='stop'
exec=':kill -9'
- timeout_seconds='3' />
+ timeout_seconds='3'>
+ <method_context>
+ <method_credential user='root' group='root' />
+ </method_context>
+ </exec_method>
+
<property_group name='startd' type='framework'>
<propval name='duration' type='astring' value='child' />
@@ -109,8 +111,20 @@ cat >console-login.xml <<EOF
<propval name='utmpx_prefix' type='astring' value='co' />
</property_group>
- <!-- these are passed to ttymon in the method script -->
+ <property_group name='general' type='framework'>
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.vt' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.manage.vt' />
+ </property_group>
+
+ <!-- these are passed to ttymon in the method script.
+ note that value_authorization is not passed to ttymon
+ and it's for smf_security(5).
+ -->
<property_group name='ttymon' type='application'>
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.vt' />
<propval name='device' type='astring' value='/dev/console' />
<propval name='label' type='astring' value='console' />
<propval name='timeout' type='count' value='0' />
@@ -123,6 +137,64 @@ cat >console-login.xml <<EOF
value='' />
</property_group>
+
+<instance name='default' enabled='true'>
+</instance>
+
+EOF
+
+# Note that this script file is normally parsed during build by sh(1).
+# When the parser encounters an EOF token (like the one above), it
+# will fork off and pipe all the text after the EOF above to the shell
+# for execution.
+#
+# one system console (/dev/console) plus five virtual consoles
+# (/dev/vt/#, # is from 2 to 6).
+
+for num in 2 3 4 5 6; do
+ cat >>console-login.xml <<EOF
+
+<instance name='vt$num' enabled='false'>
+
+ <dependency
+ name='system-console'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/console-login:default' />
+ </dependency>
+
+ <dependency
+ name='vtdaemon'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/vtdaemon:default' />
+ </dependency>
+
+ <!-- these are passed to ttymon in the method script -->
+ <property_group name='ttymon' type='application'>
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.vt' />
+ <propval name='device' type='astring' value='/dev/vt/$num' />
+ <propval name='label' type='astring' value='console' />
+ <propval name='timeout' type='count' value='0' />
+ <propval name='nohangup' type='boolean' value='true' />
+ <propval name='modules' type='astring'
+ value='ldterm,ttcompat' />
+ <propval name='prompt' type='astring'
+ value='\`uname -n\` vt$num login:' />
+ <propval name='terminal_type' type='astring'
+ value='' />
+ </property_group>
+
+</instance>
+
+EOF
+done
+
+cat >>console-login.xml <<EOF
+
<stability value='Evolving' />
<template>
diff --git a/usr/src/cmd/svc/milestone/vtdaemon b/usr/src/cmd/svc/milestone/vtdaemon
new file mode 100644
index 0000000000..3d039f8dbb
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/vtdaemon
@@ -0,0 +1,45 @@
+#!/sbin/sh
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+. /lib/svc/share/smf_include.sh
+
+if smf_dont_configure_vt; then
+ /usr/sbin/svcadm disable $SMF_FMRI
+ exit $SMF_EXIT_OK
+fi
+
+args=""
+
+val=`svcprop -p options/hotkeys $SMF_FMRI`
+[ "$val" = "false" ] && args="$args -k"
+
+val=`svcprop -p options/secure $SMF_FMRI`
+[ "$val" = "false" ] && args="$args -s"
+
+val=`svcprop -p options/nodecount $SMF_FMRI`
+[ -n "$val" -a "$val" != "0" ] && args="$args -c $val"
+
+exec /usr/lib/vtdaemon $args
diff --git a/usr/src/cmd/svc/milestone/vtdaemon.xml b/usr/src/cmd/svc/milestone/vtdaemon.xml
new file mode 100644
index 0000000000..920792bc5b
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/vtdaemon.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ 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
+ or http://www.opensolaris.org/os/licensing.
+ 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
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+
+<service_bundle type='manifest' name='SUNWcsr:vtdaemon'>
+
+<service
+ name='system/vtdaemon'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <single_instance />
+
+ <dependency
+ name='console-login'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/console-login:default' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/vtdaemon'
+ timeout_seconds='0'>
+ <method_context>
+ <method_credential user='root' group='root' />
+ </method_context>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill -9'
+ timeout_seconds='3'>
+ <method_context>
+ <method_credential user='root' group='root' />
+ </method_context>
+ </exec_method>
+
+ <property_group name='startd' type='framework'>
+ <propval name='duration' type='astring' value='child' />
+ <propval name='ignore_error' type='astring'
+ value='core,signal' />
+ <propval name='utmpx_prefix' type='astring' value='co' />
+ </property_group>
+
+ <property_group name='general' type='framework'>
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.vt' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.manage.vt' />
+ </property_group>
+
+ <property_group name='options' type='application'>
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.vt' />
+ <propval name='hotkeys' type='boolean' value='false' />
+ <propval name='secure' type='boolean' value='true' />
+ <propval name='nodecount' type='count' value='16' />
+ </property_group>
+
+
+ <stability value='Evolving' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+vtdaemon for virtual console secure switch
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='vtdaemon' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/svc/profile/generic_limited_net.xml b/usr/src/cmd/svc/profile/generic_limited_net.xml
index acb430bf66..6fbd62f051 100644
--- a/usr/src/cmd/svc/profile/generic_limited_net.xml
+++ b/usr/src/cmd/svc/profile/generic_limited_net.xml
@@ -23,8 +23,6 @@
Copyright 2008 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
- ident "%Z%%M% %I% %E% SMI"
-
The purpose of the limited_net profile is to provide a set of
active services that allow one to connect to the machine via ssh
(requires sshd). The services which are deactivated here are those
@@ -48,6 +46,13 @@
<!--
svc.startd(1M) services
-->
+ <service name='system/console-login' version='1' type='service'>
+ <instance name='vt2' enabled='true'/>
+ <instance name='vt3' enabled='true'/>
+ <instance name='vt4' enabled='true'/>
+ <instance name='vt5' enabled='true'/>
+ <instance name='vt6' enabled='true'/>
+ </service>
<service name='system/coreadm' version='1' type='service'>
<instance name='default' enabled='true'/>
</service>
@@ -92,6 +97,9 @@
<service name='system/utmp' version='1' type='service'>
<instance name='default' enabled='true'/>
</service>
+ <service name='system/vtdaemon' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
<service name='system/zones' version='1' type='service'>
<instance name='default' enabled='true'/>
</service>
diff --git a/usr/src/cmd/svc/profile/generic_open.xml b/usr/src/cmd/svc/profile/generic_open.xml
index cad0b821cc..e2aa1b6b53 100644
--- a/usr/src/cmd/svc/profile/generic_open.xml
+++ b/usr/src/cmd/svc/profile/generic_open.xml
@@ -23,8 +23,6 @@
Copyright 2008 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
- ident "%Z%%M% %I% %E% SMI"
-
Default service profile, containing a typical set of active service
instances.
@@ -45,6 +43,13 @@
<!--
svc.startd(1M) services
-->
+ <service name='system/console-login' version='1' type='service'>
+ <instance name='vt2' enabled='true'/>
+ <instance name='vt3' enabled='true'/>
+ <instance name='vt4' enabled='true'/>
+ <instance name='vt5' enabled='true'/>
+ <instance name='vt6' enabled='true'/>
+ </service>
<service name='system/coreadm' version='1' type='service'>
<instance name='default' enabled='true'/>
</service>
@@ -89,6 +94,9 @@
<service name='system/utmp' version='1' type='service'>
<instance name='default' enabled='true'/>
</service>
+ <service name='system/vtdaemon' version='1' type='service'>
+ <instance name='default' enabled='true'/>
+ </service>
<service name='system/zones' version='1' type='service'>
<instance name='default' enabled='true'/>
</service>
diff --git a/usr/src/cmd/svc/shell/smf_include.sh b/usr/src/cmd/svc/shell/smf_include.sh
index 9357c1bfbc..28aa22d701 100644
--- a/usr/src/cmd/svc/shell/smf_include.sh
+++ b/usr/src/cmd/svc/shell/smf_include.sh
@@ -20,10 +20,9 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
smf_present () {
[ -r /etc/svc/volatile/repository_door ] && \
@@ -95,6 +94,17 @@ smf_dont_configure_ip() {
return 1
}
+# smf_dont_configure_vt
+#
+# Returns zero (success) if vt functionality is not to be configured,
+# 1 otherwise.
+#
+smf_dont_configure_vt() {
+ [ "${SMF_ZONENAME:=`/sbin/zonename`}" != "global" ] && return 0
+ /usr/lib/vtinfo > /dev/null 2>&1
+ return $?
+}
+
# smf_is_system_labeled
#
# Returns zero (success) if system is labeled (aka Trusted Extensions).
diff --git a/usr/src/cmd/ttymon/tmexpress.c b/usr/src/cmd/ttymon/tmexpress.c
index 79c140c2cb..c01a67142e 100644
--- a/usr/src/cmd/ttymon/tmexpress.c
+++ b/usr/src/cmd/ttymon/tmexpress.c
@@ -20,15 +20,12 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -109,11 +106,9 @@ ttymon_express(int argc, char **argv)
read_ttydefs(NULL, FALSE);
- if ((pmtab->p_device != NULL) && (*(pmtab->p_device) != '\0') &&
- strcmp(pmtab->p_device, "/dev/console") == 0) {
+ if ((pmtab->p_device != NULL) && (*(pmtab->p_device) != '\0'))
while (checkut_line(pmtab->p_device))
sleep(15);
- }
if ((pmtab->p_device == NULL) || (*(pmtab->p_device) == '\0')) {
devname = find_ttyname(0);
diff --git a/usr/src/cmd/vt/Makefile b/usr/src/cmd/vt/Makefile
new file mode 100644
index 0000000000..432e832888
--- /dev/null
+++ b/usr/src/cmd/vt/Makefile
@@ -0,0 +1,57 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+PROG= vtdaemon vtinfo vtxlock
+
+VTDAEMON_SRC= vtdaemon.c
+VTINFO_SRC= vtinfo.c
+
+include ../Makefile.cmd
+
+CFLAGS += $(CCVERBOSE)
+
+LDLIBS += -ldoor -lpam -lbsm
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+vtdaemon: $(VTDAEMON_SRC)
+ $(LINK.c) -o $@ $(VTDAEMON_SRC) $(LDLIBS)
+ $(POST_PROCESS)
+
+vtinfo: $(VTINFO_SRC)
+ $(LINK.c) -o $@ $(VTINFO_SRC)
+ $(POST_PROCESS)
+
+install: all $(ROOTLIBPROG)
+
+clean:
+
+lint:
+ $(LINT.c) $(VTDAEMON_SRC) $(LDLIBS)
+ $(LINT.c) $(VTINFO_SRC)
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/vt/vtdaemon.c b/usr/src/cmd/vt/vtdaemon.c
new file mode 100644
index 0000000000..08d100594f
--- /dev/null
+++ b/usr/src/cmd/vt/vtdaemon.c
@@ -0,0 +1,1400 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * vtdaemon is responsible for the session secure switch via hotkeys.
+ *
+ * vtdaemon itself, like ttymon(1M), is also running on a virtual
+ * console device (/dev/vt/1), and provides a text console session
+ * for password input and authentication. The /dev/vt/1 special text
+ * console is reserved and end users cannot switch to it via hotkeys.
+ *
+ *
+ * The hotkey event request can come from either kernel or Xserver,
+ * and a door server is setup to handle the request:
+ *
+ * 1) All text console hotkeys (e.g. "Alt + F#") are intercepted by
+ * the kernel console driver which sends a door upcall to the
+ * vtdaemon via door_upcall (target_vt).
+ *
+ * 2) All Xserver hotkeys ("Alt + Ctrl + F#") are intercepted by
+ * Xserver which sends a door call to the vtdaemon via
+ * door_call (target_vt).
+ *
+ *
+ * server_for_door receives and handles any door server requests:
+ *
+ * Firstly, check source session:
+ *
+ * . If it's from kernel for a text console source session,
+ * then directly go to check the target session.
+ *
+ * . If it's from Xserver for a graphical source session and the vt
+ * associated with the Xserver is currently active:
+ * check if a user has logged in, if true, issue an internal
+ * VT_EV_LOCK event to the main thread to request lock for
+ * the graphical source session; else, directly go to check
+ * the target session.
+ *
+ * . otherwise, discard this request.
+ *
+ *
+ * Secondly, check the target session
+ *
+ * . if the target session is a text one that no one has logged in
+ * or a graphical one, issue an internal VT_EV_ACTIVATE event to
+ * the main thread to request the actual VT switch.
+ *
+ * . otherwise, the target session is a text one that someone has
+ * logged in, issue an internal VT_EV_AUTH event to the main
+ * thread to request authentication for the target session.
+ *
+ *
+ * The main thread of vtdaemon is a loop waiting for internal events
+ * which come from door call threads:
+ *
+ * 1) VT_EV_AUTH to authenticate for target session:
+ *
+ * firstly switch to the vtdaemon special text console;
+ * then prompt for password (target_owner on target_vt),
+ * e.g. "User Bob's password on vt/#: ".
+ *
+ * if the password is correct (authentication succeeds),
+ * then actually issue the VT switch; otherwise, ignore
+ * the request.
+ *
+ * 2) VT_EV_LOCK to lock the graphical source session:
+ *
+ * activate screenlock for this graphical session.
+ * vtdaemon just invokes existing front-end command line
+ * tools (e.g. xscreensaver-command -lock for JDS) to
+ * lock the display.
+ *
+ * 3) VT_EV_ACTIVATE to directly switch to the target session
+ *
+ *
+ * There is a system/vtdaemon:default SMF service for vtdaemon.
+ *
+ * There's a "hotkeys" property (BOOLEAN) in the
+ * system/vtdaemon:default SMF service, which allows authorized
+ * users to dynamically enable or disable VT switch via hotkeys.
+ * Its default value is TRUE (enabled).
+ *
+ * There's a "secure" property (BOOLEAN) in the
+ * system/vtdaemon:default SMF service, which allows authorized
+ * users to dynamically enable or disable hotkeys are secure.
+ * If disabled, the user can freely switch to any session without
+ * authentication. Its default value is TRUE (enabled).
+ *
+ *
+ * By default, there's only 16 virtual console device nodes (from
+ * /dev/vt/0 to /dev/vt/15). There's a property "nodecount"
+ * (default value is 16) in the system/vtdaemon:default SMF
+ * service, so authorized users can configure it to have more
+ * or less virtual console device nodes.
+ *
+ * Xserver needs to switch back to previous active vt via VT_EV_X_EXIT
+ * door event request when it's exiting, so vtdaemon always needs to
+ * be there even if the hotkeys switch is disabled, otherwise the screen
+ * will be just blank when Xserver exits.
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <syslog.h>
+#include <deflt.h>
+
+#include <bsm/adt.h>
+#include <bsm/adt_event.h>
+
+#include <alloca.h>
+#include <assert.h>
+#include <errno.h>
+#include <door.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <synch.h>
+#include <thread.h>
+#include <unistd.h>
+#include <wait.h>
+#include <limits.h>
+#include <zone.h>
+#include <priv.h>
+#include <pwd.h>
+#include <utmpx.h>
+#include <procfs.h>
+#include <poll.h>
+#include <termio.h>
+#include <security/pam_appl.h>
+#include <time.h>
+#include <sys/console.h>
+#include <assert.h>
+#include <syslog.h>
+
+#include <sys/vt.h>
+#include <sys/vtdaemon.h>
+
+/*
+ * The door file /var/run/vt/vtdaemon_door
+ */
+#define VT_TMPDIR "/var/run/vt"
+
+#define VT_DAEMON_ARG 0
+#define VT_DAEMON_CONSOLE_FILE "/dev/vt/1"
+
+#define VT_IS_SYSTEM_CONSOLE(vtno) ((vtno) == 1)
+
+/* Defaults for updating expired passwords */
+#define DEF_ATTEMPTS 3
+
+int daemonfd;
+
+static boolean_t vt_hotkeys = B_TRUE; /* '-k' option to disable */
+static boolean_t vt_secure = B_TRUE; /* '-s' option to disable */
+
+static char vt_door_path[MAXPATHLEN];
+static int vt_door = -1;
+
+/* protecting vt_hotkeys_pending and vt_auth_doing */
+static mutex_t vt_mutex = DEFAULTMUTEX;
+
+static boolean_t vt_hotkeys_pending = B_FALSE;
+static boolean_t vt_auth_doing = B_FALSE;
+
+static adt_session_data_t **vt_ah_array = NULL;
+static int vtnodecount = 0;
+
+static int vt_audit_start(adt_session_data_t **, pid_t);
+static void vt_audit_event(adt_session_data_t *, au_event_t, int);
+static void vt_check_source_audit(void);
+
+static int
+vt_setup_signal(int signo, int mask)
+{
+ sigset_t set;
+
+ (void) sigemptyset(&set);
+ (void) sigaddset(&set, signo);
+
+ if (mask)
+ return (sigprocmask(SIG_BLOCK, &set, NULL));
+ else
+ return (sigprocmask(SIG_UNBLOCK, &set, NULL));
+}
+
+static void
+do_activate_screenlock(int display_num)
+{
+ char dpy[16];
+
+ (void) snprintf(dpy, sizeof (dpy), "%d", display_num);
+ (void) execl("/usr/lib/vtxlock", "vtxlock", dpy, NULL);
+}
+
+static void
+vt_activate_screenlock(int display)
+{
+ pid_t pid;
+
+ if ((pid = fork()) == -1)
+ return;
+
+ if (pid == 0) { /* child */
+ do_activate_screenlock(display);
+ exit(0);
+ }
+
+ /* parent */
+ while (waitpid(pid, (int *)0, 0) != pid)
+ continue;
+}
+
+/*
+ * Find the login process and user logged in on the target vt.
+ */
+static void
+vt_read_utx(int target_vt, pid_t *pid, char name[])
+{
+ struct utmpx *u;
+ char ttyntail[sizeof (u->ut_line)];
+
+ *pid = (pid_t)-1;
+
+ if (VT_IS_SYSTEM_CONSOLE(target_vt)) /* system console */
+ (void) snprintf(ttyntail, sizeof (ttyntail),
+ "%s", "console");
+ else
+ (void) snprintf(ttyntail, sizeof (ttyntail),
+ "%s%d", "vt/", target_vt);
+
+ setutxent();
+ while ((u = getutxent()) != NULL)
+ /* see if this is the entry we want */
+ if ((u->ut_type == USER_PROCESS) &&
+ (!nonuserx(*u)) &&
+ (u->ut_host[0] == '\0') &&
+ (strncmp(u->ut_line, ttyntail, sizeof (u->ut_line)) == 0)) {
+
+ *pid = u->ut_pid;
+ if (name != NULL) {
+ (void) strncpy(name, u->ut_user,
+ sizeof (u->ut_user));
+ name[sizeof (u->ut_user)] = '\0';
+ }
+ break;
+ }
+
+ endutxent();
+}
+
+static boolean_t
+vt_is_tipline(void)
+{
+ static int is_tipline = 0;
+ int fd;
+ static char termbuf[MAX_TERM_TYPE_LEN];
+ static struct cons_getterm cons_term = { sizeof (termbuf), termbuf};
+
+ if (is_tipline != 0)
+ return (is_tipline == 1);
+
+ if ((fd = open("/dev/console", O_RDONLY)) < 0)
+ return (B_FALSE);
+
+ if (ioctl(fd, CONS_GETTERM, &cons_term) != 0 &&
+ errno == ENODEV) {
+ is_tipline = 1;
+ } else {
+ is_tipline = -1;
+ }
+
+ (void) close(fd);
+ return (is_tipline == 1);
+}
+
+static int
+validate_target_vt(int target_vt)
+{
+ int fd;
+ struct vt_stat state;
+
+ if (target_vt < 1)
+ return (-1);
+
+ if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_WRONLY)) < 0)
+ return (-1);
+
+ if (ioctl(fd, VT_GETSTATE, &state) != 0) {
+ (void) close(fd);
+ return (-1);
+ }
+
+ (void) close(fd);
+
+ if (state.v_active == target_vt) {
+ return (1); /* it's current active vt */
+ }
+
+ if (target_vt == 1) {
+ /*
+ * In tipline case, the system console is always
+ * available, so ignore this request.
+ */
+ if (vt_is_tipline())
+ return (-1);
+
+ target_vt = 0;
+ }
+
+ /*
+ * The hotkey request and corresponding target_vt number can come
+ * from either kernel or Xserver (or other user applications).
+ * In kernel we've validated the hotkey request, but Xserver (or
+ * other user applications) cannot do it, so here we still try
+ * to validate it.
+ *
+ * VT_GETSTATE is only valid for first 16 VTs for historical reasons.
+ * Fortunately, in practice, Xserver can only send the hotkey
+ * request of target_vt number from 1 to 12 (Ctrl + Alt + F1 to F2).
+ */
+ if (target_vt < 8 * sizeof (state.v_state)) {
+ if ((state.v_state & (1 << target_vt)) != 0) {
+ return (0);
+ } else {
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+static void
+vt_do_activate(int target_vt)
+{
+ (void) ioctl(daemonfd, VT_ACTIVATE, target_vt);
+ (void) mutex_lock(&vt_mutex);
+ vt_hotkeys_pending = B_FALSE;
+ (void) mutex_unlock(&vt_mutex);
+}
+
+/* events written to fd 0 and read from fd 1 */
+#define VT_EV_AUTH 1
+#define VT_EV_LOCK 2
+#define VT_EV_ACTIVATE 3
+
+/* events written to fd 1 and read from fd 0 */
+#define VT_EV_TERMINATE_AUTH 4
+
+typedef struct vt_evt {
+ int ve_cmd;
+ int ve_info; /* vtno or display num */
+} vt_evt_t;
+
+static int eventstream[2];
+
+boolean_t
+eventstream_init(void)
+{
+ if (pipe(eventstream) == -1)
+ return (B_FALSE);
+ return (B_TRUE);
+}
+
+void
+eventstream_write(int channel, vt_evt_t *pevt)
+{
+ (void) write(eventstream[channel], pevt, sizeof (vt_evt_t));
+}
+
+static boolean_t
+eventstream_read(int channel, vt_evt_t *pevt)
+{
+ ssize_t rval;
+
+ rval = read(eventstream[channel], pevt, sizeof (vt_evt_t));
+ return (rval > 0);
+}
+
+static void
+vt_ev_request(int cmd, int info)
+{
+ int channel;
+ vt_evt_t ve;
+
+ ve.ve_cmd = cmd;
+ ve.ve_info = info;
+
+ channel = (cmd == VT_EV_TERMINATE_AUTH) ? 1 : 0;
+ eventstream_write(channel, &ve);
+}
+
+static void
+vt_clear_events(void)
+{
+ int rval = 0;
+ struct stat buf;
+ vt_evt_t evt;
+
+ while (rval == 0) {
+ rval = fstat(eventstream[0], &buf);
+ if (rval != -1 && buf.st_size > 0)
+ (void) eventstream_read(0, &evt);
+ else
+ break;
+ }
+}
+
+static int vt_conv(int, struct pam_message **,
+ struct pam_response **, void *);
+
+/*ARGSUSED*/
+static void
+catch(int x)
+{
+ (void) signal(SIGINT, catch);
+}
+
+/*
+ * The SIGINT (ctl_c) will restart the authentication, and re-prompt
+ * the end user to input the password.
+ */
+static int
+vt_poll()
+{
+ struct pollfd pollfds[2];
+ vt_evt_t ve;
+ int ret;
+
+ pollfds[0].fd = eventstream[0];
+ pollfds[1].fd = daemonfd;
+ pollfds[0].events = pollfds[1].events =
+ POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
+
+ for (;;) {
+ pollfds[0].revents = pollfds[1].revents = 0;
+
+ ret = poll(pollfds,
+ sizeof (pollfds) / sizeof (struct pollfd), -1);
+ if (ret == -1 && errno != EINTR) {
+ continue;
+ }
+
+ if (ret == -1 && errno == EINTR)
+ return (-1);
+
+ if (pollfds[0].revents) {
+ (void) eventstream_read(0, &ve);
+ return (0);
+ }
+
+ if (pollfds[1].revents)
+ return (1);
+
+ return (0);
+
+ }
+}
+
+static char
+vt_getchar(int fd)
+{
+ char c;
+ int cnt;
+
+ cnt = read(fd, &c, 1);
+ if (cnt > 0) {
+ return (c);
+ }
+
+ return (EOF);
+}
+
+static char *
+vt_getinput(int noecho)
+{
+ int c;
+ int i = 0;
+ struct termio tty;
+ tcflag_t tty_flags;
+ char input[PAM_MAX_RESP_SIZE];
+
+ if (noecho) {
+ (void) ioctl(daemonfd, TCGETA, &tty);
+ tty_flags = tty.c_lflag;
+ tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ (void) ioctl(daemonfd, TCSETAF, &tty);
+ }
+
+ while ((vt_poll()) == 1) {
+ if ((c = vt_getchar(daemonfd)) != '\n' && c != '\r' &&
+ c != EOF && (i < PAM_MAX_RESP_SIZE))
+ input[i++] = (char)c;
+ else
+ break;
+ }
+
+ input[i] = '\0';
+
+ if (noecho) {
+ tty.c_lflag = tty_flags;
+ (void) ioctl(daemonfd, TCSETAW, &tty);
+ (void) fputc('\n', stdout);
+ }
+
+ return (strdup(input));
+}
+
+/*
+ * vt_conv: vtdaemon PAM conversation function.
+ * SIGINT/EINTR is handled in vt_getinput()/vt_poll().
+ */
+
+/*ARGSUSED*/
+static int
+vt_conv(int num_msg, struct pam_message **msg,
+ struct pam_response **response, void *appdata_ptr)
+{
+ struct pam_message *m;
+ struct pam_response *r;
+ int i, k;
+
+ if (num_msg >= PAM_MAX_NUM_MSG) {
+ syslog(LOG_ERR, "too many messages %d >= %d",
+ num_msg, PAM_MAX_NUM_MSG);
+ *response = NULL;
+ return (PAM_CONV_ERR);
+ }
+
+ *response = calloc(num_msg, sizeof (struct pam_response));
+ if (*response == NULL)
+ return (PAM_BUF_ERR);
+
+ m = *msg;
+ r = *response;
+ for (i = 0; i < num_msg; i++) {
+ int echo_off = 0;
+
+ /* Bad message */
+ if (m->msg == NULL) {
+ syslog(LOG_ERR, "message[%d]: %d/NULL\n",
+ i, m->msg_style);
+ goto err;
+ }
+
+ /*
+ * Fix up final newline:
+ * remove from prompts, add back for messages.
+ */
+ if (m->msg[strlen(m->msg)] == '\n')
+ m->msg[strlen(m->msg)] = '\0';
+
+ r->resp = NULL;
+ r->resp_retcode = 0;
+
+ switch (m->msg_style) {
+
+ case PAM_PROMPT_ECHO_OFF:
+ echo_off = 1;
+ /* FALLTHROUGH */
+
+ case PAM_PROMPT_ECHO_ON:
+ (void) fputs(m->msg, stdout);
+
+ r->resp = vt_getinput(echo_off);
+ break;
+
+ case PAM_ERROR_MSG:
+ /* the user may want to see this */
+ (void) fputs(m->msg, stdout);
+ (void) fputs("\n", stdout);
+ break;
+
+ case PAM_TEXT_INFO:
+ (void) fputs(m->msg, stdout);
+ (void) fputs("\n", stdout);
+ break;
+
+ default:
+ syslog(LOG_ERR, "message[%d]: unknown type"
+ "%d/val=\"%s\"", i, m->msg_style, m->msg);
+
+ /* error, service module won't clean up */
+ goto err;
+ }
+
+ /* Next message/response */
+ m++;
+ r++;
+
+ }
+ return (PAM_SUCCESS);
+
+err:
+ /*
+ * Service modules don't clean up responses if an error is returned.
+ * Free responses here.
+ */
+ r = *response;
+ for (k = 0; k < i; k++, r++) {
+ if (r->resp) {
+ /* Clear before freeing -- maybe a password */
+ bzero(r->resp, strlen(r->resp));
+ free(r->resp);
+ r->resp = NULL;
+ }
+ }
+
+ free(*response);
+ *response = NULL;
+ return (PAM_CONV_ERR);
+}
+
+#define DEF_FILE "/etc/default/login"
+
+/* Get PASSREQ from default file */
+static boolean_t
+vt_default(void)
+{
+ int flags;
+ char *ptr;
+ boolean_t retval = B_FALSE;
+
+ if ((defopen(DEF_FILE)) == 0) {
+ /* ignore case */
+ flags = defcntl(DC_GETFLAGS, 0);
+ TURNOFF(flags, DC_CASE);
+ (void) defcntl(DC_SETFLAGS, flags);
+
+ if ((ptr = defread("PASSREQ=")) != NULL &&
+ strcasecmp("YES", ptr) == 0)
+ retval = B_TRUE;
+
+ (void) defopen(NULL);
+ }
+
+ return (retval);
+}
+
+/*
+ * VT_CLEAR_SCREEN_STR is the console terminal escape sequence used to
+ * clear the current screen. The vt special console (/dev/vt/1) is
+ * just reserved for vtdaemon, and the TERM/termcap of it is always
+ * the local sun-color, which is always supported by our kernel terminal
+ * emulator.
+ */
+#define VT_CLEAR_SCREEN_STR "\033[2J\033[1;1H"
+
+static void
+vt_do_auth(int target_vt)
+{
+ char user_name[sizeof (((struct utmpx *)0)->ut_line) + 1] = {'\0'};
+ pam_handle_t *vt_pamh;
+ int err;
+ int pam_flag = 0;
+ int chpasswd_tries;
+ struct pam_conv pam_conv = {vt_conv, NULL};
+ pid_t pid;
+ adt_session_data_t *ah;
+
+ vt_read_utx(target_vt, &pid, user_name);
+
+ if (pid == (pid_t)-1 || user_name[0] == '\0')
+ return;
+
+ if ((err = pam_start("vtdaemon", user_name, &pam_conv,
+ &vt_pamh)) != PAM_SUCCESS)
+ return;
+
+ /*
+ * firstly switch to the vtdaemon special console
+ * and clear the current screen
+ */
+ (void) ioctl(daemonfd, VT_ACTIVATE, VT_DAEMON_ARG);
+ (void) write(daemonfd, VT_CLEAR_SCREEN_STR,
+ strlen(VT_CLEAR_SCREEN_STR));
+ (void) ioctl(daemonfd, VT_SET_TARGET, target_vt);
+
+ (void) mutex_lock(&vt_mutex);
+ vt_auth_doing = B_TRUE;
+ vt_hotkeys_pending = B_FALSE;
+ (void) mutex_unlock(&vt_mutex);
+
+ /*
+ * Fetch audit handle.
+ */
+ ah = vt_ah_array[target_vt - 1];
+
+ if (vt_default())
+ pam_flag = PAM_DISALLOW_NULL_AUTHTOK;
+
+ do {
+ if (VT_IS_SYSTEM_CONSOLE(target_vt))
+ (void) fprintf(stdout,
+ "\nUnlock user %s on the system console\n",
+ user_name);
+ else
+ (void) fprintf(stdout,
+ "\nUnlock user %s on vt/%d\n", user_name,
+ target_vt);
+
+ err = pam_authenticate(vt_pamh, pam_flag);
+
+ (void) mutex_lock(&vt_mutex);
+ if (vt_hotkeys_pending) {
+ (void) mutex_unlock(&vt_mutex);
+ break;
+ }
+ (void) mutex_unlock(&vt_mutex);
+
+ if (err == PAM_SUCCESS) {
+ err = pam_acct_mgmt(vt_pamh, pam_flag);
+
+ (void) mutex_lock(&vt_mutex);
+ if (vt_hotkeys_pending) {
+ (void) mutex_unlock(&vt_mutex);
+ break;
+ }
+ (void) mutex_unlock(&vt_mutex);
+
+ if (err == PAM_NEW_AUTHTOK_REQD) {
+ chpasswd_tries = 0;
+
+ do {
+ err = pam_chauthtok(vt_pamh,
+ PAM_CHANGE_EXPIRED_AUTHTOK);
+ chpasswd_tries++;
+
+ (void) mutex_lock(&vt_mutex);
+ if (vt_hotkeys_pending) {
+ (void) mutex_unlock(&vt_mutex);
+ break;
+ }
+ (void) mutex_unlock(&vt_mutex);
+
+ } while ((err == PAM_AUTHTOK_ERR ||
+ err == PAM_TRY_AGAIN) &&
+ chpasswd_tries < DEF_ATTEMPTS);
+
+ (void) mutex_lock(&vt_mutex);
+ if (vt_hotkeys_pending) {
+ (void) mutex_unlock(&vt_mutex);
+ break;
+ }
+ (void) mutex_unlock(&vt_mutex);
+
+ vt_audit_event(ah, ADT_passwd, err);
+ }
+ }
+
+ /*
+ * Only audit failed unlock here, successful unlock
+ * will be audited after switching to target vt.
+ */
+ if (err != PAM_SUCCESS) {
+ (void) fprintf(stdout, "%s",
+ pam_strerror(vt_pamh, err));
+
+ vt_audit_event(ah, ADT_screenunlock, err);
+ }
+
+ (void) mutex_lock(&vt_mutex);
+ if (vt_hotkeys_pending) {
+ (void) mutex_unlock(&vt_mutex);
+ break;
+ }
+ (void) mutex_unlock(&vt_mutex);
+
+ } while (err != PAM_SUCCESS);
+
+ (void) mutex_lock(&vt_mutex);
+ if (!vt_hotkeys_pending) {
+ /*
+ * Should be PAM_SUCCESS to reach here.
+ */
+ (void) ioctl(daemonfd, VT_ACTIVATE, target_vt);
+
+ vt_audit_event(ah, ADT_screenunlock, err);
+
+ /*
+ * Free audit handle.
+ */
+ (void) adt_end_session(ah);
+ vt_ah_array[target_vt - 1] = NULL;
+ }
+ (void) mutex_unlock(&vt_mutex);
+
+ (void) pam_end(vt_pamh, err);
+
+ if (user_name != NULL)
+ free(user_name);
+
+ (void) mutex_lock(&vt_mutex);
+ vt_auth_doing = B_FALSE;
+ vt_clear_events();
+ (void) mutex_unlock(&vt_mutex);
+}
+
+/* main thread (lock and auth) */
+static void
+vt_serve_events(void)
+{
+ struct pollfd pollfds[1];
+ int ret;
+ vt_evt_t ve;
+
+ pollfds[0].fd = eventstream[1];
+ pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
+
+ for (;;) {
+ pollfds[0].revents = 0;
+ ret = poll(pollfds,
+ sizeof (pollfds) / sizeof (struct pollfd), -1);
+ if (ret == -1 && errno == EINTR) {
+ continue;
+ }
+
+ if (pollfds[0].revents && eventstream_read(1, &ve)) {
+ /* new request */
+ switch (ve.ve_cmd) {
+ case VT_EV_AUTH:
+ vt_do_auth(ve.ve_info);
+ break;
+
+ case VT_EV_LOCK:
+ vt_activate_screenlock(ve.ve_info);
+ break;
+
+ case VT_EV_ACTIVATE:
+ /* directly activate target vt */
+ vt_do_activate(ve.ve_info);
+ break;
+ }
+ }
+ }
+}
+
+static void
+vt_check_target_session(uint32_t target_vt)
+{
+ pid_t pid = (pid_t)-1;
+
+ if (!vt_secure) {
+ vt_ev_request(VT_EV_ACTIVATE, target_vt);
+ return;
+ }
+
+ /* check the target session */
+ vt_read_utx(target_vt, &pid, NULL);
+ if (pid == (pid_t)-1) {
+ vt_ev_request(VT_EV_ACTIVATE, target_vt);
+ return;
+ }
+
+ vt_ev_request(VT_EV_AUTH, target_vt);
+}
+
+static boolean_t
+vt_get_active_disp_info(struct vt_dispinfo *vd)
+{
+ int fd;
+ struct vt_stat state;
+ char vtname[16];
+
+ if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_RDONLY)) < 0)
+ return (B_FALSE);
+
+ if (ioctl(fd, VT_GETSTATE, &state) != 0) {
+ (void) close(fd);
+ return (B_FALSE);
+ }
+ (void) close(fd);
+
+ (void) snprintf(vtname, sizeof (vtname), "/dev/vt/%d", state.v_active);
+ if ((fd = open(vtname, O_RDONLY)) < 0)
+ return (B_FALSE);
+
+ if (ioctl(fd, VT_GETDISPINFO, vd) != 0) {
+ (void) close(fd);
+ return (B_FALSE);
+ }
+
+ (void) close(fd);
+ return (B_TRUE);
+}
+
+/*
+ * Xserver registers its pid into kernel to associate it with
+ * its vt upon startup for each graphical display. So here we can
+ * check if the pid is of the Xserver for the current active
+ * display when we receive a special VT_EV_X_EXIT request from
+ * a process. If the request does not come from the current
+ * active Xserver, it is discarded.
+ */
+static boolean_t
+vt_check_disp_active(pid_t x_pid)
+{
+ struct vt_dispinfo vd;
+
+ if (vt_get_active_disp_info(&vd) &&
+ vd.v_pid == x_pid)
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+/*
+ * check if the pid is of the Xserver for the current active display,
+ * return true when it is, and then also return other associated
+ * information with the Xserver.
+ */
+static boolean_t
+vt_get_disp_info(pid_t x_pid, int *logged_in, int *display_num)
+{
+ struct vt_dispinfo vd;
+
+ if (!vt_get_active_disp_info(&vd) ||
+ vd.v_pid != x_pid)
+ return (B_FALSE);
+
+ *logged_in = vd.v_login;
+ *display_num = vd.v_dispnum;
+ return (B_TRUE);
+}
+
+static void
+vt_terminate_auth(void)
+{
+ struct timespec sleeptime;
+
+ sleeptime.tv_sec = 0;
+ sleeptime.tv_nsec = 1000000; /* 1ms */
+
+ (void) mutex_lock(&vt_mutex);
+ while (vt_auth_doing) {
+ vt_ev_request(VT_EV_TERMINATE_AUTH, 0);
+
+ if (vt_auth_doing) {
+ (void) mutex_unlock(&vt_mutex);
+ (void) nanosleep(&sleeptime, NULL);
+ sleeptime.tv_nsec *= 2;
+ (void) mutex_lock(&vt_mutex);
+ }
+ }
+ (void) mutex_unlock(&vt_mutex);
+}
+
+static void
+vt_do_hotkeys(pid_t pid, uint32_t target_vt)
+{
+ int logged_in;
+ int display_num;
+
+ if (validate_target_vt(target_vt) != 0)
+ return;
+
+ /*
+ * Maybe last switch action is being taken and the lock is ongoing,
+ * here we must reject the newly request.
+ */
+ (void) mutex_lock(&vt_mutex);
+ if (vt_hotkeys_pending) {
+ (void) mutex_unlock(&vt_mutex);
+ return;
+ }
+
+ /* cleared in vt_do_active and vt_do_auth */
+ vt_hotkeys_pending = B_TRUE;
+ (void) mutex_unlock(&vt_mutex);
+
+ vt_terminate_auth();
+
+ /* check source session for this hotkeys request */
+ if (pid == 0) {
+ /* ok, it comes from kernel. */
+ if (vt_secure)
+ vt_check_source_audit();
+
+ /* then only need to check target session */
+ vt_check_target_session(target_vt);
+ return;
+ }
+
+ /*
+ * check if it comes from current active X graphical session,
+ * if not, ignore this request.
+ */
+ if (!vt_get_disp_info(pid, &logged_in, &display_num)) {
+ (void) mutex_lock(&vt_mutex);
+ vt_hotkeys_pending = B_FALSE;
+ (void) mutex_unlock(&vt_mutex);
+ return;
+ }
+
+ if (logged_in && vt_secure)
+ vt_ev_request(VT_EV_LOCK, display_num);
+
+ vt_check_target_session(target_vt);
+}
+
+/*
+ * The main routine for the door server that deals with secure hotkeys
+ */
+/* ARGSUSED */
+static void
+server_for_door(void *cookie, char *args, size_t alen, door_desc_t *dp,
+ uint_t n_desc)
+{
+ ucred_t *uc = NULL;
+ vt_cmd_arg_t *vtargp;
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ vtargp = (vt_cmd_arg_t *)args;
+
+ if (vtargp == NULL ||
+ alen != sizeof (vt_cmd_arg_t) ||
+ door_ucred(&uc) != 0) {
+ (void) door_return(NULL, 0, NULL, 0);
+ return;
+ }
+
+ switch (vtargp->vt_ev) {
+ case VT_EV_X_EXIT:
+ /*
+ * Xserver will issue this event requesting to switch back
+ * to previous active vt when it's exiting and the associated
+ * vt is currently active.
+ */
+ if (vt_check_disp_active(ucred_getpid(uc)))
+ vt_do_hotkeys(0, vtargp->vt_num);
+ break;
+
+ case VT_EV_HOTKEYS:
+ if (!vt_hotkeys) /* hotkeys are disabled? */
+ break;
+
+ vt_do_hotkeys(ucred_getpid(uc), vtargp->vt_num);
+ break;
+
+ default:
+ break;
+ }
+
+ ucred_free(uc);
+ (void) door_return(NULL, 0, NULL, 0);
+}
+
+static boolean_t
+setup_door(void)
+{
+ if ((vt_door = door_create(server_for_door, NULL,
+ DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
+ syslog(LOG_ERR, "door_create failed: %s", strerror(errno));
+ return (B_FALSE);
+ }
+
+ (void) fdetach(vt_door_path);
+
+ if (fattach(vt_door, vt_door_path) != 0) {
+ syslog(LOG_ERR, "fattach to %s failed: %s",
+ vt_door_path, strerror(errno));
+ (void) door_revoke(vt_door);
+ (void) fdetach(vt_door_path);
+ vt_door = -1;
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * check to see if vtdaemon is already running.
+ *
+ * The idea here is that we want to open the path to which we will
+ * attach our door, lock it, and then make sure that no-one has beat us
+ * to fattach(3c)ing onto it.
+ *
+ * fattach(3c) is really a mount, so there are actually two possible
+ * vnodes we could be dealing with. Our strategy is as follows:
+ *
+ * - If the file we opened is a regular file (common case):
+ * There is no fattach(3c)ed door, so we have a chance of becoming
+ * the running vtdaemon. We attempt to lock the file: if it is
+ * already locked, that means someone else raced us here, so we
+ * lose and give up.
+ *
+ * - If the file we opened is a namefs file:
+ * This means there is already an established door fattach(3c)'ed
+ * to the rendezvous path. We've lost the race, so we give up.
+ * Note that in this case we also try to grab the file lock, and
+ * will succeed in acquiring it since the vnode locked by the
+ * "winning" vtdaemon was a regular one, and the one we locked was
+ * the fattach(3c)'ed door node. At any rate, no harm is done.
+ */
+static boolean_t
+make_daemon_exclusive(void)
+{
+ int doorfd = -1;
+ boolean_t ret = B_FALSE;
+ struct stat st;
+ struct flock flock;
+
+top:
+ if ((doorfd = open(vt_door_path, O_CREAT|O_RDWR,
+ S_IREAD|S_IWRITE|S_IRGRP|S_IROTH)) < 0) {
+ syslog(LOG_ERR, "failed to open %s", vt_door_path);
+ goto out;
+ }
+ if (fstat(doorfd, &st) < 0) {
+ syslog(LOG_ERR, "failed to stat %s", vt_door_path);
+ goto out;
+ }
+ /*
+ * Lock the file to synchronize
+ */
+ flock.l_type = F_WRLCK;
+ flock.l_whence = SEEK_SET;
+ flock.l_start = (off_t)0;
+ flock.l_len = (off_t)0;
+ if (fcntl(doorfd, F_SETLK, &flock) < 0) {
+ /*
+ * Someone else raced us here and grabbed the lock file
+ * first. A warning here and exit.
+ */
+ syslog(LOG_ERR, "vtdaemon is already running!");
+ goto out;
+ }
+
+ if (strcmp(st.st_fstype, "namefs") == 0) {
+ struct door_info info;
+
+ /*
+ * There is already something fattach()'ed to this file.
+ * Lets see what the door is up to.
+ */
+ if (door_info(doorfd, &info) == 0 && info.di_target != -1) {
+ syslog(LOG_ERR, "vtdaemon is already running!");
+ goto out;
+ }
+
+ (void) fdetach(vt_door_path);
+ (void) close(doorfd);
+ goto top;
+ }
+
+ ret = setup_door();
+
+out:
+ (void) close(doorfd);
+ return (ret);
+}
+
+static boolean_t
+mkvtdir(void)
+{
+ struct stat st;
+ /*
+ * We must create and lock everyone but root out of VT_TMPDIR
+ * since anyone can open any UNIX domain socket, regardless of
+ * its file system permissions.
+ */
+ if (mkdir(VT_TMPDIR, S_IRWXU|S_IROTH|S_IXOTH|S_IRGRP|S_IXGRP) < 0 &&
+ errno != EEXIST) {
+ syslog(LOG_ERR, "could not mkdir '%s'", VT_TMPDIR);
+ return (B_FALSE);
+ }
+ /* paranoia */
+ if ((stat(VT_TMPDIR, &st) < 0) || !S_ISDIR(st.st_mode)) {
+ syslog(LOG_ERR, "'%s' is not a directory", VT_TMPDIR);
+ return (B_FALSE);
+ }
+ (void) chmod(VT_TMPDIR, S_IRWXU|S_IROTH|S_IXOTH|S_IRGRP|S_IXGRP);
+ return (B_TRUE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ int opt;
+ priv_set_t *privset;
+ int active;
+
+ openlog("vtdaemon", LOG_PID | LOG_CONS, 0);
+
+ /*
+ * Check that we have all privileges. It would be nice to pare
+ * this down, but this is at least a first cut.
+ */
+ if ((privset = priv_allocset()) == NULL) {
+ syslog(LOG_ERR, "priv_allocset failed");
+ return (1);
+ }
+
+ if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
+ syslog(LOG_ERR, "getppriv failed", "getppriv");
+ priv_freeset(privset);
+ return (1);
+ }
+
+ if (priv_isfullset(privset) == B_FALSE) {
+ syslog(LOG_ERR, "You lack sufficient privilege "
+ "to run this command (all privs required)");
+ priv_freeset(privset);
+ return (1);
+ }
+ priv_freeset(privset);
+
+ while ((opt = getopt(argc, argv, "ksrc:")) != EOF) {
+ switch (opt) {
+ case 'k':
+ vt_hotkeys = B_FALSE;
+ break;
+ case 's':
+ vt_secure = B_FALSE;
+ break;
+ case 'c':
+ vtnodecount = atoi(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ (void) vt_setup_signal(SIGINT, 1);
+
+ if (!mkvtdir())
+ return (1);
+
+ if (!eventstream_init())
+ return (1);
+
+ (void) snprintf(vt_door_path, sizeof (vt_door_path),
+ VT_TMPDIR "/vtdaemon_door");
+
+ if (!make_daemon_exclusive())
+ return (1);
+
+ /* only the main thread accepts SIGINT */
+ (void) vt_setup_signal(SIGINT, 0);
+ (void) sigset(SIGPIPE, SIG_IGN);
+ (void) signal(SIGQUIT, SIG_IGN);
+ (void) signal(SIGINT, catch);
+
+ for (i = 0; i < 3; i++)
+ (void) close(i);
+ (void) setsid();
+
+ if ((daemonfd = open(VT_DAEMON_CONSOLE_FILE, O_RDWR)) < 0) {
+ return (1);
+ }
+
+ if (daemonfd != 0)
+ (void) dup2(daemonfd, STDIN_FILENO);
+ if (daemonfd != 1)
+ (void) dup2(daemonfd, STDOUT_FILENO);
+
+ if (vtnodecount >= 2)
+ (void) ioctl(daemonfd, VT_CONFIG, vtnodecount);
+
+ if ((vt_ah_array = calloc(vtnodecount - 1,
+ sizeof (adt_session_data_t *))) == NULL)
+ return (1);
+
+ (void) ioctl(daemonfd, VT_GETACTIVE, &active);
+
+ if (active == 1) {
+ /*
+ * This is for someone who restarts vtdaemon while vtdaemon
+ * is doing authentication on /dev/vt/1.
+ * A better way is to continue the authentication, but there
+ * are chances that the status of the target VT has changed.
+ * So we just clear the screen here.
+ */
+ (void) write(daemonfd, VT_CLEAR_SCREEN_STR,
+ strlen(VT_CLEAR_SCREEN_STR));
+ }
+
+ vt_serve_events();
+ /*NOTREACHED*/
+}
+
+static int
+vt_audit_start(adt_session_data_t **ah, pid_t pid)
+{
+ ucred_t *uc;
+
+ if (adt_start_session(ah, NULL, 0))
+ return (-1);
+
+ if ((uc = ucred_get(pid)) == NULL) {
+ (void) adt_end_session(*ah);
+ return (-1);
+ }
+
+ if (adt_set_from_ucred(*ah, uc, ADT_NEW)) {
+ ucred_free(uc);
+ (void) adt_end_session(*ah);
+ return (-1);
+ }
+
+ ucred_free(uc);
+ return (0);
+}
+
+/*
+ * Write audit event
+ */
+static void
+vt_audit_event(adt_session_data_t *ah, au_event_t event_id, int status)
+{
+ adt_event_data_t *event;
+
+
+ if ((event = adt_alloc_event(ah, event_id)) == NULL) {
+ return;
+ }
+
+ (void) adt_put_event(event,
+ status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
+ status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM + status);
+
+ adt_free_event(event);
+}
+
+static void
+vt_check_source_audit(void)
+{
+ int fd;
+ int source_vt;
+ int real_vt;
+ struct vt_stat state;
+ pid_t pid;
+ adt_session_data_t *ah;
+
+ if ((fd = open(VT_DAEMON_CONSOLE_FILE, O_WRONLY)) < 0)
+ return;
+
+ if (ioctl(fd, VT_GETSTATE, &state) != 0 ||
+ ioctl(fd, VT_GETACTIVE, &real_vt) != 0) {
+ (void) close(fd);
+ return;
+ }
+
+ source_vt = state.v_active; /* 1..n */
+ (void) close(fd);
+
+ /* check if it's already locked */
+ if (real_vt == 1) /* vtdaemon is taking over the screen */
+ return;
+
+ vt_read_utx(source_vt, &pid, NULL);
+ if (pid == (pid_t)-1)
+ return;
+
+ if (vt_audit_start(&ah, pid) != 0) {
+ syslog(LOG_ERR, "audit start failed ");
+ return;
+ }
+
+ /*
+ * In case the previous session terminated abnormally.
+ */
+ if (vt_ah_array[source_vt - 1] != NULL)
+ (void) adt_end_session(vt_ah_array[source_vt - 1]);
+
+ vt_ah_array[source_vt - 1] = ah;
+
+ vt_audit_event(ah, ADT_screenlock, PAM_SUCCESS);
+}
diff --git a/usr/src/cmd/vt/vtinfo.c b/usr/src/cmd/vt/vtinfo.c
new file mode 100644
index 0000000000..b9af7c3cc3
--- /dev/null
+++ b/usr/src/cmd/vt/vtinfo.c
@@ -0,0 +1,59 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <sys/vt.h>
+
+/*
+ * return value:
+ * 0: disabled
+ * 1: enabled
+ * 2: An error occured
+ */
+int
+main(void)
+{
+ int result;
+ int fd;
+
+ if ((fd = open("/dev/vt/0", O_RDONLY)) < 0)
+ return (2);
+
+ if (ioctl(fd, VT_ENABLED, &result) != 0) {
+ (void) close(fd);
+ return (2);
+ }
+
+ (void) close(fd);
+
+ if (result == 0)
+ return (0); /* disabled */
+
+ return (1); /* enabled */
+}
diff --git a/usr/src/cmd/vt/vtxlock.sh b/usr/src/cmd/vt/vtxlock.sh
new file mode 100644
index 0000000000..4ed6e55c86
--- /dev/null
+++ b/usr/src/cmd/vt/vtxlock.sh
@@ -0,0 +1,85 @@
+#!/sbin/sh
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# $1 is the display to be locked.
+# /var/xauth/$1 is a symbolic link to the actual xauth file.
+#
+
+XSCREENSAVER_LOCK=/usr/openwin/bin/xscreensaver-command
+XSCREENSAVER_LOCKARGS="-lock"
+XSCREENSAVER_CHECKARGS="-time"
+XSCREENSAVER_LOCKED="locked"
+
+OTHER_LOCK=/usr/openwin/bin/xlock
+OTHER_LOCKARGS="-mode blank"
+
+XLSATOMS="/usr/openwin/bin/xlsatoms"
+XLSATOMS_ARGS="-name"
+CDE_ATOM=_DT_SM_PREFERENCES
+GNOME_ATOM=GNOME_SM_DESKTOP
+XSCREENSAVER_ATOM=SCREENSAVER
+
+DISPLAY=:$1; export DISPLAY
+XAUTHORITY=/var/xauth/$1; export XAUTHORITY
+
+#
+# Note that these text strings we're greping are not localized.
+#
+
+#
+# Is it GNOME?
+#
+if ${XLSATOMS} ${XLSATOMS_ARGS} ${GNOME_ATOM} 2>/dev/null \
+ | grep -w ${GNOME_ATOM} >/dev/null; then
+ #
+ # Is it xscreensaver?
+ #
+ # xscreensaver
+ if [ -x ${XSCREENSAVER_LOCK} ]; then
+ ${XSCREENSAVER_LOCK} ${XSCREENSAVER_CHECKARGS} 2>/dev/null \
+ | grep -w ${XSCREENSAVER_LOCKED} >/dev/null && exit 0
+
+ ${XSCREENSAVER_LOCK} ${XSCREENSAVER_LOCKARGS} >/dev/null 2>&1 &
+ exit 0
+ fi
+fi
+
+#
+# Is it CDE?
+#
+if ${XLSATOMS} ${XLSATOMS_ARGS} ${CDE_ATOM} 2>/dev/null \
+ | grep -w ${CDE_ATOM} >/dev/null; then
+ exit 0
+fi
+
+# In other situations, use xlock as default.
+if [ -x ${OTHER_LOCK} ]; then
+ ${OTHER_LOCK} ${OTHER_LOCKARGS} &
+ exit 0
+fi
+
+exit 0
diff --git a/usr/src/lib/libc/port/gen/ttyname.c b/usr/src/lib/libc/port/gen/ttyname.c
index 24f2725199..01a4ea8cb7 100644
--- a/usr/src/lib/libc/port/gen/ttyname.c
+++ b/usr/src/lib/libc/port/gen/ttyname.c
@@ -124,6 +124,7 @@ static const entry_t dev_dir =
static const entry_t def_srch_dirs[] = { /* default search list */
{ "/dev/pts", MATCH_ALL },
+ { "/dev/vt", MATCH_ALL },
{ "/dev/term", MATCH_ALL },
{ "/dev/zcons", MATCH_ALL },
{ NULL, 0 }
@@ -537,6 +538,9 @@ srch_dir(const entry_t path, /* current path */
if (stat64(file_name, &tsb) < 0)
continue;
+ if (strcmp(file_name, "/dev/vt/active") == 0)
+ continue;
+
/*
* skip "/dev/syscon" because it may be an invalid link after
* single user mode.
diff --git a/usr/src/lib/libdevinfo/devinfo_devperm.c b/usr/src/lib/libdevinfo/devinfo_devperm.c
index 3f7380a2de..e2716af8d3 100644
--- a/usr/src/lib/libdevinfo/devinfo_devperm.c
+++ b/usr/src/lib/libdevinfo/devinfo_devperm.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#define _POSIX_PTHREAD_SEMANTICS /* for getgrnam_r */
#ifdef lint
#define _REENTRANT /* for strtok_r */
@@ -56,9 +54,12 @@
#include <strings.h>
#include <libdevinfo.h>
#include <zone.h>
+#include <fcntl.h>
+#include <utmpx.h>
extern int is_minor_node(const char *, const char **);
+static int is_login_user(uid_t);
static int logindevperm(const char *, uid_t, gid_t, void (*)());
static int dir_dev_acc(char *, char *, uid_t, gid_t, mode_t, char *line,
void (*)());
@@ -192,8 +193,21 @@ logindevperm(const char *ttyn, uid_t uid, gid_t gid, void (*errmsg)(char *))
if (console == NULL)
continue; /* ignore blank lines */
- if (strcmp(console, ttyn) != 0)
- continue; /* not our tty, skip */
+ /*
+ * If "console" read from /dev/logindevperm is
+ * "/dev/vt/active", then the first user who logged into
+ * consoles (/dev/vt/# or /dev/console) takes ownership.
+ * Otherwise the first user who logged into "console"
+ * takes owership.
+ */
+ if (strcmp(console, ttyn) != 0) {
+ if (strcmp(console, "/dev/vt/active") != 0)
+ continue; /* not our tty, skip */
+ if (strncmp(ttyn, "/dev/vt/",
+ strlen("/dev/vt/")) != 0 && strcmp(ttyn,
+ "/dev/console") != 0)
+ continue; /* not our tty, skip */
+ }
mode_str = strtok_r(last, field_delims, &last);
if (mode_str == NULL) {
@@ -372,6 +386,38 @@ check_driver_match(char *path, char *line)
}
/*
+ * Check whether the user has logged onto "/dev/console" or "/dev/vt/#".
+ */
+static int
+is_login_user(uid_t uid)
+{
+ int changed = 0;
+ struct passwd pwd, *ppwd;
+ char pwd_buf[NSS_BUFLEN_PASSWD];
+ struct utmpx *utx;
+
+ if ((getpwuid_r(uid, &pwd, pwd_buf, NSS_BUFLEN_PASSWD, &ppwd))) {
+ return (0);
+ }
+
+ setutxent();
+ while ((utx = getutxent()) != NULL) {
+ if (utx->ut_type == USER_PROCESS &&
+ strncmp(utx->ut_user, ppwd->pw_name,
+ strlen(ppwd->pw_name)) == 0 && (strncmp(utx->ut_line,
+ "console", strlen("console")) == 0 || strncmp(utx->ut_line,
+ "vt", strlen("vt")) == 0)) {
+
+ changed = 1;
+ break;
+ }
+ }
+ endutxent();
+
+ return (changed);
+}
+
+/*
* Apply owner/group/perms to all files (except "." and "..")
* in a directory.
* This function is recursive. We start with "/" and the rest of the pathname
@@ -423,6 +469,17 @@ dir_dev_acc(char *path, char *left_to_do, uid_t uid, gid_t gid, mode_t mode,
if (strlen(left_to_do) == 0) {
/* finally check the driver matches */
if (check_driver_match(path, line) == 0) {
+ /*
+ * if the owner of device has been
+ * login, the ownership and mode
+ * should be set already. in
+ * this case, do not set the
+ * permissions.
+ */
+ if (is_login_user(stat_buf.st_uid)) {
+
+ return (0);
+ }
/* we are done, set the permissions */
if (setdevaccess(path,
uid, gid, mode, errmsg)) {
diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt
index 6c671a5d75..42ec91a1b1 100644
--- a/usr/src/lib/libsecdb/auth_attr.txt
+++ b/usr/src/lib/libsecdb/auth_attr.txt
@@ -141,6 +141,7 @@ solaris.smf.manage.system-log:::Manage Syslog Service States::help=SmfSyslogStat
solaris.smf.manage.tnctl:::Manage Refresh of Trusted Network Parameters::help=TNctl.html
solaris.smf.manage.tnd:::Manage Trusted Network Daemon::help=TNDaemon.html
solaris.smf.manage.vscan:::Manage VSCAN Service States::help=SmfVscanStates.html
+solaris.smf.manage.vt:::Manage Virtual Console Service States::help=SmfVtStates.html
solaris.smf.manage.wpa:::Manage WPA Service States::help=SmfWpaStates.html
solaris.smf.manage.ndmp:::Manage NDMP Service States::help=SmfNDMPStates.html
solaris.smf.value.:::Change Values of SMF Service Properties::help=SmfValueHeader.html
@@ -158,6 +159,7 @@ solaris.smf.read.smb:::Read permission for protected SMF SMB Service Properties:
solaris.smf.value.routing:::Change Values of SMF Routing Properties::help=SmfValueRouting.html
solaris.smf.value.tnd:::Change Trusted Network Daemon Service Property Values::help=ValueTND.html
solaris.smf.value.vscan:::Change Values of VSCAN Properties::help=SmfValueVscan.html
+solaris.smf.value.vt:::Change Values of Virtual Console Service Properties::help=SmfValueVt.html
solaris.smf.value.ndmp:::Change Values of SMF NDMP Service Properties::help=SmfValueNDMP.html
solaris.smf.read.ndmp:::Read permission for protected SMF NDMP Service Properties::help=AuthReadNDMP.html
#
diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile
index f279119a4d..af16336769 100644
--- a/usr/src/lib/libsecdb/help/auths/Makefile
+++ b/usr/src/lib/libsecdb/help/auths/Makefile
@@ -91,6 +91,7 @@ HTMLENTS = \
SmfValueExAcctFlow.html \
SmfValueExAcctProcess.html \
SmfValueExAcctTask.html \
+ SmfVtStates.html \
SmfValueHeader.html \
SmfValueInetd.html \
SmfValueIPsec.html \
@@ -107,6 +108,7 @@ HTMLENTS = \
SmfSMBStates.html \
SmfValueVscan.html \
SmfVscanStates.html \
+ SmfValueVt.html \
SmfWpaStates.html \
NetworkAutoconf.html \
NetworkHeader.html \
diff --git a/usr/src/lib/libsecdb/help/auths/SmfValueVt.html b/usr/src/lib/libsecdb/help/auths/SmfValueVt.html
new file mode 100644
index 0000000000..8ff346cbbc
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/SmfValueVt.html
@@ -0,0 +1,37 @@
+<HTML>
+<!--
+ 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
+ or http://www.opensolaris.org/os/licensing.
+ 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 2008 Sun Microsystems, Inc. All rights reserved.
+Use is subject to license terms.
+-->
+<!--
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Value Virtual Console Properties is in the Authorizations Include
+column, it grants the the authorization to change virtual console service
+property values.
+<P>
+If Value Virtual Console Properties is grayed, then you are not entitled to
+Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/auths/SmfVtStates.html b/usr/src/lib/libsecdb/help/auths/SmfVtStates.html
new file mode 100644
index 0000000000..33b660289c
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/SmfVtStates.html
@@ -0,0 +1,37 @@
+<HTML>
+<!--
+ 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
+ or http://www.opensolaris.org/os/licensing.
+ 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 2008 Sun Microsystems, Inc. All rights reserved.
+Use is subject to license terms.
+-->
+<!--
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Manage Virtual Console Service States is in the Authorizations Include
+column, it grants the authorization to enable, disable, or
+restart the virtual console daemon.
+<p>
+If Manage Virtual Console Service States is grayed, then you are not entitled
+to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt
index 4c09ff6b49..2fb7504a67 100644
--- a/usr/src/lib/libsecdb/prof_attr.txt
+++ b/usr/src/lib/libsecdb/prof_attr.txt
@@ -39,7 +39,7 @@ Printer Management:::Manage printers, daemons, spooling:auths=solaris.print.*,so
Cron Management:::Manage at and cron jobs:auths=solaris.jobs.*,solaris.smf.manage.cron;help=RtCronMngmnt.html
Log Management:::Manage log files:help=RtLogMngmnt.html
Basic Solaris User:::Automatically assigned rights:auths=solaris.profmgr.read,solaris.jobs.user,solaris.mail.mailq,solaris.device.mount.removable;profiles=All;help=RtDefault.html
-Device Security:::Manage devices and Volume Manager:auths=solaris.device.*;help=RtDeviceSecurity.html
+Device Security:::Manage devices and Volume Manager:auths=solaris.device.*,solaris.smf.manage.vt;help=RtDeviceSecurity.html
DHCP Management:::Manage the DHCP service:auths=solaris.dhcpmgr.*;help=RtDHCPMngmnt.html
Extended Accounting Flow Management:::Manage the Flow Extended Accounting service:auths=solaris.smf.manage.extended-accounting.flow,solaris.smf.value.extended-accounting.flow;profiles=acctadm;help=RtExActtFlow.html
Extended Accounting Process Management:::Manage the Process Extended Accounting service:auths=solaris.smf.manage.extended-accounting.process,solaris.smf.value.extended-accounting.process;profiles=acctadm;hep=RtExAcctProcess.html
diff --git a/usr/src/pkgdefs/SUNW0on/prototype_com b/usr/src/pkgdefs/SUNW0on/prototype_com
index 387eeaab53..a8ec534d70 100644
--- a/usr/src/pkgdefs/SUNW0on/prototype_com
+++ b/usr/src/pkgdefs/SUNW0on/prototype_com
@@ -265,6 +265,7 @@ f none usr/lib/help/auths/locale/SmfVscanStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueExAcctFlow.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueExAcctProcess.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueExAcctTask.html 444 root bin
+f none usr/lib/help/auths/locale/SmfVtStates.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueHeader.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueInetd.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueIPsec.html 444 root bin
@@ -279,6 +280,7 @@ f none usr/lib/help/auths/locale/SmfValueRouting.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueSMB.html 444 root bin
f none usr/lib/help/auths/locale/AuthReadSMB.html 444 root bin
f none usr/lib/help/auths/locale/SmfValueVscan.html 444 root bin
+f none usr/lib/help/auths/locale/SmfValueVt.html 444 root bin
f none usr/lib/help/auths/locale/SmfWpaStates.html 444 root bin
f none usr/lib/help/auths/locale/NetworkAutoconf.html 444 root bin
f none usr/lib/help/auths/locale/NetworkHeader.html 444 root bin
diff --git a/usr/src/pkgdefs/SUNWcsd/prototype_com b/usr/src/pkgdefs/SUNWcsd/prototype_com
index 1c036a6c15..9ff03705c9 100644
--- a/usr/src/pkgdefs/SUNWcsd/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsd/prototype_com
@@ -22,8 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This required package information file contains a list of package contents.
# The 'pkgmk' command uses this file to identify the contents of a package
# and their location on the development machine when building the package.
@@ -82,6 +80,7 @@ s none dev/stdin=./fd/0
s none dev/stdout=./fd/1
d none dev/swap 755 root sys
d none dev/term 755 root root
+d none dev/vt 755 root sys
d none dev/zcons 755 root sys
d none devices 755 root sys
d none devices/pseudo 755 root sys
diff --git a/usr/src/pkgdefs/SUNWcsr/postinstall b/usr/src/pkgdefs/SUNWcsr/postinstall
index a97a62f4f6..fb42157c67 100644
--- a/usr/src/pkgdefs/SUNWcsr/postinstall
+++ b/usr/src/pkgdefs/SUNWcsr/postinstall
@@ -21,8 +21,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
BASEPREFIX=`echo $BASEDIR | sed "s/\//_/g"`
#
# Clear sysidtool which may have gone into maintenance due to a dependency
@@ -408,4 +406,29 @@ if [ -f /etc/acctadm.conf ]; then
fi
_ACCTADM
+# Preinstall script will create this file if vtdaemon service was
+# already installed, in which case we preserve current service state,
+# be it enabled or disabled.
+if [ -f $PKG_INSTALL_ROOT/var/tmp/vtdaemon_installed.tmp ]; then
+ rm -f $PKG_INSTALL_ROOT/var/tmp/vtdaemon_installed.tmp
+elif [ "${PKG_INSTALL_ROOT:-/}" = "/" ]; then
+ # live system
+ /usr/sbin/svcadm enable svc:/system/vtdaemon:default
+ /usr/sbin/svcadm enable svc:/system/console-login:vt2
+ /usr/sbin/svcadm enable svc:/system/console-login:vt3
+ /usr/sbin/svcadm enable svc:/system/console-login:vt4
+ /usr/sbin/svcadm enable svc:/system/console-login:vt5
+ /usr/sbin/svcadm enable svc:/system/console-login:vt6
+else
+ # upgrade
+ cat >> ${PKG_INSTALL_ROOT}/var/svc/profile/upgrade <<-EOF
+ /usr/sbin/svcadm enable svc:/system/vtdaemon:default
+ /usr/sbin/svcadm enable svc:/system/console-login:vt2
+ /usr/sbin/svcadm enable svc:/system/console-login:vt3
+ /usr/sbin/svcadm enable svc:/system/console-login:vt4
+ /usr/sbin/svcadm enable svc:/system/console-login:vt5
+ /usr/sbin/svcadm enable svc:/system/console-login:vt6
+ EOF
+fi
+
exit 0
diff --git a/usr/src/pkgdefs/SUNWcsr/preinstall b/usr/src/pkgdefs/SUNWcsr/preinstall
index 53fe22b5ec..ad54851d7d 100644
--- a/usr/src/pkgdefs/SUNWcsr/preinstall
+++ b/usr/src/pkgdefs/SUNWcsr/preinstall
@@ -18,10 +18,9 @@
#
# CDDL HEADER END
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
#
# When first introduced the /etc/inet/ipnodes file was seperate from
@@ -127,4 +126,14 @@ if [ "$UPDATE" = yes ]; then
fi
fi
+# Presence of this temp file will tell postinstall script
+# that the vtdaemon service is already installed, in which case
+# the current service state will be preserved, be it enabled
+# or disabled.
+rm -f $PKG_INSTALL_ROOT/var/tmp/vtdaemon_installed.tmp > /dev/null 2>&1
+
+if [ -f $PKG_INSTALL_ROOT/var/svc/manifest/system/vtdaemon.xml ]; then
+ touch $PKG_INSTALL_ROOT/var/tmp/vtdaemon_installed.tmp
+fi
+
exit 0
diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com
index 737e3b4757..a806ca1425 100644
--- a/usr/src/pkgdefs/SUNWcsr/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsr/prototype_com
@@ -375,6 +375,7 @@ f none lib/svc/method/svc-dlmgmtd 0555 root bin
f none lib/svc/method/svc-nscd 0555 root bin
f none lib/svc/method/svc-utmpd 0555 root bin
f none lib/svc/method/system-log 0555 root bin
+f none lib/svc/method/vtdaemon 0555 root bin
f none lib/svc/method/yp 0555 root bin
d none lib/svc/monitor 0755 root bin
d none lib/svc/seed 0755 root bin
@@ -547,6 +548,7 @@ f manifest var/svc/manifest/system/rmtmpfiles.xml 0444 root sys
f manifest var/svc/manifest/system/sac.xml 0444 root sys
f manifest var/svc/manifest/system/system-log.xml 0444 root sys
f manifest var/svc/manifest/system/utmp.xml 0444 root sys
+f manifest var/svc/manifest/system/vtdaemon.xml 0444 root sys
d none var/svc/manifest/system/svc 755 root sys
f manifest var/svc/manifest/system/svc/restarter.xml 0444 root sys
d none var/svc/profile 755 root sys
diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com
index 213f55d4a3..e01cfff87c 100644
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com
@@ -505,6 +505,7 @@ f none usr/lib/help/auths/locale/C/SmfSyslogStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueExAcctFlow.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueExAcctProcess.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueExAcctTask.html 444 root bin
+f none usr/lib/help/auths/locale/C/SmfVtStates.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueHeader.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueInetd.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueIPsec.html 444 root bin
@@ -519,6 +520,7 @@ f none usr/lib/help/auths/locale/C/SmfValueRouting.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfValueSMB.html 444 root bin
f none usr/lib/help/auths/locale/C/AuthReadSMB.html 444 root bin
f none usr/lib/help/auths/locale/C/SmfWpaStates.html 444 root bin
+f none usr/lib/help/auths/locale/C/SmfValueVt.html 444 root bin
f none usr/lib/help/auths/locale/C/SysDate.html 444 root bin
f none usr/lib/help/auths/locale/C/SysHeader.html 444 root bin
f none usr/lib/help/auths/locale/C/SysMaintenance.html 444 root bin
@@ -697,6 +699,9 @@ f none usr/lib/utmp_update 4555 root bin
f none usr/lib/utmpd 555 root bin
f none usr/lib/vna 555 root bin
f none usr/lib/vplot 555 root bin
+f none usr/lib/vtdaemon 555 root bin
+f none usr/lib/vtinfo 555 root bin
+f none usr/lib/vtxlock 555 root bin
s none usr/mail=../var/mail
d none usr/net 755 root sys
d none usr/net/nls 755 root sys
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com
index 91e68ba64f..6a9a3b1db8 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_com
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com
@@ -957,6 +957,7 @@ f none usr/include/sys/kbd.h 644 root bin
f none usr/include/sys/kbdreg.h 644 root bin
f none usr/include/sys/kbio.h 644 root bin
f none usr/include/sys/kcpc.h 644 root bin
+f none usr/include/sys/kd.h 644 root bin
f none usr/include/sys/kdi.h 644 root bin
f none usr/include/sys/kdi_impl.h 644 root bin
f none usr/include/sys/kdi_machimpl.h 644 root bin
@@ -1354,6 +1355,8 @@ f none usr/include/sys/vmmeter.h 644 root bin
f none usr/include/sys/vmparam.h 644 root bin
f none usr/include/sys/vmsystm.h 644 root bin
f none usr/include/sys/vnode.h 644 root bin
+f none usr/include/sys/vt.h 644 root bin
+f none usr/include/sys/vtdaemon.h 644 root bin
f none usr/include/sys/vtoc.h 644 root bin
f none usr/include/sys/vtrace.h 644 root bin
f none usr/include/sys/vuid_event.h 644 root bin
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_i386 b/usr/src/pkgdefs/SUNWhea/prototype_i386
index 824c5d690c..c5769ec020 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_i386
+++ b/usr/src/pkgdefs/SUNWhea/prototype_i386
@@ -22,7 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#
# This required package information file contains a list of package contents.
# The 'pkgmk' command uses this file to identify the contents of a package
# and their location on the development machine when building the package.
@@ -89,7 +88,6 @@ f none usr/include/sys/fp.h 644 root bin
f none usr/include/sys/hypervisor.h 644 root bin
f none usr/include/sys/i8272A.h 644 root bin
f none usr/include/sys/iommulib.h 644 root bin
-f none usr/include/sys/kd.h 644 root bin
f none usr/include/sys/mc.h 644 root bin
f none usr/include/sys/mc_amd.h 644 root bin
f none usr/include/sys/mca_amd.h 644 root bin
diff --git a/usr/src/pkgdefs/common_files/i.logindevperm b/usr/src/pkgdefs/common_files/i.logindevperm
index e05cbe9823..ea511184d8 100644
--- a/usr/src/pkgdefs/common_files/i.logindevperm
+++ b/usr/src/pkgdefs/common_files/i.logindevperm
@@ -19,10 +19,7 @@
#
# CDDL HEADER END
#
-#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -62,9 +59,13 @@ while read src dest; do
devices=`echo "$devices" | sed 's/\[/\\\[/g' | sed 's/\]/\\\]/g' | sed 's/\+/\\\+/g' | sed 's/\*/\\\*/g'`
- # if dest has an entry for these devices, preserve that
+ # if dest has an entry for these devices and the difference
+ # between dest entry and src entry is not only
+ # "/dev/console" vs. "/dev/vt/active", preserve dest entry
dest_entry=`egrep "^[# ]*/[a-zA-Z0-9\/]+[ ]+[0-9]+[ ]+$devices[ ]*$drivers" $dest | tail -1 2>/dev/null`
- if [ -n "$dest_entry" ]; then
+ tmp_line=`echo "$line" | sed 's:/dev/vt/active:/dev/console:'`
+
+ if [ -n "$dest_entry" ] && [ "$dest_entry" != "$tmp_line" ]; then
echo "$dest_entry"
else
echo "$line"
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index 5350bc4e40..5076f9f718 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -247,6 +247,7 @@ superfluous_nonglobal_zone_files="
dev/stdout
dev/swap
dev/term
+ dev/vt
devices
etc/dacf.conf
etc/dat
@@ -321,6 +322,7 @@ superfluous_nonglobal_zone_files="
lib/svc/method/svc-tnd
lib/svc/method/svc-vntsd
lib/svc/method/svc-zones
+ lib/svc/method/vtdaemon
platform/*/kernel
platform/SUNW,Sun-Fire-15000/lib/cvcd
platform/SUNW,Ultra-Enterprise-10000/lib/cvcd
@@ -379,6 +381,7 @@ superfluous_nonglobal_zone_files="
var/svc/manifest/system/resource-mgmt.xml
var/svc/manifest/system/scheduler.xml
var/svc/manifest/system/sysevent.xml
+ var/svc/manifest/system/vtdaemon.xml
var/svc/manifest/system/zones.xml
var/svc/manifest/system/filesystem/rmvolmgr.xml
"
@@ -1557,6 +1560,20 @@ smf_cleanup_dlmgmtd() {
)
}
+smf_cleanup_vt() {
+ (
+ smf_delete_manifest var/src/manifest/system/vtdaemon.xml
+ cd $root
+ rm -f lib/svc/method/vtdaemon
+
+ vt_conslogin_instances=`/usr/bin/svcs -o FMRI | \
+ grep console-login:vt`
+ for i in $vt_conslogin_instances; do
+ /usr/sbin/svccfg delete -f $i
+ done
+ )
+}
+
old_mfst_dir="var/svc/manifest.orig"
new_mfst_dir="var/svc/manifest"
@@ -1864,6 +1881,17 @@ smf_apply_conf () {
smf_cleanup_dlmgmtd
fi
+ #
+ # When doing backwards BFU, if the target does not contain
+ # vtdaemon manifest, delete it and delete all the additional
+ # console-login service instances which were used to provide
+ # additional console sessions.
+ #
+ if ((! $ZCAT $cpiodir/generic.root$ZFIX | cpio -it 2>/dev/null | \
+ grep vtdaemon.xml > /dev/null 2>&1) && [ $zone = global ]); then
+ smf_cleanup_vt
+ fi
+
print "Disabling unneeded inetd.conf entries ..."
smf_inetd_disable
smf_tftp_reinstall
@@ -6029,6 +6057,7 @@ mondo_loop() {
rm -f \
$usr/include/table.h \
$usr/include/libgenIO.h \
+ $usr/include/sys/kd.h \
$usr/lib/llib-lTL \
$usr/lib/llib-lTL.ln
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 5da8fe4faa..7affe7dc8e 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -666,7 +666,9 @@ USBS49_FW_OBJS += keyspan_49fw.o
USBSPRL_OBJS += usbser_pl2303.o pl2303_dsd.o
-WC_OBJS += wscons.o
+WC_OBJS += wscons.o vcons.o
+
+VCONS_CONF_OBJS += vcons_conf.o
SCSI_OBJS += scsi_capabilities.o scsi_confsubr.o scsi_control.o \
scsi_data.o scsi_fm.o scsi_hba.o scsi_reset_notify.o \
@@ -857,7 +859,7 @@ DEVFS_OBJS += devfs_subr.o devfs_vfsops.o devfs_vnops.o
DEV_OBJS += sdev_subr.o sdev_vfsops.o sdev_vnops.o \
sdev_ptsops.o sdev_comm.o sdev_profile.o \
- sdev_ncache.o sdev_netops.o
+ sdev_ncache.o sdev_netops.o sdev_vtops.o
CTFS_OBJS += ctfs_all.o ctfs_cdir.o ctfs_ctl.o ctfs_event.o \
ctfs_latest.o ctfs_root.o ctfs_sym.o ctfs_tdir.o ctfs_tmpl.o
diff --git a/usr/src/uts/common/fs/dev/sdev_subr.c b/usr/src/uts/common/fs/dev/sdev_subr.c
index 40d2b7962e..7a926cab67 100644
--- a/usr/src/uts/common/fs/dev/sdev_subr.c
+++ b/usr/src/uts/common/fs/dev/sdev_subr.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* utility routines for the /dev fs
*/
@@ -608,6 +606,9 @@ static struct sdev_vop_table vtab[] =
{ "pts", devpts_vnodeops_tbl, NULL, &devpts_vnodeops, devpts_validate,
SDEV_DYNAMIC | SDEV_VTOR },
+ { "vt", devvt_vnodeops_tbl, NULL, &devvt_vnodeops, devvt_validate,
+ SDEV_DYNAMIC | SDEV_VTOR },
+
{ "zcons", NULL, NULL, NULL, NULL, SDEV_NO_NCACHE },
{ "net", devnet_vnodeops_tbl, NULL, &devnet_vnodeops, devnet_validate,
@@ -1949,7 +1950,6 @@ sdev_call_dircallback(struct sdev_node *ddv, struct sdev_node **dvp, char *nm,
return (-1);
}
- ASSERT(physpath);
rvp = devname_configure_by_path(physpath, NULL);
if (rvp == NULL) {
sdcmn_err3(("devname_configure_by_path: "
@@ -1990,6 +1990,34 @@ sdev_call_dircallback(struct sdev_node *ddv, struct sdev_node **dvp, char *nm,
return (0);
}
}
+ } else if (flags & SDEV_VLINK) {
+ physpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ rv = callback(ddv, nm, (void *)&physpath, kcred, NULL,
+ NULL);
+ if (rv) {
+ kmem_free(physpath, MAXPATHLEN);
+ return (-1);
+ }
+
+ vap = sdev_getdefault_attr(VLNK);
+ vap->va_size = strlen(physpath);
+ ASSERT(RW_READ_HELD(&ddv->sdev_contents));
+
+ if (!rw_tryupgrade(&ddv->sdev_contents)) {
+ rw_exit(&ddv->sdev_contents);
+ rw_enter(&ddv->sdev_contents, RW_WRITER);
+ }
+ rv = sdev_mknode(ddv, nm, &dv, vap, NULL,
+ (void *)physpath, cred, SDEV_READY);
+ rw_downgrade(&ddv->sdev_contents);
+ kmem_free(physpath, MAXPATHLEN);
+ if (rv)
+ return (rv);
+
+ mutex_enter(&dv->sdev_lookup_lock);
+ SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP);
+ mutex_exit(&dv->sdev_lookup_lock);
+ return (0);
} else if (flags & SDEV_VNODE) {
/*
* DBNR has its own way to create the device
diff --git a/usr/src/uts/common/fs/dev/sdev_vtops.c b/usr/src/uts/common/fs/dev/sdev_vtops.c
new file mode 100644
index 0000000000..11ceaadd26
--- /dev/null
+++ b/usr/src/uts/common/fs/dev/sdev_vtops.c
@@ -0,0 +1,442 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * vnode ops for the /dev/vt directory
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <sys/sunndi.h>
+#include <fs/fs_subr.h>
+#include <sys/fs/dv_node.h>
+#include <sys/fs/sdev_impl.h>
+#include <sys/policy.h>
+#include <sys/stat.h>
+#include <sys/vfs_opreg.h>
+#include <sys/tty.h>
+#include <sys/vt_impl.h>
+#include <sys/note.h>
+
+/* warlock in this file only cares about variables shared by vt and devfs */
+_NOTE(SCHEME_PROTECTS_DATA("Do not care", sdev_node vattr vnode))
+
+#define DEVVT_UID_DEFAULT SDEV_UID_DEFAULT
+#define DEVVT_GID_DEFAULT (0)
+#define DEVVT_DEVMODE_DEFAULT (0600)
+#define DEVVT_ACTIVE_NAME "active"
+
+#define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
+
+/* attributes for VT nodes */
+static vattr_t devvt_vattr = {
+ AT_TYPE|AT_MODE|AT_UID|AT_GID, /* va_mask */
+ VCHR, /* va_type */
+ S_IFCHR | DEVVT_DEVMODE_DEFAULT, /* va_mode */
+ DEVVT_UID_DEFAULT, /* va_uid */
+ DEVVT_GID_DEFAULT, /* va_gid */
+ 0 /* 0 hereafter */
+};
+
+struct vnodeops *devvt_vnodeops;
+
+struct vnodeops *
+devvt_getvnodeops(void)
+{
+ return (devvt_vnodeops);
+}
+
+static int
+devvt_str2minor(const char *nm, minor_t *mp)
+{
+ long uminor = 0;
+ char *endptr = NULL;
+
+ if (nm == NULL || !isdigit(*nm))
+ return (EINVAL);
+
+ *mp = 0;
+ if (ddi_strtol(nm, &endptr, 10, &uminor) != 0 ||
+ *endptr != '\0' || uminor < 0) {
+ return (EINVAL);
+ }
+
+ *mp = (minor_t)uminor;
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+devvt_validate(struct sdev_node *dv)
+{
+ minor_t min;
+ char *nm = dv->sdev_name;
+
+ ASSERT(!(dv->sdev_flags & SDEV_STALE));
+ ASSERT(dv->sdev_state == SDEV_READY);
+
+ /* validate only READY nodes */
+ if (dv->sdev_state != SDEV_READY) {
+ sdcmn_err(("dev fs: skipping: node not ready %s(%p)",
+ nm, (void *)dv));
+ return (SDEV_VTOR_SKIP);
+ }
+
+ if (vt_wc_attached() == (major_t)-1)
+ return (SDEV_VTOR_INVALID);
+
+ if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
+ char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+ (void) vt_getactive(link, MAXPATHLEN);
+ if (strcmp(link, dv->sdev_symlink) != 0) {
+ kmem_free(dv->sdev_symlink,
+ strlen(dv->sdev_symlink) + 1);
+ dv->sdev_symlink = i_ddi_strdup(link, KM_SLEEP);
+ dv->sdev_attr->va_size = strlen(link);
+ }
+ kmem_free(link, MAXPATHLEN);
+ return (SDEV_VTOR_VALID);
+ } else if (devvt_str2minor(nm, &min) != 0) {
+ return (SDEV_VTOR_INVALID);
+ }
+
+ if (vt_minor_valid(min) == B_FALSE)
+ return (SDEV_VTOR_INVALID);
+
+ return (SDEV_VTOR_VALID);
+}
+
+/*
+ * This callback is invoked from devname_lookup_func() to create
+ * a entry when the node is not found in the cache.
+ */
+/*ARGSUSED*/
+static int
+devvt_create_rvp(struct sdev_node *ddv, char *nm,
+ void **arg, cred_t *cred, void *whatever, char *whichever)
+{
+ minor_t min;
+ major_t maj;
+ struct vattr *vap = (struct vattr *)arg;
+
+ if ((maj = vt_wc_attached()) == (major_t)-1)
+ return (SDEV_VTOR_INVALID);
+
+ if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
+ (void) vt_getactive((char *)*arg, MAXPATHLEN);
+ return (0);
+ }
+
+ if (devvt_str2minor(nm, &min) != 0)
+ return (-1);
+
+ if (vt_minor_valid(min) == B_FALSE)
+ return (-1);
+
+ *vap = devvt_vattr;
+ vap->va_rdev = makedevice(maj, min);
+
+ return (0);
+}
+
+/*ARGSUSED3*/
+static int
+devvt_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
+ struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
+{
+ struct sdev_node *sdvp = VTOSDEV(dvp);
+ struct sdev_node *dv;
+ struct vnode *rvp = NULL;
+ int type, error;
+
+ if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
+ type = SDEV_VLINK;
+ } else {
+ type = SDEV_VATTR;
+ }
+
+/* Give warlock a more clear call graph */
+#ifndef __lock_lint
+ error = devname_lookup_func(sdvp, nm, vpp, cred,
+ devvt_create_rvp, type);
+#else
+ devvt_create_rvp(0, 0, 0, 0, 0, 0);
+#endif
+
+ if (error == 0) {
+ switch ((*vpp)->v_type) {
+ case VCHR:
+ dv = VTOSDEV(VTOS(*vpp)->s_realvp);
+ ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
+ break;
+ case VDIR:
+ case VLNK:
+ dv = VTOSDEV(*vpp);
+ break;
+ default:
+ cmn_err(CE_PANIC, "devvt_lookup: Unsupported node "
+ "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
+ break;
+ }
+ ASSERT(SDEV_HELD(dv));
+ }
+
+ return (error);
+}
+
+static void
+devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type)
+{
+ int error;
+ struct sdev_node *sdv = NULL;
+ struct vattr *vap = NULL;
+ major_t maj;
+ minor_t min;
+
+ if ((maj = vt_wc_attached()) == (major_t)-1)
+ return;
+
+ if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 &&
+ devvt_str2minor(nm, &min) != 0)
+ return;
+
+ error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT);
+ if (error || !sdv) {
+ return;
+ }
+
+ mutex_enter(&sdv->sdev_lookup_lock);
+ SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP);
+ mutex_exit(&sdv->sdev_lookup_lock);
+
+ if (type & SDEV_VATTR) {
+ vap = &devvt_vattr;
+ vap->va_rdev = makedevice(maj, min);
+ error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
+ NULL, cred, SDEV_READY);
+ } else if (type & SDEV_VLINK) {
+ char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+ (void) vt_getactive(link, MAXPATHLEN);
+ vap = &sdev_vattr_lnk;
+ vap->va_size = strlen(link);
+ error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
+ (void *)link, cred, SDEV_READY);
+
+ kmem_free(link, MAXPATHLEN);
+ }
+
+ mutex_enter(&sdv->sdev_lookup_lock);
+ SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP);
+ mutex_exit(&sdv->sdev_lookup_lock);
+
+}
+
+static void
+devvt_prunedir(struct sdev_node *ddv)
+{
+ struct vnode *vp;
+ struct sdev_node *dv, *next = NULL;
+ int (*vtor)(struct sdev_node *) = NULL;
+
+ ASSERT(ddv->sdev_flags & SDEV_VTOR);
+
+ vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
+ ASSERT(vtor);
+
+ for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
+ next = SDEV_NEXT_ENTRY(ddv, dv);
+
+ /* skip stale nodes */
+ if (dv->sdev_flags & SDEV_STALE)
+ continue;
+
+ /* validate and prune only ready nodes */
+ if (dv->sdev_state != SDEV_READY)
+ continue;
+
+ switch (vtor(dv)) {
+ case SDEV_VTOR_VALID:
+ case SDEV_VTOR_SKIP:
+ continue;
+ case SDEV_VTOR_INVALID:
+ sdcmn_err7(("destroy invalid "
+ "node: %s(%p)\n", dv->sdev_name, (void *)dv));
+ break;
+ }
+ vp = SDEVTOV(dv);
+ if (vp->v_count > 0)
+ continue;
+ SDEV_HOLD(dv);
+ /* remove the cache node */
+ (void) sdev_cache_update(ddv, &dv, dv->sdev_name,
+ SDEV_CACHE_DELETE);
+ }
+}
+
+static void
+devvt_cleandir(struct vnode *dvp, struct cred *cred)
+{
+ struct sdev_node *sdvp = VTOSDEV(dvp);
+ struct sdev_node *dv, *next = NULL;
+ int min, cnt;
+ int found = 0;
+
+ mutex_enter(&vc_lock);
+ cnt = VC_INSTANCES_COUNT;
+ mutex_exit(&vc_lock);
+
+/* We have to fool warlock this way, otherwise it will complain */
+#ifndef __lock_lint
+ if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) {
+ rw_exit(&sdvp->sdev_contents);
+ rw_enter(&sdvp->sdev_contents, RW_WRITER);
+ }
+#else
+ rw_enter(&sdvp->sdev_contents, RW_WRITER);
+#endif
+
+ /* 1. create missed nodes */
+ for (min = 0; min < cnt; min++) {
+ char nm[16];
+
+ if (vt_minor_valid(min) == B_FALSE)
+ continue;
+
+ (void) snprintf(nm, sizeof (nm), "%d", min);
+ found = 0;
+ for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
+ next = SDEV_NEXT_ENTRY(sdvp, dv);
+
+ /* skip stale nodes */
+ if (dv->sdev_flags & SDEV_STALE)
+ continue;
+ /* validate and prune only ready nodes */
+ if (dv->sdev_state != SDEV_READY)
+ continue;
+ if (strcmp(nm, dv->sdev_name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ devvt_create_snode(sdvp, nm, cred, SDEV_VATTR);
+ }
+ }
+
+ /* 2. create active link node */
+ found = 0;
+ for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
+ next = SDEV_NEXT_ENTRY(sdvp, dv);
+
+ /* skip stale nodes */
+ if (dv->sdev_flags & SDEV_STALE)
+ continue;
+ /* validate and prune only ready nodes */
+ if (dv->sdev_state != SDEV_READY)
+ continue;
+ if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK);
+
+ /* 3. cleanup invalid nodes */
+ devvt_prunedir(sdvp);
+
+#ifndef __lock_lint
+ rw_downgrade(&sdvp->sdev_contents);
+#else
+ rw_exit(&sdvp->sdev_contents);
+#endif
+}
+
+/*ARGSUSED4*/
+static int
+devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
+ int *eofp, caller_context_t *ct, int flags)
+{
+ if (uiop->uio_offset == 0) {
+ devvt_cleandir(dvp, cred);
+ }
+
+ return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
+}
+
+/*
+ * We allow create to find existing nodes
+ * - if the node doesn't exist - EROFS
+ * - creating an existing dir read-only succeeds, otherwise EISDIR
+ * - exclusive creates fail - EEXIST
+ */
+/*ARGSUSED2*/
+static int
+devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
+ int mode, struct vnode **vpp, struct cred *cred, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
+{
+ int error;
+ struct vnode *vp;
+
+ *vpp = NULL;
+
+ if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
+ NULL)) != 0) {
+ if (error == ENOENT)
+ error = EROFS;
+ return (error);
+ }
+
+ if (excl == EXCL)
+ error = EEXIST;
+ else if (vp->v_type == VDIR && (mode & VWRITE))
+ error = EISDIR;
+ else
+ error = VOP_ACCESS(vp, mode, 0, cred, ct);
+
+ if (error) {
+ VN_RELE(vp);
+ } else
+ *vpp = vp;
+
+ return (error);
+}
+
+const fs_operation_def_t devvt_vnodeops_tbl[] = {
+ VOPNAME_READDIR, { .vop_readdir = devvt_readdir },
+ VOPNAME_LOOKUP, { .vop_lookup = devvt_lookup },
+ VOPNAME_CREATE, { .vop_create = devvt_create },
+ VOPNAME_REMOVE, { .error = fs_nosys },
+ VOPNAME_MKDIR, { .error = fs_nosys },
+ VOPNAME_RMDIR, { .error = fs_nosys },
+ VOPNAME_SYMLINK, { .error = fs_nosys },
+ VOPNAME_SETSECATTR, { .error = fs_nosys },
+ NULL, NULL
+};
diff --git a/usr/src/uts/common/fs/namefs/namevfs.c b/usr/src/uts/common/fs/namefs/namevfs.c
index fa245b1ece..a6670d9cd6 100644
--- a/usr/src/uts/common/fs/namefs/namevfs.c
+++ b/usr/src/uts/common/fs/namefs/namevfs.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -27,8 +27,6 @@
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI" /* from S5R4 1.28 */
-
/*
* This file supports the vfs operations for the NAMEFS file system.
*/
@@ -356,13 +354,14 @@ nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
/*
* Cannot allow users to fattach() in /dev/pts.
* First, there is no need for doing so and secondly
- * we cannot allow arbitrary users to park on a
- * /dev/pts node.
+ * we cannot allow arbitrary users to park on a node in
+ * /dev/pts or /dev/vt.
*/
rvp = NULLVP;
if (vn_matchops(mvp, spec_getvnodeops()) &&
VOP_REALVP(mvp, &rvp, NULL) == 0 && rvp &&
- vn_matchops(rvp, devpts_getvnodeops())) {
+ (vn_matchops(rvp, devpts_getvnodeops()) ||
+ vn_matchops(rvp, devvt_getvnodeops()))) {
releasef(namefdp.fd);
return (ENOTSUP);
}
diff --git a/usr/src/uts/common/io/cons.c b/usr/src/uts/common/io/cons.c
index 9174f48db9..a44c5c7a9f 100644
--- a/usr/src/uts/common/io/cons.c
+++ b/usr/src/uts/common/io/cons.c
@@ -24,7 +24,6 @@
* Use is subject to license terms.
*/
-
/*
* Indirect console driver for Sun.
*
@@ -221,6 +220,7 @@ cn_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
ddi_remove_minor_node(devi, NULL);
return (DDI_FAILURE);
}
+
cn_dip = devi;
return (DDI_SUCCESS);
}
@@ -357,7 +357,6 @@ cnclose(dev_t dev, int flag, int state, struct cred *cred)
while ((rconsopen != 0) && ((vp = rconsvp) != NULL)) {
err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
if (!err) {
- vp->v_stream = NULL;
rconsopen--;
}
}
diff --git a/usr/src/uts/common/io/consconfig_dacf.c b/usr/src/uts/common/io/consconfig_dacf.c
index fbc71cb239..4226766769 100644
--- a/usr/src/uts/common/io/consconfig_dacf.c
+++ b/usr/src/uts/common/io/consconfig_dacf.c
@@ -496,6 +496,9 @@ consconfig_tem_supported(cons_state_t *sp)
uint_t nint;
int rv = 0;
+ if (sp->cons_fb_path == NULL)
+ return (0);
+
if ((dev = ddi_pathname_to_dev_t(sp->cons_fb_path)) == NODEV)
return (0); /* warning printed later by common code */
@@ -722,6 +725,9 @@ consconfig_state_init(void)
#endif /* _HAVE_TEM_FIRMWARE */
} else {
sp->cons_fb_path = plat_fbpath();
+#ifdef _HAVE_TEM_FIRMWARE
+ sp->cons_tem_supported = consconfig_tem_supported(sp);
+#endif /* _HAVE_TEM_FIRMWARE */
}
sp->cons_li = ldi_ident_from_anon();
@@ -2109,3 +2115,17 @@ flush_usb_serial_buf(void)
kmem_free(usbser_kern_buf, MMU_PAGESIZE);
}
+
+boolean_t
+consconfig_console_is_tipline(void)
+{
+ cons_state_t *sp;
+
+ if ((sp = (cons_state_t *)space_fetch("consconfig")) == NULL)
+ return (B_FALSE);
+
+ if (sp->cons_input_type == CONSOLE_TIP)
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
diff --git a/usr/src/uts/common/io/kbtrans/kbtrans_streams.c b/usr/src/uts/common/io/kbtrans/kbtrans_streams.c
index f5b6a4a1d9..fa99e5caac 100644
--- a/usr/src/uts/common/io/kbtrans/kbtrans_streams.c
+++ b/usr/src/uts/common/io/kbtrans/kbtrans_streams.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Generic keyboard support: streams and administration.
*/
@@ -56,6 +54,8 @@ int kbtrans_errmask;
int kbtrans_errlevel;
#endif
+#define KB_NR_FUNCKEYS 12
+
/*
* Repeat rates set in static variables so they can be tweeked with
* debugger.
@@ -78,7 +78,7 @@ extern struct mod_ops mod_miscops;
static struct modlmisc modlmisc = {
&mod_miscops, /* Type of module */
- "kbtrans (key translation) 1.32"
+ "kbtrans (key translation)"
};
static struct modlinkage modlinkage = {
@@ -242,7 +242,7 @@ kbtrans_streams_init(
case CLONEOPEN:
DPRINTF(PRINT_L1, PRINT_MASK_OPEN, (NULL,
- "kbtrans_streams_init: Clone open not supported"));
+ "kbtrans_streams_init: Clone open not supported"));
return (EINVAL);
}
@@ -308,15 +308,15 @@ kbtrans_streams_init(
/* Allocate dynamic memory for downs table */
upper->kbtrans_streams_num_downs_entries = kbtrans_downs_size;
upper->kbtrans_streams_downs_bytes =
- (uint32_t)(kbtrans_downs_size * sizeof (Key_event));
+ (uint32_t)(kbtrans_downs_size * sizeof (Key_event));
upper->kbtrans_streams_downs =
- kmem_zalloc(upper->kbtrans_streams_downs_bytes, KM_SLEEP);
+ kmem_zalloc(upper->kbtrans_streams_downs_bytes, KM_SLEEP);
upper->kbtrans_streams_abortable = B_FALSE;
upper->kbtrans_streams_flags = KBTRANS_STREAMS_OPEN;
DPRINTF(PRINT_L1, PRINT_MASK_OPEN, (upper, "kbtrans_streams_init "
- "exiting"));
+ "exiting"));
return (0);
}
@@ -338,18 +338,18 @@ kbtrans_streams_fini(struct kbtrans *upper)
/* clear all timeouts */
if (upper->kbtrans_streams_bufcallid) {
qunbufcall(upper->kbtrans_streams_readq,
- upper->kbtrans_streams_bufcallid);
+ upper->kbtrans_streams_bufcallid);
}
if (upper->kbtrans_streams_rptid) {
(void) quntimeout(upper->kbtrans_streams_readq,
- upper->kbtrans_streams_rptid);
+ upper->kbtrans_streams_rptid);
}
kmem_free(upper->kbtrans_streams_downs,
- upper->kbtrans_streams_downs_bytes);
+ upper->kbtrans_streams_downs_bytes);
kmem_free(upper, sizeof (struct kbtrans));
DPRINTF(PRINT_L1, PRINT_MASK_CLOSE, (upper, "kbtrans_streams_fini "
- "exiting"));
+ "exiting"));
return (0);
}
@@ -396,7 +396,7 @@ kbtrans_streams_message(struct kbtrans *upper, register mblk_t *mp)
enum kbtrans_message_response ret;
DPRINTF(PRINT_L1, PRINT_MASK_ALL, (upper,
- "kbtrans_streams_message entering"));
+ "kbtrans_streams_message entering"));
/*
* Process M_FLUSH, and some M_IOCTL, messages here; pass
* everything else down.
@@ -425,7 +425,7 @@ kbtrans_streams_message(struct kbtrans *upper, register mblk_t *mp)
}
DPRINTF(PRINT_L1, PRINT_MASK_ALL, (upper,
- "kbtrans_streams_message exiting\n"));
+ "kbtrans_streams_message exiting\n"));
return (ret);
}
@@ -459,7 +459,7 @@ kbtrans_streams_key(
if (key == (kbtrans_key_t)kp->k_abort1 ||
key == (kbtrans_key_t)kp->k_abort1a) {
upper->kbtrans_streams_abort_state =
- ABORT_ABORT1_RECEIVED;
+ ABORT_ABORT1_RECEIVED;
upper->kbtrans_streams_abort1_key = key;
return;
}
@@ -467,7 +467,7 @@ kbtrans_streams_key(
if (key == (kbtrans_key_t)kp->k_newabort1 ||
key == (kbtrans_key_t)kp->k_newabort1a) {
upper->kbtrans_streams_abort_state =
- NEW_ABORT_ABORT1_RECEIVED;
+ NEW_ABORT_ABORT1_RECEIVED;
upper->kbtrans_streams_new_abort1_key = key;
}
break;
@@ -479,9 +479,9 @@ kbtrans_streams_key(
return;
} else {
kbtrans_processkey(lower,
- upper->kbtrans_streams_callback,
- upper->kbtrans_streams_abort1_key,
- KEY_PRESSED);
+ upper->kbtrans_streams_callback,
+ upper->kbtrans_streams_abort1_key,
+ KEY_PRESSED);
}
break;
case NEW_ABORT_ABORT1_RECEIVED:
@@ -490,9 +490,9 @@ kbtrans_streams_key(
key == (kbtrans_key_t)kp->k_newabort2) {
abort_sequence_enter((char *)NULL);
kbtrans_processkey(lower,
- upper->kbtrans_streams_callback,
- upper->kbtrans_streams_new_abort1_key,
- KEY_RELEASED);
+ upper->kbtrans_streams_callback,
+ upper->kbtrans_streams_new_abort1_key,
+ KEY_RELEASED);
return;
}
}
@@ -605,12 +605,12 @@ kbtrans_streams_untimeout(struct kbtrans *upper)
/* clear all timeouts */
if (upper->kbtrans_streams_bufcallid) {
qunbufcall(upper->kbtrans_streams_readq,
- upper->kbtrans_streams_bufcallid);
+ upper->kbtrans_streams_bufcallid);
upper->kbtrans_streams_bufcallid = 0;
}
if (upper->kbtrans_streams_rptid) {
(void) quntimeout(upper->kbtrans_streams_readq,
- upper->kbtrans_streams_rptid);
+ upper->kbtrans_streams_rptid);
upper->kbtrans_streams_rptid = 0;
}
}
@@ -659,7 +659,7 @@ kbtrans_ioctl(struct kbtrans *upper, register mblk_t *mp)
iocp = (struct iocblk *)mp->b_rptr;
DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper,
- "kbtrans_ioctl: ioc_cmd 0x%x - ", iocp->ioc_cmd));
+ "kbtrans_ioctl: ioc_cmd 0x%x - ", iocp->ioc_cmd));
switch (iocp->ioc_cmd) {
case VUIDSFORMAT:
@@ -729,7 +729,7 @@ kbtrans_ioctl(struct kbtrans *upper, register mblk_t *mp)
*(int *)datap->b_wptr =
(upper->kbtrans_streams_translate_mode == TR_EVENT ||
upper->kbtrans_streams_translate_mode == TR_UNTRANS_EVENT) ?
- VUID_FIRM_EVENT: VUID_NATIVE;
+ VUID_FIRM_EVENT: VUID_NATIVE;
datap->b_wptr += sizeof (int);
if (mp->b_cont) /* free msg to prevent memory leak */
freemsg(mp->b_cont);
@@ -793,17 +793,17 @@ kbtrans_ioctl(struct kbtrans *upper, register mblk_t *mp)
case ASCII_FIRST:
addr_probe->data.current =
- upper->kbtrans_streams_vuid_addr.ascii;
+ upper->kbtrans_streams_vuid_addr.ascii;
break;
case TOP_FIRST:
addr_probe->data.current =
- upper->kbtrans_streams_vuid_addr.top;
+ upper->kbtrans_streams_vuid_addr.top;
break;
case VKEY_FIRST:
addr_probe->data.current =
- upper->kbtrans_streams_vuid_addr.vkey;
+ upper->kbtrans_streams_vuid_addr.vkey;
break;
default:
@@ -870,7 +870,7 @@ kbtrans_ioctl(struct kbtrans *upper, register mblk_t *mp)
case KIOCSETKEY:
DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSETKEY %d\n",
- kiocsetkey++));
+ kiocsetkey++));
err = miocpullup(mp, sizeof (struct kiockey));
if (err != 0)
break;
@@ -885,7 +885,7 @@ kbtrans_ioctl(struct kbtrans *upper, register mblk_t *mp)
case KIOCGETKEY:
DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGETKEY %d\n",
- kiocgetkey++));
+ kiocgetkey++));
err = miocpullup(mp, sizeof (struct kiockey));
if (err != 0)
break;
@@ -1073,11 +1073,11 @@ allocfailure:
upper->kbtrans_streams_iocpending = mp;
if (upper->kbtrans_streams_bufcallid) {
qunbufcall(upper->kbtrans_streams_readq,
- upper->kbtrans_streams_bufcallid);
+ upper->kbtrans_streams_bufcallid);
}
upper->kbtrans_streams_bufcallid =
- qbufcall(upper->kbtrans_streams_readq, ioctlrespsize, BPRI_HI,
- kbtrans_reioctl, upper);
+ qbufcall(upper->kbtrans_streams_readq, ioctlrespsize, BPRI_HI,
+ kbtrans_reioctl, upper);
/*
* This is a white lie... we *will* handle it, eventually.
*/
@@ -1111,8 +1111,8 @@ static void
kbtrans_setled(struct kbtrans *upper)
{
upper->kbtrans_streams_hw_callbacks->kbtrans_streams_setled(
- upper->kbtrans_streams_hw,
- upper->kbtrans_lower.kbtrans_led_state);
+ upper->kbtrans_streams_hw,
+ upper->kbtrans_lower.kbtrans_led_state);
}
/*
@@ -1127,8 +1127,8 @@ kbtrans_rpt(void *arg)
struct kbtrans_lower *lower = &upper->kbtrans_lower;
DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL,
- "kbtrans_rpt: repeat key %X\n",
- lower->kbtrans_repeatkey));
+ "kbtrans_rpt: repeat key %X\n",
+ lower->kbtrans_repeatkey));
upper->kbtrans_streams_rptid = 0;
@@ -1140,13 +1140,13 @@ kbtrans_rpt(void *arg)
kbtrans_keyreleased(upper, lower->kbtrans_repeatkey);
kbtrans_processkey(lower,
- upper->kbtrans_streams_callback,
- lower->kbtrans_repeatkey,
- KEY_PRESSED);
+ upper->kbtrans_streams_callback,
+ lower->kbtrans_repeatkey,
+ KEY_PRESSED);
upper->kbtrans_streams_rptid =
- qtimeout(upper->kbtrans_streams_readq, kbtrans_rpt,
- (caddr_t)upper, kbtrans_repeat_rate);
+ qtimeout(upper->kbtrans_streams_readq, kbtrans_rpt,
+ (caddr_t)upper, kbtrans_repeat_rate);
}
}
@@ -1161,7 +1161,7 @@ kbtrans_cancelrpt(struct kbtrans *upper)
if (upper->kbtrans_streams_rptid != 0) {
(void) quntimeout(upper->kbtrans_streams_readq,
- upper->kbtrans_streams_rptid);
+ upper->kbtrans_streams_rptid);
upper->kbtrans_streams_rptid = 0;
}
}
@@ -1236,7 +1236,7 @@ kbtrans_keypressed(struct kbtrans *upper, uchar_t key_station,
unsigned int mask;
mask = lower->kbtrans_shiftmask &
- ~(CTRLMASK | CTLSMASK | UPMASK);
+ ~(CTRLMASK | CTLSMASK | UPMASK);
ke = kbtrans_find_entry(lower, mask, key_station);
if (ke == NULL)
@@ -1287,7 +1287,7 @@ kbtrans_queuepress(struct kbtrans *upper,
register int i;
DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "kbtrans_queuepress:"
- " key=%d", key_station));
+ " key=%d", key_station));
ke_free = 0;
@@ -1300,9 +1300,9 @@ kbtrans_queuepress(struct kbtrans *upper,
if (ke->key_station == key_station) {
DPRINTF(PRINT_L0, PRINT_MASK_ALL,
- (NULL, "kbtrans: Double "
- "entry in downs table (%d,%d)!\n",
- key_station, i));
+ (NULL, "kbtrans: Double "
+ "entry in downs table (%d,%d)!\n",
+ key_station, i));
goto add_event;
}
@@ -1335,7 +1335,7 @@ kbtrans_keyreleased(register struct kbtrans *upper, uchar_t key_station)
register int i;
DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "RELEASE key=%d\n",
- key_station));
+ key_station));
if (upper->kbtrans_streams_translate_mode != TR_EVENT &&
upper->kbtrans_streams_translate_mode != TR_UNTRANS_EVENT) {
@@ -1446,7 +1446,7 @@ kbtrans_queueevent(struct kbtrans *upper, Firm_event *fe)
if (!canputnext(q)) {
if (kbtrans_overflow_msg) {
DPRINTF(PRINT_L2, PRINT_MASK_ALL, (NULL,
- "kbtrans: Buffer flushed when overflowed."));
+ "kbtrans: Buffer flushed when overflowed."));
}
kbtrans_flush(upper);
@@ -1457,7 +1457,7 @@ kbtrans_queueevent(struct kbtrans *upper, Firm_event *fe)
block for event.");
} else {
uniqtime32(&fe->time);
- *(Firm_event *)bp->b_wptr = *fe;
+ *(Firm_event *)bp->b_wptr = *fe;
bp->b_wptr += sizeof (Firm_event);
(void) putnext(q, bp);
@@ -1478,6 +1478,14 @@ kbtrans_set_translation_callback(register struct kbtrans *upper)
default:
case TR_ASCII:
+ upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
+
+ /* Discard any obsolete CTRL/ALT/SHIFT keys */
+ upper->kbtrans_lower.kbtrans_shiftmask &=
+ ~(CTRLMASK | ALTMASK | SHIFTMASK);
+ upper->kbtrans_lower.kbtrans_togglemask &=
+ ~(CTRLMASK | ALTMASK | SHIFTMASK);
+
upper->kbtrans_streams_callback = &ascii_callback;
break;
@@ -1535,6 +1543,75 @@ kbtrans_untrans_keyreleased_raw(struct kbtrans *upper, kbtrans_key_t key)
}
/*
+ * kbtrans_vt_compose:
+ * To compose the key sequences for virtual terminal switching.
+ *
+ * 'ALTL + F#' for 1-12 terminals
+ * 'ALTGR + F#' for 13-24 terminals
+ * 'ALT + UPARROW' for last terminal
+ * 'ALT + LEFTARROW' for previous terminal
+ * 'ALT + RIGHTARROW' for next terminal
+ *
+ * the vt switching message is encoded as:
+ *
+ * -------------------------------------------------------------
+ * | \033 | 'Q' | vtno + 'A' | opcode | 'z' | '\0' |
+ * -------------------------------------------------------------
+ *
+ * opcode:
+ * 'B' to switch to previous terminal
+ * 'F' to switch to next terminal
+ * 'L' to switch to last terminal
+ * 'H' to switch to the terminal as specified by vtno,
+ * which is from 1 to 24.
+ *
+ * Here keyid is the keycode of UPARROW, LEFTARROW, or RIGHTARROW
+ * when it is a kind of arrow key as indicated by is_arrow_key,
+ * otherwise it indicates a function key and keyid is the number
+ * corresponding to that function key.
+ */
+static void
+kbtrans_vt_compose(struct kbtrans *upper, unsigned short keyid,
+ boolean_t is_arrow_key, char *buf)
+{
+ char *bufp;
+
+ bufp = buf;
+ *bufp++ = '\033'; /* Escape */
+ *bufp++ = 'Q';
+ if (is_arrow_key) {
+ *bufp++ = 'A';
+ switch (keyid) {
+ case UPARROW: /* last vt */
+ *bufp++ = 'L';
+ break;
+ case LEFTARROW: /* previous vt */
+ *bufp++ = 'B';
+ break;
+ case RIGHTARROW: /* next vt */
+ *bufp++ = 'F';
+ break;
+ default:
+ break;
+ }
+ } else {
+ /* this is funckey specifying vtno for switch */
+ *bufp++ = keyid +
+ (upper->vt_switch_keystate - VT_SWITCH_KEY_ALT) *
+ KB_NR_FUNCKEYS + 'A';
+ *bufp++ = 'H';
+ }
+ *bufp++ = 'z';
+ *bufp = '\0';
+
+ /*
+ * Send the result upstream.
+ */
+ kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
+
+}
+
+/*
* kbtrans_ascii_keypressed:
* This is the code if we are in TR_ASCII mode and a key
* is pressed. This is where we will do any special processing that
@@ -1551,16 +1628,29 @@ kbtrans_ascii_keypressed(
register char *cp;
register char *bufp;
char buf[14];
+ unsigned short keyid;
struct kbtrans_lower *lower = &upper->kbtrans_lower;
/*
* Based on the type of key, we may need to do some ASCII
- * specific post processing.
+ * specific post processing. Note that the translated entry
+ * is constructed as the actual keycode plus entrytype. see
+ * sys/kbd.h for details of each entrytype.
*/
switch (entrytype) {
case BUCKYBITS:
+ return;
+
case SHIFTKEYS:
+ keyid = entry & 0xFF;
+ if (keyid == ALT) {
+ upper->vt_switch_keystate = VT_SWITCH_KEY_ALT;
+ } else if (keyid == ALTGRAPH) {
+ upper->vt_switch_keystate = VT_SWITCH_KEY_ALTGR;
+ }
+ return;
+
case FUNNY:
/*
* There is no ascii equivalent. We will ignore these
@@ -1569,14 +1659,29 @@ kbtrans_ascii_keypressed(
return;
case FUNCKEYS:
+ if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
+ if (entry >= TOPFUNC &&
+ entry < (TOPFUNC + KB_NR_FUNCKEYS)) {
+
+ /*
+ * keyid is the number correspoding to F#
+ * and its value is from 1 to 12.
+ */
+ keyid = (entry & 0xF) + 1;
+
+ kbtrans_vt_compose(upper, keyid, B_FALSE, buf);
+ return;
+ }
+ }
+
/*
* We need to expand this key to get the ascii
* equivalent. These are the function keys (F1, F2 ...)
*/
bufp = buf;
cp = kbtrans_strsetwithdecimal(bufp + 2,
- (uint_t)((entry & 0x003F) + 192),
- sizeof (buf) - 5);
+ (uint_t)((entry & 0x003F) + 192),
+ sizeof (buf) - 5);
*bufp++ = '\033'; /* Escape */
*bufp++ = '[';
while (*cp != '\0')
@@ -1592,6 +1697,17 @@ kbtrans_ascii_keypressed(
return;
case STRING:
+ if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
+ keyid = entry & 0xFF;
+ if (keyid == UPARROW ||
+ keyid == RIGHTARROW ||
+ keyid == LEFTARROW) {
+
+ kbtrans_vt_compose(upper, keyid, B_TRUE, buf);
+ return;
+ }
+ }
+
/*
* These are the multi byte keys (Home, Up, Down ...)
*/
@@ -1616,7 +1732,7 @@ kbtrans_ascii_keypressed(
* answer in the kb_numlock_table and send it upstream.
*/
kbtrans_putcode(upper,
- lower->kbtrans_numlock_table[entry&0x1F]);
+ lower->kbtrans_numlock_table[entry&0x1F]);
return;
@@ -1632,17 +1748,24 @@ kbtrans_ascii_keypressed(
}
+#define KB_SCANCODE_ALT 0xe2
+#define KB_SCANCODE_ALTGRAPH 0xe6
+
/*
* kbtrans_ascii_keyreleased:
* This is the function if we are in TR_ASCII mode and a key
* is released. ASCII doesn't have the concept of released keys,
- * or make/break codes. So there is nothing for us to do.
+ * or make/break codes. So there is nothing for us to do except
+ * checking 'Alt/AltGraph' release key in order to reset the state
+ * of vt switch key sequence.
*/
/* ARGSUSED */
static void
kbtrans_ascii_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
{
- /* Nothing to do ... for now */
+ if (key == KB_SCANCODE_ALT || key == KB_SCANCODE_ALTGRAPH) {
+ upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
+ }
}
/*
@@ -1675,7 +1798,7 @@ kbtrans_ascii_setup_repeat(
* be called to repeat the key.
*/
upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
- kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
+ kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
}
/*
@@ -1890,7 +2013,7 @@ kbtrans_trans_event_setup_repeat(
* be called to repeat the key.
*/
upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
- kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
+ kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
}
/*
@@ -1990,7 +2113,7 @@ kbtrans_setkey(struct kbtrans_lower *lower, struct kiockey *key, cred_t *cr)
key->kio_entry <= (uchar_t)(OLD_STRING + 15)) {
strtabindex = key->kio_entry - OLD_STRING;
bcopy(key->kio_string,
- lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
+ lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
}
@@ -2064,7 +2187,7 @@ kbtrans_getkey(struct kbtrans_lower *lower, struct kiockey *key)
}
ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
- key->kio_station);
+ key->kio_station);
if (ke == NULL)
return (EINVAL);
@@ -2084,7 +2207,7 @@ kbtrans_getkey(struct kbtrans_lower *lower, struct kiockey *key)
if (entry >= STRING && entry <= (uchar_t)(STRING + 15)) {
strtabindex = entry - STRING;
bcopy(lower->kbtrans_keystringtab[strtabindex],
- key->kio_string, KTAB_STRLEN);
+ key->kio_string, KTAB_STRLEN);
}
return (0);
}
@@ -2134,7 +2257,7 @@ kbtrans_skey(struct kbtrans_lower *lower, struct kiockeymap *key, cred_t *cr)
}
ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
- key->kio_station);
+ key->kio_station);
if (ke == NULL)
return (EINVAL);
@@ -2142,7 +2265,7 @@ kbtrans_skey(struct kbtrans_lower *lower, struct kiockeymap *key, cred_t *cr)
key->kio_entry <= (ushort_t)(STRING + 15)) {
strtabindex = key->kio_entry-STRING;
bcopy(key->kio_string,
- lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
+ lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
}
@@ -2184,7 +2307,7 @@ kbtrans_gkey(struct kbtrans_lower *lower, struct kiockeymap *key)
}
ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
- key->kio_station);
+ key->kio_station);
if (ke == NULL)
return (EINVAL);
@@ -2194,7 +2317,7 @@ kbtrans_gkey(struct kbtrans_lower *lower, struct kiockeymap *key)
key->kio_entry <= (ushort_t)(STRING + 15)) {
strtabindex = key->kio_entry-STRING;
bcopy(lower->kbtrans_keystringtab[strtabindex],
- key->kio_string, KTAB_STRLEN);
+ key->kio_string, KTAB_STRLEN);
}
return (0);
}
diff --git a/usr/src/uts/common/io/kbtrans/kbtrans_streams.h b/usr/src/uts/common/io/kbtrans/kbtrans_streams.h
index 68f23580d5..d6870e0864 100644
--- a/usr/src/uts/common/io/kbtrans/kbtrans_streams.h
+++ b/usr/src/uts/common/io/kbtrans/kbtrans_streams.h
@@ -18,16 +18,15 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _KBTRANS_STREAMS_H
#define _KBTRANS_STREAMS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -132,6 +131,13 @@ struct kbtrans {
/* Buffers to hold characters during the polled mode */
char *kbtrans_polled_pending_chars;
char kbtrans_polled_buf[KBTRANS_POLLED_BUF_SIZE+1];
+
+ /* vt switch key sequence state */
+ enum {
+ VT_SWITCH_KEY_NONE = 0,
+ VT_SWITCH_KEY_ALT, /* left Alt key is pressed */
+ VT_SWITCH_KEY_ALTGR /* right Alt key is pressed */
+ } vt_switch_keystate;
};
#ifdef __cplusplus
diff --git a/usr/src/uts/common/io/tem.c b/usr/src/uts/common/io/tem.c
index 3cc0df18c3..33e42fd982 100644
--- a/usr/src/uts/common/io/tem.c
+++ b/usr/src/uts/common/io/tem.c
@@ -27,8 +27,39 @@
/*
* ANSI terminal emulator module; parse ANSI X3.64 escape sequences and
* the like.
+ *
+ * How Virtual Terminal Emulator Works:
+ *
+ * Every virtual terminal is associated with a tem_vt_state structure
+ * and maintains a virtual screen buffer in tvs_screen_buf, which contains
+ * all the characters which should be shown on the physical screen when
+ * the terminal is activated. There are also two other buffers, tvs_fg_buf
+ * and tvs_bg_buf, which track the foreground and background colors of the
+ * on screen characters
+ *
+ * Data written to a virtual terminal is composed of characters which
+ * should be displayed on the screen when this virtual terminal is
+ * activated, fg/bg colors of these characters, and other control
+ * information (escape sequence, etc).
+ *
+ * When data is passed to a virtual terminal it first is parsed for
+ * control information by tem_safe_parse(). Subsequently the character
+ * and color data are written to tvs_screen_buf, tvs_fg_buf, and
+ * tvs_bg_buf. They are saved in these buffers in order to refresh
+ * the screen when this terminal is activated. If the terminal is
+ * currently active, the data (characters and colors) are also written
+ * to the physical screen by invoking a callback function,
+ * tem_safe_text_callbacks() or tem_safe_pix_callbacks().
+ *
+ * When rendering data to the framebuffer, if the framebuffer is in
+ * VIS_PIXEL mode, the character data will first be converted to pixel
+ * data using tem_safe_pix_bit2pix(), and then the pixels get displayed
+ * on the physical screen. We only store the character and color data in
+ * tem_vt_state since the bit2pix conversion only happens when actually
+ * rendering to the physical framebuffer.
*/
+
#include <sys/types.h>
#include <sys/file.h>
#include <sys/conf.h>
@@ -54,26 +85,33 @@
#include <sys/sunddi.h>
#include <sys/sunldi.h>
#include <sys/tem_impl.h>
-#include <sys/tem.h>
#ifdef _HAVE_TEM_FIRMWARE
#include <sys/promif.h>
#endif /* _HAVE_TEM_FIRMWARE */
#include <sys/consplat.h>
+#include <sys/kd.h>
+#include <sys/sysmacros.h>
+#include <sys/note.h>
+#include <sys/t_lock.h>
+
+/* Terminal emulator internal helper functions */
+static void tems_setup_terminal(struct vis_devinit *, size_t, size_t);
+static void tems_modechange_callback(struct vis_modechg_arg *,
+ struct vis_devinit *);
-/* Terminal emulator functions */
-static int tem_setup_terminal(struct vis_devinit *, tem_t *,
- size_t, size_t);
-static void tem_modechange_callback(tem_t *, struct vis_devinit *);
-static void tem_free(tem_t *);
-static void tem_get_inverses(boolean_t *, boolean_t *);
-static void tem_get_initial_color(tem_t *);
-static int tem_adjust_row(tem_t *, int, cred_t *);
+static void tems_reset_colormap(cred_t *, enum called_from);
+
+static void tem_free_buf(struct tem_vt_state *);
+static void tem_internal_init(struct tem_vt_state *, cred_t *, boolean_t,
+ boolean_t);
+static void tems_get_initial_color(tem_color_t *pcolor);
/*
* Globals
*/
-ldi_ident_t term_li = NULL;
-
+static ldi_ident_t term_li = NULL;
+tem_state_t tems; /* common term info */
+_NOTE(MUTEX_PROTECTS_DATA(tems.ts_lock, tems))
extern struct mod_ops mod_miscops;
@@ -98,6 +136,12 @@ _init(void)
(void) mod_remove(&modlinkage);
return (ret);
}
+
+ mutex_init(&tems.ts_lock, (char *)NULL, MUTEX_DRIVER, NULL);
+ list_create(&tems.ts_list, sizeof (struct tem_vt_state),
+ offsetof(struct tem_vt_state, tvs_list_node));
+ tems.ts_active = NULL;
+
return (0);
}
@@ -120,114 +164,238 @@ _info(struct modinfo *modinfop)
return (mod_info(&modlinkage, modinfop));
}
-int
-tem_fini(tem_t *tem)
+static void
+tem_add(struct tem_vt_state *tem)
{
- int lyr_rval;
+ ASSERT(MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock));
- mutex_enter(&tem->lock);
+ list_insert_head(&tems.ts_list, tem);
+}
- ASSERT(tem->hdl != NULL);
+static void
+tem_rm(struct tem_vt_state *tem)
+{
+ ASSERT(MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock));
- /*
- * Allow layered on driver to clean up console private
- * data.
- */
- (void) ldi_ioctl(tem->hdl, VIS_DEVFINI,
- 0, FKIOCTL, kcred, &lyr_rval);
+ list_remove(&tems.ts_list, tem);
+}
- /*
- * Close layered on driver
- */
- (void) ldi_close(tem->hdl, NULL, kcred);
- tem->hdl = NULL;
+/*
+ * This is the main entry point to the module. It handles output requests
+ * during normal system operation, when (e.g.) mutexes are available.
+ */
+void
+tem_write(tem_vt_state_t tem_arg, uchar_t *buf, ssize_t len, cred_t *credp)
+{
+ struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
- mutex_exit(&tem->lock);
+ mutex_enter(&tems.ts_lock);
+ mutex_enter(&tem->tvs_lock);
- tem_free(tem);
+ if (!tem->tvs_initialized) {
+ mutex_exit(&tem->tvs_lock);
+ mutex_exit(&tems.ts_lock);
+ return;
+ }
- return (0);
+ tem_safe_check_first_time(tem, credp, CALLED_FROM_NORMAL);
+ tem_safe_terminal_emulate(tem, buf, len, credp, CALLED_FROM_NORMAL);
+
+ mutex_exit(&tem->tvs_lock);
+ mutex_exit(&tems.ts_lock);
}
-static int
-tem_init_failed(tem_t *tem, cred_t *credp, boolean_t finish_ioctl)
+static void
+tem_internal_init(struct tem_vt_state *ptem, cred_t *credp,
+ boolean_t init_color, boolean_t clear_screen)
{
- int lyr_rval;
+ int i, j;
+ int width, height;
+ int total;
+ text_color_t fg;
+ text_color_t bg;
+ size_t tc_size = sizeof (text_color_t);
+
+ ASSERT(MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&ptem->tvs_lock));
+
+ if (tems.ts_display_mode == VIS_PIXEL) {
+ ptem->tvs_pix_data_size = tems.ts_pix_data_size;
+ ptem->tvs_pix_data =
+ kmem_alloc(ptem->tvs_pix_data_size, KM_SLEEP);
+ }
- if (finish_ioctl)
- (void) ldi_ioctl(tem->hdl, VIS_DEVFINI, 0, FWRITE|FKIOCTL,
- credp, &lyr_rval);
+ ptem->tvs_outbuf_size = tems.ts_c_dimension.width;
+ ptem->tvs_outbuf =
+ (unsigned char *)kmem_alloc(ptem->tvs_outbuf_size, KM_SLEEP);
- (void) ldi_close(tem->hdl, NULL, credp);
- tem_free(tem);
- return (ENXIO);
+ width = tems.ts_c_dimension.width;
+ height = tems.ts_c_dimension.height;
+ ptem->tvs_screen_buf_size = width * height;
+ ptem->tvs_screen_buf =
+ (unsigned char *)kmem_alloc(width * height, KM_SLEEP);
+
+ total = width * height * tc_size;
+ ptem->tvs_fg_buf = (text_color_t *)kmem_alloc(total, KM_SLEEP);
+ ptem->tvs_bg_buf = (text_color_t *)kmem_alloc(total, KM_SLEEP);
+ ptem->tvs_color_buf_size = total;
+
+ tem_safe_reset_display(ptem, credp, CALLED_FROM_NORMAL,
+ clear_screen, init_color);
+
+ tem_safe_get_color(ptem, &fg, &bg, TEM_ATTR_SCREEN_REVERSE);
+ for (i = 0; i < height; i++)
+ for (j = 0; j < width; j++) {
+ ptem->tvs_screen_buf[i * width + j] = ' ';
+ ptem->tvs_fg_buf[(i * width +j) * tc_size] = fg;
+ ptem->tvs_bg_buf[(i * width +j) * tc_size] = bg;
+
+ }
+
+ ptem->tvs_initialized = 1;
}
-static void
-tem_free_state(struct tem_state *tems)
+int
+tem_initialized(tem_vt_state_t tem_arg)
{
- ASSERT(tems != NULL);
+ struct tem_vt_state *ptem = (struct tem_vt_state *)tem_arg;
+ int ret;
+
+ mutex_enter(&ptem->tvs_lock);
+ ret = ptem->tvs_initialized;
+ mutex_exit(&ptem->tvs_lock);
- if (tems->a_outbuf != NULL)
- kmem_free(tems->a_outbuf,
- tems->a_c_dimension.width);
- if (tems->a_blank_line != NULL)
- kmem_free(tems->a_blank_line,
- tems->a_c_dimension.width);
- if (tems->a_pix_data != NULL)
- kmem_free(tems->a_pix_data,
- tems->a_pix_data_size);
- kmem_free(tems, sizeof (struct tem_state));
+ return (ret);
}
-static void
-tem_free(tem_t *tem)
+tem_vt_state_t
+tem_init(cred_t *credp)
{
- ASSERT(tem != NULL);
+ struct tem_vt_state *ptem;
+
+ ptem = kmem_zalloc(sizeof (struct tem_vt_state), KM_SLEEP);
+ mutex_init(&ptem->tvs_lock, (char *)NULL, MUTEX_DRIVER, NULL);
+
+ mutex_enter(&tems.ts_lock);
+ mutex_enter(&ptem->tvs_lock);
+
+ ptem->tvs_isactive = B_FALSE;
+ ptem->tvs_fbmode = KD_TEXT;
+
+ /*
+ * A tem is regarded as initialized only after tem_internal_init(),
+ * will be set at the end of tem_internal_init().
+ */
+ ptem->tvs_initialized = 0;
+
- if (tem->state != NULL)
- tem_free_state(tem->state);
+ if (!tems.ts_initialized) {
+ /*
+ * Only happens during early console configuration.
+ */
+ tem_add(ptem);
+ mutex_exit(&ptem->tvs_lock);
+ mutex_exit(&tems.ts_lock);
+ return ((tem_vt_state_t)ptem);
+ }
- kmem_free(tem, sizeof (struct tem));
+ tem_internal_init(ptem, credp, B_TRUE, B_FALSE);
+ tem_add(ptem);
+ mutex_exit(&ptem->tvs_lock);
+ mutex_exit(&tems.ts_lock);
+
+ return ((tem_vt_state_t)ptem);
}
/*
- * This is the main entry point to the module. It handles output requests
- * during normal system operation, when (e.g.) mutexes are available.
+ * re-init the tem after video mode has changed and tems_info has
+ * been re-inited. The lock is already held.
*/
+static void
+tem_reinit(struct tem_vt_state *tem, boolean_t reset_display)
+{
+ ASSERT(MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock));
+
+ tem_free_buf(tem); /* only free virtual buffers */
+
+ /* reserve color */
+ tem_internal_init(tem, kcred, B_FALSE, reset_display);
+}
+
+static void
+tem_free_buf(struct tem_vt_state *tem)
+{
+ ASSERT(tem != NULL && MUTEX_HELD(&tem->tvs_lock));
+
+ if (tem->tvs_outbuf != NULL)
+ kmem_free(tem->tvs_outbuf, tem->tvs_outbuf_size);
+ if (tem->tvs_pix_data != NULL)
+ kmem_free(tem->tvs_pix_data, tem->tvs_pix_data_size);
+ if (tem->tvs_screen_buf != NULL)
+ kmem_free(tem->tvs_screen_buf, tem->tvs_screen_buf_size);
+ if (tem->tvs_fg_buf != NULL)
+ kmem_free(tem->tvs_fg_buf, tem->tvs_color_buf_size);
+ if (tem->tvs_bg_buf != NULL)
+ kmem_free(tem->tvs_bg_buf, tem->tvs_color_buf_size);
+}
+
void
-tem_write(tem_t *tem, uchar_t *buf, ssize_t len, cred_t *credp)
+tem_destroy(tem_vt_state_t tem_arg, cred_t *credp)
{
- mutex_enter(&tem->lock);
+ struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
- ASSERT(tem->hdl != NULL);
+ mutex_enter(&tems.ts_lock);
+ mutex_enter(&tem->tvs_lock);
- tem_check_first_time(tem, credp, CALLED_FROM_NORMAL);
- tem_terminal_emulate(tem, buf, len, credp, CALLED_FROM_NORMAL);
+ if (tem->tvs_isactive && tem->tvs_fbmode == KD_TEXT)
+ tem_safe_blank_screen(tem, credp, CALLED_FROM_NORMAL);
- mutex_exit(&tem->lock);
+ tem_free_buf(tem);
+ tem_rm(tem);
+
+ if (tems.ts_active == tem)
+ tems.ts_active = NULL;
+
+ mutex_exit(&tem->tvs_lock);
+ mutex_exit(&tems.ts_lock);
+
+ kmem_free(tem, sizeof (struct tem_vt_state));
+}
+
+static int
+tems_failed(cred_t *credp, boolean_t finish_ioctl)
+{
+ int lyr_rval;
+
+ ASSERT(MUTEX_HELD(&tems.ts_lock));
+
+ if (finish_ioctl)
+ (void) ldi_ioctl(tems.ts_hdl, VIS_DEVFINI, 0,
+ FWRITE|FKIOCTL, credp, &lyr_rval);
+
+ (void) ldi_close(tems.ts_hdl, NULL, credp);
+ tems.ts_hdl = NULL;
+ return (ENXIO);
}
+/*
+ * only called once during boot
+ */
int
-tem_init(tem_t **ptem, char *pathname, cred_t *credp)
+tem_info_init(char *pathname, cred_t *credp)
{
- struct vis_devinit devinit;
- tem_t *tem;
+ int lyr_rval, ret;
+ struct vis_devinit temargs;
+ char *pathbuf;
size_t height = 0;
size_t width = 0;
- uint32_t row = 0;
- uint32_t col = 0;
- char *pathbuf;
- int err = 0;
- int lyr_rval;
+ struct tem_vt_state *p;
- tem = kmem_zalloc(sizeof (struct tem), KM_SLEEP);
+ mutex_enter(&tems.ts_lock);
- mutex_init(&tem->lock, (char *)NULL, MUTEX_DRIVER, NULL);
-
-#ifdef _HAVE_TEM_FIRMWARE
- tem->cons_wrtvec = tem_write;
-#endif /* _HAVE_TEM_FIRMWARE */
+ if (tems.ts_initialized) {
+ mutex_exit(&tems.ts_lock);
+ return (0);
+ }
/*
* Open the layered device using the devfs physical device name
@@ -237,220 +405,143 @@ tem_init(tem_t **ptem, char *pathname, cred_t *credp)
(void) strcpy(pathbuf, "/devices");
if (i_ddi_prompath_to_devfspath(pathname,
pathbuf + strlen("/devices")) != DDI_SUCCESS) {
- cmn_err(CE_WARN, "terminal emulator: Path conversion error");
+ cmn_err(CE_WARN, "terminal-emulator: path conversion error");
kmem_free(pathbuf, MAXPATHLEN);
- tem_free(tem);
+
+ mutex_exit(&tems.ts_lock);
return (ENXIO);
}
- if (ldi_open_by_name(pathbuf, FWRITE, credp, &tem->hdl, term_li) != 0) {
- cmn_err(CE_WARN, "terminal emulator: Device path open error");
+ if (ldi_open_by_name(pathbuf, FWRITE, credp,
+ &tems.ts_hdl, term_li) != 0) {
+ cmn_err(CE_WARN, "terminal-emulator: device path open error");
kmem_free(pathbuf, MAXPATHLEN);
- tem_free(tem);
+
+ mutex_exit(&tems.ts_lock);
return (ENXIO);
}
kmem_free(pathbuf, MAXPATHLEN);
- devinit.modechg_cb = (vis_modechg_cb_t)tem_modechange_callback;
- devinit.modechg_arg = (struct vis_modechg_arg *)tem;
+ temargs.modechg_cb = (vis_modechg_cb_t)tems_modechange_callback;
+ temargs.modechg_arg = NULL;
/*
* Initialize the console and get the device parameters
*/
- if ((err = ldi_ioctl(tem->hdl, VIS_DEVINIT,
- (intptr_t)&devinit, FWRITE|FKIOCTL, credp, &lyr_rval)) != 0) {
+ if (ldi_ioctl(tems.ts_hdl, VIS_DEVINIT,
+ (intptr_t)&temargs, FWRITE|FKIOCTL, credp, &lyr_rval) != 0) {
cmn_err(CE_WARN, "terminal emulator: Compatible fb not found");
- return (tem_init_failed(tem, credp, B_FALSE));
+ ret = tems_failed(credp, B_FALSE);
+ mutex_exit(&tems.ts_lock);
+ return (ret);
}
/* Make sure the fb driver and terminal emulator versions match */
- if (devinit.version != VIS_CONS_REV) {
+ if (temargs.version != VIS_CONS_REV) {
cmn_err(CE_WARN,
"terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) "
- "of console fb driver not supported", devinit.version);
- return (tem_init_failed(tem, credp, B_TRUE));
+ "of console fb driver not supported", temargs.version);
+ ret = tems_failed(credp, B_TRUE);
+ mutex_exit(&tems.ts_lock);
+ return (ret);
}
- if ((tem->fb_polledio = devinit.polledio) == NULL) {
+ if ((tems.ts_fb_polledio = temargs.polledio) == NULL) {
cmn_err(CE_WARN, "terminal emulator: fb doesn't support polled "
"I/O");
- return (tem_init_failed(tem, credp, B_TRUE));
+ ret = tems_failed(credp, B_TRUE);
+ mutex_exit(&tems.ts_lock);
+ return (ret);
}
/* other sanity checks */
- if (!((devinit.depth == 4) || (devinit.depth == 8) ||
- (devinit.depth == 24) || (devinit.depth == 32))) {
+ if (!((temargs.depth == 4) || (temargs.depth == 8) ||
+ (temargs.depth == 24) || (temargs.depth == 32))) {
cmn_err(CE_WARN, "terminal emulator: unsupported depth");
- return (tem_init_failed(tem, credp, B_TRUE));
+ ret = tems_failed(credp, B_TRUE);
+ mutex_exit(&tems.ts_lock);
+ return (ret);
}
- if ((devinit.mode != VIS_TEXT) && (devinit.mode != VIS_PIXEL)) {
+ if ((temargs.mode != VIS_TEXT) && (temargs.mode != VIS_PIXEL)) {
cmn_err(CE_WARN, "terminal emulator: unsupported mode");
- return (tem_init_failed(tem, credp, B_TRUE));
+ ret = tems_failed(credp, B_TRUE);
+ mutex_exit(&tems.ts_lock);
+ return (ret);
}
- if ((devinit.mode == VIS_PIXEL) && plat_stdout_is_framebuffer()) {
+ if ((temargs.mode == VIS_PIXEL) && plat_stdout_is_framebuffer())
plat_tem_get_prom_size(&height, &width);
- }
/*
- * Initialize the terminal emulator
+ * Initialize the common terminal emulator info
*/
- mutex_enter(&tem->lock);
- if ((err = tem_setup_terminal(&devinit, tem, height, width)) != 0) {
- cmn_err(CE_WARN, "terminal emulator: Init failed");
- (void) ldi_ioctl(tem->hdl, VIS_DEVFINI, 0, FWRITE|FKIOCTL,
- credp, &lyr_rval);
- (void) ldi_close(tem->hdl, NULL, credp);
- mutex_exit(&tem->lock);
- tem_free(tem);
- return (err);
- }
+ tems_setup_terminal(&temargs, height, width);
- /*
- * make our kernel console keep compatibility with OBP.
- */
- tem_get_initial_color(tem);
+ tems_reset_colormap(credp, CALLED_FROM_NORMAL);
+ tems_get_initial_color(&tems.ts_init_color);
- /*
- * On SPARC don't clear the screen if the console is the framebuffer.
- * Otherwise it needs to be cleared to get rid of junk that may be
- * in frameuffer memory, since the screen isn't cleared when
- * boot messages are directed elsewhere.
- */
- if (devinit.mode == VIS_TEXT) {
- /*
- * The old getting current cursor position code, which
- * is not needed here, has been in tem_write/tem_polled_write.
- */
- tem_reset_display(tem, credp, CALLED_FROM_NORMAL, 0, NULL);
- } else if (plat_stdout_is_framebuffer()) {
- ASSERT(devinit.mode == VIS_PIXEL);
- plat_tem_hide_prom_cursor();
- tem_reset_display(tem, credp, CALLED_FROM_NORMAL, 0, NULL);
-
- /*
- * We are getting the current cursor position in pixel
- * mode so that we don't over-write the console output
- * during boot.
- */
- plat_tem_get_prom_pos(&row, &col);
-
- /*
- * Adjust the row if necessary when the font of our
- * kernel console tem is different with that of prom
- * tem.
- */
- row = tem_adjust_row(tem, row, credp);
+ tems.ts_initialized = 1; /* initialization flag */
- /* first line of our kernel console output */
- tem->state->first_line = row + 1;
-
- /* re-set and align cusror position */
- tem->state->a_c_cursor.row = row;
- tem->state->a_c_cursor.col = 0;
- tem_align_cursor(tem);
- } else {
- tem_reset_display(tem, credp, CALLED_FROM_NORMAL, 1, NULL);
+ for (p = list_head(&tems.ts_list); p != NULL;
+ p = list_next(&tems.ts_list, p)) {
+ mutex_enter(&p->tvs_lock);
+ tem_internal_init(p, credp, B_TRUE, B_FALSE);
+ if (temargs.mode == VIS_PIXEL)
+ tem_pix_align(p, credp, CALLED_FROM_NORMAL);
+ mutex_exit(&p->tvs_lock);
}
-#ifdef _HAVE_TEM_FIRMWARE
- if (plat_stdout_is_framebuffer()) {
- /*
- * Drivers in the console stream may emit additional
- * messages before we are ready. This causes text
- * overwrite on the screen. So we set the redirection
- * here. It is safe because the ioctl in consconfig_dacf
- * will succeed and consmode will be set to CONS_KFB.
- */
- prom_set_stdout_redirect(console_prom_write_cb,
- (promif_redir_arg_t)tem);
-
- }
-#endif /* _HAVE_TEM_FIRMWARE */
-
- mutex_exit(&tem->lock);
- *ptem = tem; /* Return tem to caller only upon success */
+ mutex_exit(&tems.ts_lock);
return (0);
}
-/*
- * This is a callback function that we register with the frame
- * buffer driver layered underneath. It gets invoked from
- * the underlying frame buffer driver to reconfigure the terminal
- * emulator to a new screen size and depth in conjunction with
- * framebuffer videomode changes.
- * Here we keep the foreground/background color and attributes,
- * which may be different with the initial settings, so that
- * the color won't change while the framebuffer videomode changes.
- * And we also reset the kernel terminal emulator and clear the
- * whole screen.
- */
-void
-tem_modechange_callback(tem_t *tem, struct vis_devinit *devinit)
-{
- tem_color_t tc;
+#define TEMS_DEPTH_DIFF 0x01
+#define TEMS_DIMENSION_DIFF 0x02
- mutex_enter(&tem->lock);
-
- ASSERT(tem->hdl != NULL);
-
- tc.fg_color = tem->state->fg_color;
- tc.bg_color = tem->state->bg_color;
- tc.a_flags = tem->state->a_flags;
-
- (void) tem_setup_terminal(devinit, tem,
- tem->state->a_c_dimension.height,
- tem->state->a_c_dimension.width);
+static uchar_t
+tems_check_videomode(struct vis_devinit *tp)
+{
+ uchar_t result = 0;
- tem_reset_display(tem, kcred, CALLED_FROM_NORMAL, 1, &tc);
+ if (tems.ts_pdepth != tp->depth)
+ result |= TEMS_DEPTH_DIFF;
- mutex_exit(&tem->lock);
+ if (tp->mode == VIS_TEXT) {
+ if (tems.ts_c_dimension.width != tp->width ||
+ tems.ts_c_dimension.height != tp->height)
+ result |= TEMS_DIMENSION_DIFF;
+ } else {
+ if (tems.ts_p_dimension.width != tp->width ||
+ tems.ts_p_dimension.height != tp->height)
+ result |= TEMS_DIMENSION_DIFF;
+ }
- if (tem->modechg_cb != NULL)
- tem->modechg_cb(tem->modechg_arg);
+ return (result);
}
-static int
-tem_setup_terminal(
- struct vis_devinit *devinit,
- tem_t *tem,
- size_t height, size_t width)
+static void
+tems_setup_terminal(struct vis_devinit *tp, size_t height, size_t width)
{
int i;
- struct tem_state *new_state, *prev_state;
-
- ASSERT(MUTEX_HELD(&tem->lock));
+ int old_blank_buf_size = tems.ts_c_dimension.width;
- prev_state = tem->state;
+ ASSERT(MUTEX_HELD(&tems.ts_lock));
- new_state = kmem_zalloc(sizeof (struct tem_state), KM_SLEEP);
+ tems.ts_pdepth = tp->depth;
+ tems.ts_linebytes = tp->linebytes;
+ tems.ts_display_mode = tp->mode;
- new_state->a_pdepth = devinit->depth;
- new_state->display_mode = devinit->mode;
- new_state->linebytes = devinit->linebytes;
-
- switch (devinit->mode) {
+ switch (tp->mode) {
case VIS_TEXT:
- new_state->a_p_dimension.width = 0;
- new_state->a_p_dimension.height = 0;
- new_state->a_c_dimension.width = devinit->width;
- new_state->a_c_dimension.height = devinit->height;
-
- new_state->in_fp.f_display = tem_text_display;
- new_state->in_fp.f_copy = tem_text_copy;
- new_state->in_fp.f_cursor = tem_text_cursor;
- new_state->in_fp.f_cls = tem_text_cls;
- new_state->in_fp.f_bit2pix = NULL;
-
- new_state->a_blank_line =
- kmem_alloc(new_state->a_c_dimension.width, KM_SLEEP);
-
- for (i = 0; i < new_state->a_c_dimension.width; i++)
- new_state->a_blank_line[i] = ' ';
+ tems.ts_p_dimension.width = 0;
+ tems.ts_p_dimension.height = 0;
+ tems.ts_c_dimension.width = tp->width;
+ tems.ts_c_dimension.height = tp->height;
+ tems.ts_callbacks = &tem_safe_text_callbacks;
break;
- case VIS_PIXEL:
+ case VIS_PIXEL:
/*
* First check to see if the user has specified a screen size.
* If so, use those values. Else use 34x80 as the default.
@@ -459,18 +550,13 @@ tem_setup_terminal(
width = TEM_DEFAULT_COLS;
height = TEM_DEFAULT_ROWS;
}
- new_state->a_c_dimension.height = height;
- new_state->a_c_dimension.width = width;
-
- new_state->a_p_dimension.height = devinit->height;
- new_state->a_p_dimension.width = devinit->width;
+ tems.ts_c_dimension.height = (screen_size_t)height;
+ tems.ts_c_dimension.width = (screen_size_t)width;
- new_state->in_fp.f_display = tem_pix_display;
- new_state->in_fp.f_copy = tem_pix_copy;
- new_state->in_fp.f_cursor = tem_pix_cursor;
- new_state->in_fp.f_cls = tem_pix_cls;
+ tems.ts_p_dimension.height = tp->height;
+ tems.ts_p_dimension.width = tp->width;
- new_state->a_blank_line = NULL;
+ tems.ts_callbacks = &tem_safe_pix_callbacks;
/*
* set_font() will select a appropriate sized font for
@@ -479,75 +565,114 @@ tem_setup_terminal(
* default builtin font and adjust the rows and columns
* to fit on the screen.
*/
- set_font(&new_state->a_font,
- &new_state->a_c_dimension.height,
- &new_state->a_c_dimension.width,
- new_state->a_p_dimension.height,
- new_state->a_p_dimension.width);
-
- new_state->a_p_offset.y =
- (new_state->a_p_dimension.height -
- (new_state->a_c_dimension.height *
- new_state->a_font.height)) / 2;
-
- new_state->a_p_offset.x =
- (new_state->a_p_dimension.width -
- (new_state->a_c_dimension.width *
- new_state->a_font.width)) / 2;
-
- switch (devinit->depth) {
- case 4:
- new_state->in_fp.f_bit2pix = bit_to_pix4;
- new_state->a_pix_data_size =
- (((new_state->a_font.width * 4) +
- NBBY - 1) / NBBY) * new_state->a_font.height;
- break;
- case 8:
- new_state->in_fp.f_bit2pix = bit_to_pix8;
- new_state->a_pix_data_size =
- new_state->a_font.width *
- new_state->a_font.height;
- break;
- case 24:
- case 32:
- new_state->in_fp.f_bit2pix = bit_to_pix24;
- new_state->a_pix_data_size =
- new_state->a_font.width *
- new_state->a_font.height;
- new_state->a_pix_data_size *= 4;
- break;
- }
+ set_font(&tems.ts_font,
+ &tems.ts_c_dimension.height,
+ &tems.ts_c_dimension.width,
+ tems.ts_p_dimension.height,
+ tems.ts_p_dimension.width);
+
+ tems.ts_p_offset.y = (tems.ts_p_dimension.height -
+ (tems.ts_c_dimension.height * tems.ts_font.height)) / 2;
+ tems.ts_p_offset.x = (tems.ts_p_dimension.width -
+ (tems.ts_c_dimension.width * tems.ts_font.width)) / 2;
- new_state->a_pix_data =
- kmem_alloc(new_state->a_pix_data_size, KM_SLEEP);
+ tems.ts_pix_data_size =
+ tems.ts_font.width * tems.ts_font.height;
+
+ tems.ts_pix_data_size *= 4;
+
+ tems.ts_pdepth = tp->depth;
break;
+ }
+
+ /* Now virtual cls also uses the blank_line buffer */
+ if (tems.ts_blank_line)
+ kmem_free(tems.ts_blank_line, old_blank_buf_size);
- default:
+ tems.ts_blank_line = (unsigned char *)
+ kmem_alloc(tems.ts_c_dimension.width, KM_SLEEP);
+ for (i = 0; i < tems.ts_c_dimension.width; i++)
+ tems.ts_blank_line[i] = ' ';
+}
+
+/*
+ * This is a callback function that we register with the frame
+ * buffer driver layered underneath. It gets invoked from
+ * the underlying frame buffer driver to reconfigure the terminal
+ * emulator to a new screen size and depth in conjunction with
+ * framebuffer videomode changes.
+ * Here we keep the foreground/background color and attributes,
+ * which may be different with the initial settings, so that
+ * the color won't change while the framebuffer videomode changes.
+ * And we also reset the kernel terminal emulator and clear the
+ * whole screen.
+ */
+/* ARGSUSED */
+void
+tems_modechange_callback(struct vis_modechg_arg *arg,
+ struct vis_devinit *devinit)
+{
+ uchar_t diff;
+ struct tem_vt_state *p;
+ tem_modechg_cb_t cb;
+ tem_modechg_cb_arg_t cb_arg;
+
+ ASSERT(!(list_is_empty(&tems.ts_list)));
+
+ mutex_enter(&tems.ts_lock);
+
+ /*
+ * currently only for pixel mode
+ */
+ diff = tems_check_videomode(devinit);
+ if (diff == 0) {
+ mutex_exit(&tems.ts_lock);
+ return;
+ }
+
+ diff = diff & TEMS_DIMENSION_DIFF;
+
+ if (diff == 0) {
/*
- * The layered fb driver conveyed an unrecognized rendering
- * mode. We cannot proceed with tem initialization.
+ * Only need to reinit the active tem.
*/
- kmem_free(new_state, sizeof (struct tem_state));
- return (ENXIO);
+ struct tem_vt_state *active = tems.ts_active;
+ tems.ts_pdepth = devinit->depth;
+
+ mutex_enter(&active->tvs_lock);
+ ASSERT(active->tvs_isactive);
+ tem_reinit(active, B_TRUE);
+ mutex_exit(&active->tvs_lock);
+
+ mutex_exit(&tems.ts_lock);
+ return;
}
- new_state->a_outbuf =
- kmem_alloc(new_state->a_c_dimension.width, KM_SLEEP);
+ tems_setup_terminal(devinit, tems.ts_c_dimension.height,
+ tems.ts_c_dimension.width);
- /*
- * Change state atomically so that polled I/O requests
- * can be safely and reliably serviced anytime after the terminal
- * emulator is originally initialized and the console mode has been
- * switched over from the PROM, even while a videomode change
- * callback is being processed.
- */
- tem->state = new_state;
+ for (p = list_head(&tems.ts_list); p != NULL;
+ p = list_next(&tems.ts_list, p)) {
+ mutex_enter(&p->tvs_lock);
+ tem_reinit(p, p->tvs_isactive);
+ mutex_exit(&p->tvs_lock);
+ }
- if (prev_state != NULL)
- tem_free_state(prev_state);
- return (0);
+ if (tems.ts_modechg_cb == NULL) {
+ mutex_exit(&tems.ts_lock);
+ return;
+ }
+
+ cb = tems.ts_modechg_cb;
+ cb_arg = tems.ts_modechg_arg;
+
+ /*
+ * Release the lock while doing callback.
+ */
+ mutex_exit(&tems.ts_lock);
+ cb(cb_arg);
}
/*
@@ -556,14 +681,13 @@ tem_setup_terminal(
* The blit can be as small as a pixel or as large as the screen.
*/
void
-tem_display_layered(
- tem_t *tem,
+tems_display_layered(
struct vis_consdisplay *pda,
cred_t *credp)
{
int rval;
- (void) ldi_ioctl(tem->hdl, VIS_CONSDISPLAY,
+ (void) ldi_ioctl(tems.ts_hdl, VIS_CONSDISPLAY,
(intptr_t)pda, FKIOCTL, credp, &rval);
}
@@ -574,14 +698,13 @@ tem_display_layered(
* such as from vi when deleting characters and words.
*/
void
-tem_copy_layered(
- tem_t *tem,
+tems_copy_layered(
struct vis_conscopy *pma,
cred_t *credp)
{
int rval;
- (void) ldi_ioctl(tem->hdl, VIS_CONSCOPY,
+ (void) ldi_ioctl(tems.ts_hdl, VIS_CONSCOPY,
(intptr_t)pma, FKIOCTL, credp, &rval);
}
@@ -590,22 +713,28 @@ tem_copy_layered(
* pixel inverting, text block cursor via the underlying framebuffer.
*/
void
-tem_cursor_layered(
- tem_t *tem,
+tems_cursor_layered(
struct vis_conscursor *pca,
cred_t *credp)
{
int rval;
- (void) ldi_ioctl(tem->hdl, VIS_CONSCURSOR,
+ (void) ldi_ioctl(tems.ts_hdl, VIS_CONSCURSOR,
(intptr_t)pca, FKIOCTL, credp, &rval);
}
-void
-tem_reset_colormap(
- tem_t *tem,
- cred_t *credp,
- enum called_from called_from)
+static void
+tem_kdsetmode(int mode, cred_t *credp)
+{
+ int rval;
+
+ (void) ldi_ioctl(tems.ts_hdl, KDSETMODE,
+ (intptr_t)mode, FKIOCTL, credp, &rval);
+
+}
+
+static void
+tems_reset_colormap(cred_t *credp, enum called_from called_from)
{
struct vis_cmap cm;
int rval;
@@ -613,35 +742,41 @@ tem_reset_colormap(
if (called_from == CALLED_FROM_STANDALONE)
return;
- switch (tem->state->a_pdepth) {
+ switch (tems.ts_pdepth) {
case 8:
cm.index = 0;
cm.count = 16;
cm.red = cmap4_to_24.red; /* 8-bits (1/3 of TrueColor 24) */
cm.blue = cmap4_to_24.blue; /* 8-bits (1/3 of TrueColor 24) */
cm.green = cmap4_to_24.green; /* 8-bits (1/3 of TrueColor 24) */
- (void) ldi_ioctl(tem->hdl, VIS_PUTCMAP, (intptr_t)&cm,
+ (void) ldi_ioctl(tems.ts_hdl, VIS_PUTCMAP, (intptr_t)&cm,
FKIOCTL, credp, &rval);
break;
}
}
void
-tem_get_size(tem_t *tem, ushort_t *r, ushort_t *c,
+tem_get_size(ushort_t *r, ushort_t *c,
ushort_t *x, ushort_t *y)
{
- *r = (ushort_t)tem->state->a_c_dimension.height;
- *c = (ushort_t)tem->state->a_c_dimension.width;
- *x = (ushort_t)tem->state->a_p_dimension.width;
- *y = (ushort_t)tem->state->a_p_dimension.height;
+ mutex_enter(&tems.ts_lock);
+ *r = (ushort_t)tems.ts_c_dimension.height;
+ *c = (ushort_t)tems.ts_c_dimension.width;
+ *x = (ushort_t)tems.ts_p_dimension.width;
+ *y = (ushort_t)tems.ts_p_dimension.height;
+ mutex_exit(&tems.ts_lock);
}
void
-tem_register_modechg_cb(tem_t *tem, tem_modechg_cb_t func,
+tem_register_modechg_cb(tem_modechg_cb_t func,
tem_modechg_cb_arg_t arg)
{
- tem->modechg_cb = func;
- tem->modechg_arg = arg;
+ mutex_enter(&tems.ts_lock);
+
+ tems.ts_modechg_cb = func;
+ tems.ts_modechg_arg = arg;
+
+ mutex_exit(&tems.ts_lock);
}
/*
@@ -649,43 +784,41 @@ tem_register_modechg_cb(tem_t *tem, tem_modechg_cb_t func,
* different screen height and width with our kernel console.
*/
static void
-tem_prom_scroll_up(struct tem *tem, int nrows, cred_t *credp)
+tem_prom_scroll_up(struct tem_vt_state *tem, int nrows, cred_t *credp,
+ enum called_from called_from)
{
- struct tem_state *tems = tem->state;
struct vis_conscopy ma;
int ncols, width;
/* copy */
- ma.s_row = nrows * tems->a_font.height;
- ma.e_row = tems->a_p_dimension.height - 1;
+ ma.s_row = nrows * tems.ts_font.height;
+ ma.e_row = tems.ts_p_dimension.height - 1;
ma.t_row = 0;
ma.s_col = 0;
- ma.e_col = tems->a_p_dimension.width - 1;
+ ma.e_col = tems.ts_p_dimension.width - 1;
ma.t_col = 0;
- tem_copy(tem, &ma, credp, CALLED_FROM_NORMAL);
+ tems_safe_copy(&ma, credp, called_from);
/* clear */
- width = tems->a_font.width;
- ncols = (tems->a_p_dimension.width +
- (width - 1))/ width;
+ width = tems.ts_font.width;
+ ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
- tem_pix_cls_range(tem,
- 0, nrows, tems->a_p_offset.y,
- 0, ncols, 0,
- B_TRUE, credp, CALLED_FROM_NORMAL);
+ tem_safe_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y,
+ 0, ncols, 0, B_TRUE, credp, called_from);
}
#define PROM_DEFAULT_FONT_HEIGHT 22
-#define PROM_DEFAULT_WINDOW_TOP 0x8a
+#define PROM_DEFAULT_WINDOW_TOP 0x8a
/*
* This function is to compute the starting row of the console, according to
* PROM cursor's position. Here we have to take different fonts into account.
*/
static int
-tem_adjust_row(tem_t *tem, int prom_row, cred_t *credp)
+tem_adjust_row(struct tem_vt_state *tem, int prom_row, cred_t *credp,
+ enum called_from called_from)
{
int tem_row;
int tem_y;
@@ -700,28 +833,64 @@ tem_adjust_row(tem_t *tem, int prom_row, cred_t *credp)
prom_window_top = PROM_DEFAULT_WINDOW_TOP;
tem_y = (prom_row + 1) * prom_charheight + prom_window_top -
- tem->state->a_p_offset.y;
- tem_row = (tem_y + tem->state->a_font.height - 1) /
- tem->state->a_font.height - 1;
+ tems.ts_p_offset.y;
+ tem_row = (tem_y + tems.ts_font.height - 1) /
+ tems.ts_font.height - 1;
if (tem_row < 0) {
tem_row = 0;
- } else if (tem_row >= (tem->state->a_c_dimension.height - 1)) {
+ } else if (tem_row >= (tems.ts_c_dimension.height - 1)) {
/*
* Scroll up the prom outputs if the PROM cursor's position is
* below our tem's lower boundary.
*/
scroll_up_lines = tem_row -
- (tem->state->a_c_dimension.height - 1);
- tem_prom_scroll_up(tem, scroll_up_lines, credp);
- tem_row = tem->state->a_c_dimension.height - 1;
+ (tems.ts_c_dimension.height - 1);
+ tem_prom_scroll_up(tem, scroll_up_lines, credp, called_from);
+ tem_row = tems.ts_c_dimension.height - 1;
}
return (tem_row);
}
+void
+tem_pix_align(struct tem_vt_state *tem, cred_t *credp,
+ enum called_from called_from)
+{
+ uint32_t row = 0;
+ uint32_t col = 0;
+
+ if (plat_stdout_is_framebuffer()) {
+ plat_tem_hide_prom_cursor();
+
+ /*
+ * We are getting the current cursor position in pixel
+ * mode so that we don't over-write the console output
+ * during boot.
+ */
+ plat_tem_get_prom_pos(&row, &col);
+
+ /*
+ * Adjust the row if necessary when the font of our
+ * kernel console tem is different with that of prom
+ * tem.
+ */
+ row = tem_adjust_row(tem, row, credp, called_from);
+
+ /* first line of our kernel console output */
+ tem->tvs_first_line = row + 1;
+
+ /* re-set and align cusror position */
+ tem->tvs_s_cursor.row = tem->tvs_c_cursor.row =
+ (screen_pos_t)row;
+ tem->tvs_s_cursor.col = tem->tvs_c_cursor.col = 0;
+ } else {
+ tem_safe_reset_display(tem, credp, called_from, B_TRUE, B_TRUE);
+ }
+}
+
static void
-tem_get_inverses(boolean_t *p_inverse, boolean_t *p_inverse_screen)
+tems_get_inverses(boolean_t *p_inverse, boolean_t *p_inverse_screen)
{
int i_inverse = 0;
int i_inverse_screen = 0;
@@ -737,16 +906,16 @@ tem_get_inverses(boolean_t *p_inverse, boolean_t *p_inverse_screen)
* PROM, so that our kernel console can keep the same visual behaviour.
*/
static void
-tem_get_initial_color(tem_t *tem)
+tems_get_initial_color(tem_color_t *pcolor)
{
boolean_t inverse, inverse_screen;
unsigned short flags = 0;
- tem->init_color.fg_color = DEFAULT_ANSI_FOREGROUND;
- tem->init_color.bg_color = DEFAULT_ANSI_BACKGROUND;
+ pcolor->fg_color = DEFAULT_ANSI_FOREGROUND;
+ pcolor->bg_color = DEFAULT_ANSI_BACKGROUND;
if (plat_stdout_is_framebuffer()) {
- tem_get_inverses(&inverse, &inverse_screen);
+ tems_get_inverses(&inverse, &inverse_screen);
if (inverse)
flags |= TEM_ATTR_REVERSE;
if (inverse_screen)
@@ -755,5 +924,91 @@ tem_get_initial_color(tem_t *tem)
flags |= TEM_ATTR_BOLD;
}
- tem->init_color.a_flags = flags;
+ pcolor->a_flags = flags;
+}
+
+uchar_t
+tem_get_fbmode(tem_vt_state_t tem_arg)
+{
+ struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
+
+ uchar_t fbmode;
+
+ mutex_enter(&tem->tvs_lock);
+ fbmode = tem->tvs_fbmode;
+ mutex_exit(&tem->tvs_lock);
+
+ return (fbmode);
+}
+
+void
+tem_set_fbmode(tem_vt_state_t tem_arg, uchar_t fbmode, cred_t *credp)
+{
+ struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
+
+ mutex_enter(&tems.ts_lock);
+ mutex_enter(&tem->tvs_lock);
+
+ if (fbmode == tem->tvs_fbmode) {
+ mutex_exit(&tem->tvs_lock);
+ mutex_exit(&tems.ts_lock);
+ return;
+ }
+
+ tem->tvs_fbmode = fbmode;
+
+ if (tem->tvs_isactive) {
+ tem_kdsetmode(tem->tvs_fbmode, credp);
+ if (fbmode == KD_TEXT)
+ tem_safe_unblank_screen(tem, credp, CALLED_FROM_NORMAL);
+ }
+
+ mutex_exit(&tem->tvs_lock);
+ mutex_exit(&tems.ts_lock);
+}
+
+void
+tem_activate(tem_vt_state_t tem_arg, boolean_t unblank, cred_t *credp)
+{
+ struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
+
+ mutex_enter(&tems.ts_lock);
+ tems.ts_active = tem;
+
+ mutex_enter(&tem->tvs_lock);
+ tem->tvs_isactive = B_TRUE;
+
+ tem_kdsetmode(tem->tvs_fbmode, credp);
+
+ if (unblank)
+ tem_safe_unblank_screen(tem, credp, CALLED_FROM_NORMAL);
+
+ mutex_exit(&tem->tvs_lock);
+ mutex_exit(&tems.ts_lock);
+}
+
+void
+tem_switch(tem_vt_state_t tem_arg1, tem_vt_state_t tem_arg2, cred_t *credp)
+{
+ struct tem_vt_state *cur = (struct tem_vt_state *)tem_arg1;
+ struct tem_vt_state *tobe = (struct tem_vt_state *)tem_arg2;
+
+ mutex_enter(&tems.ts_lock);
+ mutex_enter(&tobe->tvs_lock);
+ mutex_enter(&cur->tvs_lock);
+
+ tems.ts_active = tobe;
+ cur->tvs_isactive = B_FALSE;
+ tobe->tvs_isactive = B_TRUE;
+
+ mutex_exit(&cur->tvs_lock);
+
+ if (cur->tvs_fbmode != tobe->tvs_fbmode)
+ tem_kdsetmode(tobe->tvs_fbmode, credp);
+
+ if (tobe->tvs_fbmode == KD_TEXT)
+ tem_safe_unblank_screen(tobe, credp, CALLED_FROM_NORMAL);
+
+ mutex_exit(&tobe->tvs_lock);
+ mutex_exit(&tems.ts_lock);
}
diff --git a/usr/src/uts/common/io/tem_safe.c b/usr/src/uts/common/io/tem_safe.c
index 10df667057..fa2e4916cd 100644
--- a/usr/src/uts/common/io/tem_safe.c
+++ b/usr/src/uts/common/io/tem_safe.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Polled I/O safe ANSI terminal emulator module;
* Supporting TERM types 'sun' and 'sun-color, parsing
@@ -48,6 +46,14 @@
* - CANNOT wait for interrupts
* - CANNOT allocate memory
*
+ * All non-static functions in this file which:
+ * - Operates on tems and tem_vt_state
+ * - Not only called from standalone mode, i.e. has
+ * a "calledfrom" argument
+ * should assert this at the beginning:
+ *
+ * ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ * called_from == CALLED_FROM_STANDALONE);
*/
#include <sys/types.h>
@@ -59,65 +65,91 @@
#include <sys/ksynch.h>
#include <sys/sysmacros.h>
#include <sys/mutex.h>
+#include <sys/note.h>
+#include <sys/t_lock.h>
+
+tem_safe_callbacks_t tem_safe_text_callbacks = {
+ &tem_safe_text_display,
+ &tem_safe_text_copy,
+ &tem_safe_text_cursor,
+ NULL,
+ &tem_safe_text_cls
+};
+tem_safe_callbacks_t tem_safe_pix_callbacks = {
+ &tem_safe_pix_display,
+ &tem_safe_pix_copy,
+ &tem_safe_pix_cursor,
+ &tem_safe_pix_bit2pix,
+ &tem_safe_pix_cls
+};
-static void tem_display(struct tem *,
- struct vis_consdisplay *,
- cred_t *, enum called_from);
-static void tem_cursor(struct tem *,
- struct vis_conscursor *,
- cred_t *, enum called_from);
-static void tem_control(struct tem *, uchar_t,
+
+static void tem_safe_control(struct tem_vt_state *, uchar_t,
cred_t *, enum called_from);
-static void tem_setparam(struct tem *, int, int);
-static void tem_selgraph(struct tem *);
-static void tem_chkparam(struct tem *, uchar_t,
+static void tem_safe_setparam(struct tem_vt_state *, int, int);
+static void tem_safe_selgraph(struct tem_vt_state *);
+static void tem_safe_chkparam(struct tem_vt_state *, uchar_t,
cred_t *, enum called_from);
-static void tem_getparams(struct tem *, uchar_t,
+static void tem_safe_getparams(struct tem_vt_state *, uchar_t,
cred_t *, enum called_from);
-static void tem_outch(struct tem *, uchar_t,
+static void tem_safe_outch(struct tem_vt_state *, uchar_t,
cred_t *, enum called_from);
-static void tem_parse(struct tem *, uchar_t,
+static void tem_safe_parse(struct tem_vt_state *, uchar_t,
cred_t *, enum called_from);
-static void tem_new_line(struct tem *,
+static void tem_safe_new_line(struct tem_vt_state *,
cred_t *, enum called_from);
-static void tem_cr(struct tem *);
-static void tem_lf(struct tem *,
+static void tem_safe_cr(struct tem_vt_state *);
+static void tem_safe_lf(struct tem_vt_state *,
cred_t *, enum called_from);
-static void tem_send_data(struct tem *, cred_t *,
+static void tem_safe_send_data(struct tem_vt_state *, cred_t *,
enum called_from);
-static void tem_cls(struct tem *,
+static void tem_safe_cls(struct tem_vt_state *,
cred_t *, enum called_from);
-static void tem_tab(struct tem *,
+static void tem_safe_tab(struct tem_vt_state *,
cred_t *, enum called_from);
-static void tem_back_tab(struct tem *,
+static void tem_safe_back_tab(struct tem_vt_state *,
cred_t *, enum called_from);
-static void tem_clear_tabs(struct tem *, int);
-static void tem_set_tab(struct tem *);
-static void tem_mv_cursor(struct tem *, int, int,
+static void tem_safe_clear_tabs(struct tem_vt_state *, int);
+static void tem_safe_set_tab(struct tem_vt_state *);
+static void tem_safe_mv_cursor(struct tem_vt_state *, int, int,
cred_t *, enum called_from);
-static void tem_shift(struct tem *, int, int,
+static void tem_safe_shift(struct tem_vt_state *, int, int,
cred_t *, enum called_from);
-static void tem_scroll(struct tem *, int, int,
+static void tem_safe_scroll(struct tem_vt_state *, int, int,
int, int, cred_t *, enum called_from);
-static void tem_clear_chars(struct tem *tem,
+static void tem_safe_clear_chars(struct tem_vt_state *tem,
int count, screen_pos_t row, screen_pos_t col,
cred_t *credp, enum called_from called_from);
-static void tem_copy_area(struct tem *tem,
+static void tem_safe_copy_area(struct tem_vt_state *tem,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row,
cred_t *credp, enum called_from called_from);
-static void tem_image_display(struct tem *, uchar_t *,
+static void tem_safe_image_display(struct tem_vt_state *, uchar_t *,
int, int, screen_pos_t, screen_pos_t,
cred_t *, enum called_from);
-static void tem_bell(struct tem *tem,
+static void tem_safe_bell(struct tem_vt_state *tem,
enum called_from called_from);
-static void tem_get_color(struct tem *tem,
- text_color_t *fg, text_color_t *bg);
-static void tem_pix_clear_prom_output(struct tem *tem,
+static void tem_safe_pix_clear_prom_output(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from);
+static void tem_safe_virtual_cls(struct tem_vt_state *, int, screen_pos_t,
+ screen_pos_t);
+static void tem_safe_virtual_display(struct tem_vt_state *,
+ unsigned char *, int, screen_pos_t, screen_pos_t,
+ text_color_t, text_color_t);
+static void tem_safe_virtual_copy(struct tem_vt_state *, screen_pos_t,
+ screen_pos_t, screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t);
+static void tem_safe_align_cursor(struct tem_vt_state *tem);
+static void bit_to_pix4(struct tem_vt_state *tem, uchar_t c,
+ text_color_t fg_color, text_color_t bg_color);
+static void bit_to_pix8(struct tem_vt_state *tem, uchar_t c,
+ text_color_t fg_color, text_color_t bg_color);
+static void bit_to_pix24(struct tem_vt_state *tem, uchar_t c,
+ text_color_t fg_color, text_color_t bg_color);
+
/* BEGIN CSTYLED */
/* Bk Rd Gr Br Bl Mg Cy Wh */
static text_color_t fg_dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 };
@@ -168,31 +200,40 @@ struct fontlist fonts[] = {
#define INVERSE(ch) (ch ^ 0xff)
-#define BIT_TO_PIX(tem, c, fg, bg) { \
- ASSERT((tem)->state->in_fp.f_bit2pix != NULL); \
- (void) (*(tem)->state->in_fp.f_bit2pix)((tem), (c), (fg), (bg));\
+#define tem_safe_callback_display (*tems.ts_callbacks->tsc_display)
+#define tem_safe_callback_copy (*tems.ts_callbacks->tsc_copy)
+#define tem_safe_callback_cursor (*tems.ts_callbacks->tsc_cursor)
+#define tem_safe_callback_cls (*tems.ts_callbacks->tsc_cls)
+#define tem_safe_callback_bit2pix(tem, c, fg, bg) { \
+ ASSERT(tems.ts_callbacks->tsc_bit2pix != NULL); \
+ (void) (*tems.ts_callbacks->tsc_bit2pix)((tem), (c), (fg), (bg));\
}
void
-tem_check_first_time(
- struct tem *tem,
+tem_safe_check_first_time(
+ struct tem_vt_state *tem,
cred_t *credp,
enum called_from called_from)
{
static int first_time = 1;
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
+
/*
* Realign the console cursor. We did this in tem_init().
* However, drivers in the console stream may emit additional
* messages before we are ready. This causes text overwrite
* on the screen. This is a workaround.
*/
- if (first_time && tem->state->display_mode == VIS_TEXT) {
- tem_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
- tem_align_cursor(tem);
- }
- first_time = 0;
+ if (!first_time)
+ return;
+ first_time = 0;
+ if (tems.ts_display_mode == VIS_TEXT) {
+ tem_safe_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
+ tem_safe_align_cursor(tem);
+ }
}
/*
@@ -205,16 +246,24 @@ tem_check_first_time(
* It is also entered when the kernel is panicing.
*/
void
-tem_polled_write(
- struct tem *tem,
+tem_safe_polled_write(
+ tem_vt_state_t tem_arg,
uchar_t *buf,
int len)
{
+ struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
+
+#ifdef __lock_lint
+ _NOTE(NO_COMPETING_THREADS_NOW)
+ _NOTE(NO_COMPETING_THREADS_AS_SIDE_EFFECT)
+#endif
- ASSERT(tem->hdl != NULL);
+ if (!tem->tvs_initialized) {
+ return;
+ }
- tem_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
- tem_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
+ tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
+ tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
}
@@ -227,32 +276,32 @@ tem_polled_write(
* no enqueing.
*/
void
-tem_terminal_emulate(
- struct tem *tem,
+tem_safe_terminal_emulate(
+ struct tem_vt_state *tem,
uchar_t *buf,
int len,
cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- (*tems->in_fp.f_cursor)
- (tem, VIS_HIDE_CURSOR, credp, called_from);
+ if (tem->tvs_isactive)
+ tem_safe_callback_cursor(tem,
+ VIS_HIDE_CURSOR, credp, called_from);
- for (; len > 0; len--, buf++) {
- tem_parse(tem, *buf, credp, called_from);
- }
+ for (; len > 0; len--, buf++)
+ tem_safe_parse(tem, *buf, credp, called_from);
/*
* Send the data we just got to the framebuffer.
*/
- tem_send_data(tem, credp, called_from);
+ tem_safe_send_data(tem, credp, called_from);
- (*tems->in_fp.f_cursor)
- (tem, VIS_DISPLAY_CURSOR, credp, called_from);
+ if (tem->tvs_isactive)
+ tem_safe_callback_cursor(tem,
+ VIS_DISPLAY_CURSOR, credp, called_from);
}
/*
@@ -261,16 +310,15 @@ tem_terminal_emulate(
* from quiesced or normal (ie. use polled I/O vs. layered ioctls)
*/
static void
-tem_display(
- struct tem *tem,
+tems_safe_display(
struct vis_consdisplay *pda,
cred_t *credp,
enum called_from called_from)
{
if (called_from == CALLED_FROM_STANDALONE)
- tem->fb_polledio->display(tem->fb_polledio->arg, pda);
+ tems.ts_fb_polledio->display(tems.ts_fb_polledio->arg, pda);
else
- tem_display_layered(tem, pda, credp);
+ tems_display_layered(pda, credp);
}
/*
@@ -279,16 +327,15 @@ tem_display(
* from, quiesced or normal (ie. use polled I/O vs. layered ioctls)
*/
void
-tem_copy(
- struct tem *tem,
+tems_safe_copy(
struct vis_conscopy *pca,
cred_t *credp,
enum called_from called_from)
{
if (called_from == CALLED_FROM_STANDALONE)
- tem->fb_polledio->copy(tem->fb_polledio->arg, pca);
+ tems.ts_fb_polledio->copy(tems.ts_fb_polledio->arg, pca);
else
- tem_copy_layered(tem, pca, credp);
+ tems_copy_layered(pca, credp);
}
/*
@@ -298,16 +345,15 @@ tem_copy(
* normal (ie. use polled I/O vs. layered ioctls).
*/
static void
-tem_cursor(
- struct tem *tem,
+tems_safe_cursor(
struct vis_conscursor *pca,
cred_t *credp,
enum called_from called_from)
{
if (called_from == CALLED_FROM_STANDALONE)
- tem->fb_polledio->cursor(tem->fb_polledio->arg, pca);
+ tems.ts_fb_polledio->cursor(tems.ts_fb_polledio->arg, pca);
else
- tem_cursor_layered(tem, pca, credp);
+ tems_cursor_layered(pca, credp);
}
/*
@@ -316,75 +362,70 @@ tem_cursor(
*/
static void
-tem_control(
- struct tem *tem,
+tem_safe_control(
+ struct tem_vt_state *tem,
uchar_t ch,
cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
-
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
-
- tems->a_state = A_STATE_START;
+ tem->tvs_state = A_STATE_START;
switch (ch) {
case A_BEL:
- tem_bell(tem, called_from);
+ tem_safe_bell(tem, called_from);
break;
case A_BS:
- tem_mv_cursor(tem,
- tems->a_c_cursor.row,
- tems->a_c_cursor.col - 1,
+ tem_safe_mv_cursor(tem,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col - 1,
credp, called_from);
break;
case A_HT:
- tem_tab(tem, credp, called_from);
+ tem_safe_tab(tem, credp, called_from);
break;
case A_NL:
/*
- * tem_send_data(tem, credp, called_from);
- * tem_new_line(tem, credp, called_from);
+ * tem_safe_send_data(tem, credp, called_from);
+ * tem_safe_new_line(tem, credp, called_from);
* break;
*/
case A_VT:
- tem_send_data(tem, credp, called_from);
- tem_lf(tem, credp, called_from);
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_lf(tem, credp, called_from);
break;
case A_FF:
- tem_send_data(tem, credp, called_from);
- tem_cls(tem, credp, called_from);
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_cls(tem, credp, called_from);
break;
case A_CR:
- tem_send_data(tem, credp, called_from);
- tem_cr(tem);
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_cr(tem);
break;
case A_ESC:
- tems->a_state = A_STATE_ESC;
+ tem->tvs_state = A_STATE_ESC;
break;
case A_CSI:
{
int i;
- tems->a_curparam = 0;
- tems->a_paramval = 0;
- tems->a_gotparam = B_FALSE;
+ tem->tvs_curparam = 0;
+ tem->tvs_paramval = 0;
+ tem->tvs_gotparam = B_FALSE;
/* clear the parameters */
for (i = 0; i < TEM_MAXPARAMS; i++)
- tems->a_params[i] = -1;
- tems->a_state = A_STATE_CSI;
+ tem->tvs_params[i] = -1;
+ tem->tvs_state = A_STATE_CSI;
}
break;
case A_GS:
- tem_back_tab(tem, credp, called_from);
+ tem_safe_back_tab(tem, credp, called_from);
break;
default:
@@ -399,13 +440,13 @@ tem_control(
*/
static void
-tem_setparam(struct tem *tem, int count, int newparam)
+tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam)
{
int i;
for (i = 0; i < count; i++) {
- if (tem->state->a_params[i] == -1)
- tem->state->a_params[i] = newparam;
+ if (tem->tvs_params[i] == -1)
+ tem->tvs_params[i] = newparam;
}
}
@@ -414,47 +455,44 @@ tem_setparam(struct tem *tem, int count, int newparam)
* select graphics mode based on the param vals stored in a_params
*/
static void
-tem_selgraph(struct tem *tem)
+tem_safe_selgraph(struct tem_vt_state *tem)
{
- struct tem_state *tems = tem->state;
int curparam;
int count = 0;
int param;
- curparam = tems->a_curparam;
+ tem->tvs_state = A_STATE_START;
+
+ curparam = tem->tvs_curparam;
do {
- param = tems->a_params[count];
+ param = tem->tvs_params[count];
switch (param) {
case -1:
case 0:
- if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) {
- tems->a_flags |= TEM_ATTR_REVERSE;
- } else {
- tems->a_flags &= ~TEM_ATTR_REVERSE;
- }
- tems->a_flags = tem->init_color.a_flags;
- tems->fg_color = tem->init_color.fg_color;
- tems->bg_color = tem->init_color.bg_color;
+ /* reset to initial normal settings */
+ tem->tvs_fg_color = tems.ts_init_color.fg_color;
+ tem->tvs_bg_color = tems.ts_init_color.bg_color;
+ tem->tvs_flags = tems.ts_init_color.a_flags;
break;
case 1: /* Bold Intense */
- tems->a_flags |= TEM_ATTR_BOLD;
+ tem->tvs_flags |= TEM_ATTR_BOLD;
break;
case 2: /* Faint Intense */
- tems->a_flags &= ~TEM_ATTR_BOLD;
+ tem->tvs_flags &= ~TEM_ATTR_BOLD;
break;
case 5: /* Blink */
- tems->a_flags |= TEM_ATTR_BLINK;
+ tem->tvs_flags |= TEM_ATTR_BLINK;
break;
case 7: /* Reverse video */
- if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) {
- tems->a_flags &= ~TEM_ATTR_REVERSE;
+ if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
+ tem->tvs_flags &= ~TEM_ATTR_REVERSE;
} else {
- tems->a_flags |= TEM_ATTR_REVERSE;
+ tem->tvs_flags |= TEM_ATTR_REVERSE;
}
break;
@@ -466,7 +504,7 @@ tem_selgraph(struct tem *tem)
case 35: /* magenta (light magenta) foreground */
case 36: /* cyan (light cyan) foreground */
case 37: /* white (bright white) foreground */
- tems->fg_color = param - 30;
+ tem->tvs_fg_color = param - 30;
break;
case 40: /* black (grey) background */
@@ -477,7 +515,7 @@ tem_selgraph(struct tem *tem)
case 45: /* magenta (light magenta) background */
case 46: /* cyan (light cyan) background */
case 47: /* white (bright white) background */
- tems->bg_color = param - 40;
+ tem->tvs_bg_color = param - 40;
break;
default:
@@ -487,9 +525,6 @@ tem_selgraph(struct tem *tem)
curparam--;
} while (curparam > 0);
-
-
- tems->a_state = A_STATE_START;
}
/*
@@ -499,103 +534,102 @@ tem_selgraph(struct tem *tem)
* It assumes that the next lower level will do so.
*/
static void
-tem_chkparam(
- struct tem *tem,
+tem_safe_chkparam(
+ struct tem_vt_state *tem,
uchar_t ch,
cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int i;
int row;
int col;
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ MUTEX_HELD(&tem->tvs_lock));
- row = tems->a_c_cursor.row;
- col = tems->a_c_cursor.col;
+ row = tem->tvs_c_cursor.row;
+ col = tem->tvs_c_cursor.col;
switch (ch) {
case 'm': /* select terminal graphics mode */
- tem_send_data(tem, credp, called_from);
- tem_selgraph(tem);
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_selgraph(tem);
break;
case '@': /* insert char */
- tem_setparam(tem, 1, 1);
- tem_shift(tem, tems->a_params[0], TEM_SHIFT_RIGHT,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT,
credp, called_from);
break;
case 'A': /* cursor up */
- tem_setparam(tem, 1, 1);
- tem_mv_cursor(tem, row - tems->a_params[0], col,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_mv_cursor(tem, row - tem->tvs_params[0], col,
credp, called_from);
break;
case 'd': /* VPA - vertical position absolute */
- tem_setparam(tem, 1, 1);
- tem_mv_cursor(tem, tems->a_params[0] - 1, col,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_mv_cursor(tem, tem->tvs_params[0] - 1, col,
credp, called_from);
break;
case 'e': /* VPR - vertical position relative */
case 'B': /* cursor down */
- tem_setparam(tem, 1, 1);
- tem_mv_cursor(tem, row + tems->a_params[0], col,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_mv_cursor(tem, row + tem->tvs_params[0], col,
credp, called_from);
break;
case 'a': /* HPR - horizontal position relative */
case 'C': /* cursor right */
- tem_setparam(tem, 1, 1);
- tem_mv_cursor(tem, row, col + tems->a_params[0],
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_mv_cursor(tem, row, col + tem->tvs_params[0],
credp, called_from);
break;
case '`': /* HPA - horizontal position absolute */
- tem_setparam(tem, 1, 1);
- tem_mv_cursor(tem, row, tems->a_params[0] - 1,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
credp, called_from);
break;
case 'D': /* cursor left */
- tem_setparam(tem, 1, 1);
- tem_mv_cursor(tem, row, col - tems->a_params[0],
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_mv_cursor(tem, row, col - tem->tvs_params[0],
credp, called_from);
break;
case 'E': /* CNL cursor next line */
- tem_setparam(tem, 1, 1);
- tem_mv_cursor(tem, row + tems->a_params[0], 0,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_mv_cursor(tem, row + tem->tvs_params[0], 0,
credp, called_from);
break;
case 'F': /* CPL cursor previous line */
- tem_setparam(tem, 1, 1);
- tem_mv_cursor(tem, row - tems->a_params[0], 0,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_mv_cursor(tem, row - tem->tvs_params[0], 0,
credp, called_from);
break;
case 'G': /* cursor horizontal position */
- tem_setparam(tem, 1, 1);
- tem_mv_cursor(tem, row, tems->a_params[0] - 1,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
credp, called_from);
break;
case 'g': /* clear tabs */
- tem_setparam(tem, 1, 0);
- tem_clear_tabs(tem, tems->a_params[0]);
+ tem_safe_setparam(tem, 1, 0);
+ tem_safe_clear_tabs(tem, tem->tvs_params[0]);
break;
case 'f': /* HVP Horizontal and Vertical Position */
case 'H': /* CUP position cursor */
- tem_setparam(tem, 2, 1);
- tem_mv_cursor(tem,
- tems->a_params[0] - 1,
- tems->a_params[1] - 1,
+ tem_safe_setparam(tem, 2, 1);
+ tem_safe_mv_cursor(tem,
+ tem->tvs_params[0] - 1,
+ tem->tvs_params[1] - 1,
credp, called_from);
break;
@@ -604,24 +638,24 @@ tem_chkparam(
break;
case 'J': /* ED - Erase in Display */
- tem_send_data(tem, credp, called_from);
- tem_setparam(tem, 1, 0);
- switch (tems->a_params[0]) {
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_setparam(tem, 1, 0);
+ switch (tem->tvs_params[0]) {
case 0:
/* erase cursor to end of screen */
/* FIRST erase cursor to end of line */
- tem_clear_chars(tem,
- tems->a_c_dimension.width -
- tems->a_c_cursor.col,
- tems->a_c_cursor.row,
- tems->a_c_cursor.col, credp, called_from);
+ tem_safe_clear_chars(tem,
+ tems.ts_c_dimension.width -
+ tem->tvs_c_cursor.col,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col, credp, called_from);
/* THEN erase lines below the cursor */
- for (row = tems->a_c_cursor.row + 1;
- row < tems->a_c_dimension.height;
+ for (row = tem->tvs_c_cursor.row + 1;
+ row < tems.ts_c_dimension.height;
row++) {
- tem_clear_chars(tem,
- tems->a_c_dimension.width,
+ tem_safe_clear_chars(tem,
+ tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
break;
@@ -630,26 +664,26 @@ tem_chkparam(
/* erase beginning of screen to cursor */
/* FIRST erase lines above the cursor */
for (row = 0;
- row < tems->a_c_cursor.row;
+ row < tem->tvs_c_cursor.row;
row++) {
- tem_clear_chars(tem,
- tems->a_c_dimension.width,
+ tem_safe_clear_chars(tem,
+ tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
/* THEN erase beginning of line to cursor */
- tem_clear_chars(tem,
- tems->a_c_cursor.col + 1,
- tems->a_c_cursor.row,
+ tem_safe_clear_chars(tem,
+ tem->tvs_c_cursor.col + 1,
+ tem->tvs_c_cursor.row,
0, credp, called_from);
break;
case 2:
/* erase whole screen */
for (row = 0;
- row < tems->a_c_dimension.height;
+ row < tems.ts_c_dimension.height;
row++) {
- tem_clear_chars(tem,
- tems->a_c_dimension.width,
+ tem_safe_clear_chars(tem,
+ tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
break;
@@ -657,92 +691,92 @@ tem_chkparam(
break;
case 'K': /* EL - Erase in Line */
- tem_send_data(tem, credp, called_from);
- tem_setparam(tem, 1, 0);
- switch (tems->a_params[0]) {
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_setparam(tem, 1, 0);
+ switch (tem->tvs_params[0]) {
case 0:
/* erase cursor to end of line */
- tem_clear_chars(tem,
- (tems->a_c_dimension.width -
- tems->a_c_cursor.col),
- tems->a_c_cursor.row,
- tems->a_c_cursor.col,
+ tem_safe_clear_chars(tem,
+ (tems.ts_c_dimension.width -
+ tem->tvs_c_cursor.col),
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col,
credp, called_from);
break;
case 1:
/* erase beginning of line to cursor */
- tem_clear_chars(tem,
- tems->a_c_cursor.col + 1,
- tems->a_c_cursor.row,
+ tem_safe_clear_chars(tem,
+ tem->tvs_c_cursor.col + 1,
+ tem->tvs_c_cursor.row,
0, credp, called_from);
break;
case 2:
/* erase whole line */
- tem_clear_chars(tem,
- tems->a_c_dimension.width,
- tems->a_c_cursor.row,
+ tem_safe_clear_chars(tem,
+ tems.ts_c_dimension.width,
+ tem->tvs_c_cursor.row,
0, credp, called_from);
break;
}
break;
case 'L': /* insert line */
- tem_send_data(tem, credp, called_from);
- tem_setparam(tem, 1, 1);
- tem_scroll(tem,
- tems->a_c_cursor.row,
- tems->a_c_dimension.height - 1,
- tems->a_params[0], TEM_SCROLL_DOWN,
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_scroll(tem,
+ tem->tvs_c_cursor.row,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_params[0], TEM_SCROLL_DOWN,
credp, called_from);
break;
case 'M': /* delete line */
- tem_send_data(tem, credp, called_from);
- tem_setparam(tem, 1, 1);
- tem_scroll(tem,
- tems->a_c_cursor.row,
- tems->a_c_dimension.height - 1,
- tems->a_params[0], TEM_SCROLL_UP,
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_scroll(tem,
+ tem->tvs_c_cursor.row,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_params[0], TEM_SCROLL_UP,
credp, called_from);
break;
case 'P': /* DCH - delete char */
- tem_setparam(tem, 1, 1);
- tem_shift(tem, tems->a_params[0], TEM_SHIFT_LEFT,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT,
credp, called_from);
break;
case 'S': /* scroll up */
- tem_send_data(tem, credp, called_from);
- tem_setparam(tem, 1, 1);
- tem_scroll(tem, 0,
- tems->a_c_dimension.height - 1,
- tems->a_params[0], TEM_SCROLL_UP,
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_scroll(tem, 0,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_params[0], TEM_SCROLL_UP,
credp, called_from);
break;
case 'T': /* scroll down */
- tem_send_data(tem, credp, called_from);
- tem_setparam(tem, 1, 1);
- tem_scroll(tem, 0,
- tems->a_c_dimension.height - 1,
- tems->a_params[0], TEM_SCROLL_DOWN,
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_scroll(tem, 0,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_params[0], TEM_SCROLL_DOWN,
credp, called_from);
break;
case 'X': /* erase char */
- tem_setparam(tem, 1, 1);
- tem_clear_chars(tem,
- tems->a_params[0],
- tems->a_c_cursor.row,
- tems->a_c_cursor.col,
+ tem_safe_setparam(tem, 1, 1);
+ tem_safe_clear_chars(tem,
+ tem->tvs_params[0],
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col,
credp, called_from);
break;
case 'Z': /* cursor backward tabulation */
- tem_setparam(tem, 1, 1);
+ tem_safe_setparam(tem, 1, 1);
/*
* Rule exception - We do sanity checking here.
@@ -751,14 +785,14 @@ tem_chkparam(
* looping for a long time. There can't be more than one
* tab stop per column, so use that as a limit.
*/
- if (tems->a_params[0] > tems->a_c_dimension.width)
- tems->a_params[0] = tems->a_c_dimension.width;
+ if (tem->tvs_params[0] > tems.ts_c_dimension.width)
+ tem->tvs_params[0] = tems.ts_c_dimension.width;
- for (i = 0; i < tems->a_params[0]; i++)
- tem_back_tab(tem, credp, called_from);
+ for (i = 0; i < tem->tvs_params[0]; i++)
+ tem_safe_back_tab(tem, credp, called_from);
break;
}
- tems->a_state = A_STATE_START;
+ tem->tvs_state = A_STATE_START;
}
@@ -766,38 +800,36 @@ tem_chkparam(
* Gather the parameters of an ANSI escape sequence
*/
static void
-tem_getparams(struct tem *tem, uchar_t ch,
+tem_safe_getparams(struct tem_vt_state *tem, uchar_t ch,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
-
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ MUTEX_HELD(&tem->tvs_lock));
if (ch >= '0' && ch <= '9') {
- tems->a_paramval = ((tems->a_paramval * 10) + (ch - '0'));
- tems->a_gotparam = B_TRUE; /* Remember got parameter */
+ tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
+ tem->tvs_gotparam = B_TRUE; /* Remember got parameter */
return; /* Return immediately */
- } else if (tems->a_state == A_STATE_CSI_EQUAL ||
- tems->a_state == A_STATE_CSI_QMARK) {
- tems->a_state = A_STATE_START;
+ } else if (tem->tvs_state == A_STATE_CSI_EQUAL ||
+ tem->tvs_state == A_STATE_CSI_QMARK) {
+ tem->tvs_state = A_STATE_START;
} else {
- if (tems->a_curparam < TEM_MAXPARAMS) {
- if (tems->a_gotparam) {
+ if (tem->tvs_curparam < TEM_MAXPARAMS) {
+ if (tem->tvs_gotparam) {
/* get the parameter value */
- tems->a_params[tems->a_curparam] =
- tems->a_paramval;
+ tem->tvs_params[tem->tvs_curparam] =
+ tem->tvs_paramval;
}
- tems->a_curparam++;
+ tem->tvs_curparam++;
}
if (ch == ';') {
/* Restart parameter search */
- tems->a_gotparam = B_FALSE;
- tems->a_paramval = 0; /* No parame value yet */
+ tem->tvs_gotparam = B_FALSE;
+ tem->tvs_paramval = 0; /* No parame value yet */
} else {
/* Handle escape sequence */
- tem_chkparam(tem, ch, credp, called_from);
+ tem_safe_chkparam(tem, ch, credp, called_from);
}
}
}
@@ -808,64 +840,63 @@ tem_getparams(struct tem *tem, uchar_t ch,
*/
static void
-tem_outch(struct tem *tem, uchar_t ch,
+tem_safe_outch(struct tem_vt_state *tem, uchar_t ch,
cred_t *credp, enum called_from called_from)
{
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
/* buffer up the character until later */
- tem->state->a_outbuf[tem->state->a_outindex++] = ch;
- tem->state->a_c_cursor.col++;
- if (tem->state->a_c_cursor.col >= tem->state->a_c_dimension.width) {
- tem_send_data(tem, credp, called_from);
- tem_new_line(tem, credp, called_from);
+ tem->tvs_outbuf[tem->tvs_outindex++] = ch;
+ tem->tvs_c_cursor.col++;
+ if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
+ tem_safe_send_data(tem, credp, called_from);
+ tem_safe_new_line(tem, credp, called_from);
}
}
static void
-tem_new_line(struct tem *tem,
+tem_safe_new_line(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
- tem_cr(tem);
- tem_lf(tem, credp, called_from);
+ tem_safe_cr(tem);
+ tem_safe_lf(tem, credp, called_from);
}
static void
-tem_cr(struct tem *tem)
+tem_safe_cr(struct tem_vt_state *tem)
{
- tem->state->a_c_cursor.col = 0;
- tem_align_cursor(tem);
+ tem->tvs_c_cursor.col = 0;
+ tem_safe_align_cursor(tem);
}
static void
-tem_lf(struct tem *tem,
+tem_safe_lf(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int row;
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ MUTEX_HELD(&tem->tvs_lock));
/*
* Sanity checking notes:
* . a_nscroll was validated when it was set.
- * . Regardless of that, tem_scroll and tem_mv_cursor will prevent
- * anything bad from happening.
+ * . Regardless of that, tem_safe_scroll and tem_safe_mv_cursor
+ * will prevent anything bad from happening.
*/
- row = tems->a_c_cursor.row + 1;
+ row = tem->tvs_c_cursor.row + 1;
- if (row >= tems->a_c_dimension.height) {
- if (tems->a_nscroll != 0) {
- tem_scroll(tem, 0,
- tems->a_c_dimension.height - 1,
- tems->a_nscroll, TEM_SCROLL_UP,
+ if (row >= tems.ts_c_dimension.height) {
+ if (tem->tvs_nscroll != 0) {
+ tem_safe_scroll(tem, 0,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_nscroll, TEM_SCROLL_UP,
credp, called_from);
- row = tems->a_c_dimension.height -
- tems->a_nscroll;
+ row = tems.ts_c_dimension.height -
+ tem->tvs_nscroll;
} else { /* no scroll */
/*
* implement Esc[#r when # is zero. This means no
@@ -876,61 +907,58 @@ tem_lf(struct tem *tem,
}
}
- tem_mv_cursor(tem, row, tems->a_c_cursor.col,
+ tem_safe_mv_cursor(tem, row, tem->tvs_c_cursor.col,
credp, called_from);
- if (tems->a_nscroll == 0) {
+ if (tem->tvs_nscroll == 0) {
/* erase rest of cursor line */
- tem_clear_chars(tem,
- tems->a_c_dimension.width -
- tems->a_c_cursor.col,
- tems->a_c_cursor.row,
- tems->a_c_cursor.col,
+ tem_safe_clear_chars(tem,
+ tems.ts_c_dimension.width -
+ tem->tvs_c_cursor.col,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col,
credp, called_from);
}
- tem_align_cursor(tem);
+ tem_safe_align_cursor(tem);
}
static void
-tem_send_data(struct tem *tem, cred_t *credp,
+tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
text_color_t fg_color;
text_color_t bg_color;
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ MUTEX_HELD(&tem->tvs_lock));
- if (tems->a_outindex != 0) {
+ if (tem->tvs_outindex == 0) {
+ tem_safe_align_cursor(tem);
+ return;
+ }
- if (tems->a_flags & TEM_ATTR_REVERSE) {
- fg_color = ansi_fg_to_solaris(tem,
- tems->bg_color);
- bg_color = ansi_bg_to_solaris(tem,
- tems->fg_color);
- } else {
- fg_color = ansi_fg_to_solaris(tem,
- tems->fg_color);
- bg_color = ansi_bg_to_solaris(tem,
- tems->bg_color);
- }
+ tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_REVERSE);
+ tem_safe_virtual_display(tem,
+ tem->tvs_outbuf, tem->tvs_outindex,
+ tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
+ fg_color, bg_color);
+ if (tem->tvs_isactive) {
/*
* Call the primitive to render this data.
*/
- (*tems->in_fp.f_display)(tem,
- tems->a_outbuf,
- tems->a_outindex,
- tems->a_s_cursor.row,
- tems->a_s_cursor.col,
+ tem_safe_callback_display(tem,
+ tem->tvs_outbuf, tem->tvs_outindex,
+ tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
fg_color, bg_color,
credp, called_from);
- tems->a_outindex = 0;
}
- tem_align_cursor(tem);
+
+ tem->tvs_outindex = 0;
+
+ tem_safe_align_cursor(tem);
}
@@ -939,52 +967,51 @@ tem_send_data(struct tem *tem, cred_t *credp,
* point for the buffered data in a_outbuf. There shouldn't be any data
* buffered yet.
*/
-void
-tem_align_cursor(struct tem *tem)
+static void
+tem_safe_align_cursor(struct tem_vt_state *tem)
{
- tem->state->a_s_cursor.row = tem->state->a_c_cursor.row;
- tem->state->a_s_cursor.col = tem->state->a_c_cursor.col;
+ tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
+ tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
}
-
-
/*
* State machine parser based on the current state and character input
* major terminations are to control character or normal character
*/
static void
-tem_parse(struct tem *tem, uchar_t ch,
+tem_safe_parse(struct tem_vt_state *tem, uchar_t ch,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int i;
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ MUTEX_HELD(&tem->tvs_lock));
- if (tems->a_state == A_STATE_START) { /* Normal state? */
- if (ch == A_CSI || ch == A_ESC || ch < ' ') /* Control? */
- tem_control(tem, ch, credp, called_from);
- else
+ if (tem->tvs_state == A_STATE_START) { /* Normal state? */
+ if (ch == A_CSI || ch == A_ESC || ch < ' ') {
+ /* Control */
+ tem_safe_control(tem, ch, credp, called_from);
+ } else {
/* Display */
- tem_outch(tem, ch, credp, called_from);
+ tem_safe_outch(tem, ch, credp, called_from);
+ }
return;
}
/* In <ESC> sequence */
- if (tems->a_state != A_STATE_ESC) { /* Need to get parameters? */
- if (tems->a_state != A_STATE_CSI) {
- tem_getparams(tem, ch, credp, called_from);
+ if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */
+ if (tem->tvs_state != A_STATE_CSI) {
+ tem_safe_getparams(tem, ch, credp, called_from);
return;
}
switch (ch) {
case '?':
- tems->a_state = A_STATE_CSI_QMARK;
+ tem->tvs_state = A_STATE_CSI_QMARK;
return;
case '=':
- tems->a_state = A_STATE_CSI_EQUAL;
+ tem->tvs_state = A_STATE_CSI_EQUAL;
return;
case 's':
/*
@@ -1003,120 +1030,120 @@ tem_parse(struct tem *tem, uchar_t ch,
/*
* Original code
- * tems->a_r_cursor.row = tems->a_c_cursor.row;
- * tems->a_r_cursor.col = tems->a_c_cursor.col;
- * tems->a_state = A_STATE_START;
+ * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
+ * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
+ * tem->tvs_state = A_STATE_START;
*/
- tems->a_state = A_STATE_START;
+ tem->tvs_state = A_STATE_START;
return;
case 'u':
- tem_mv_cursor(tem, tems->a_r_cursor.row,
- tems->a_r_cursor.col, credp, called_from);
- tems->a_state = A_STATE_START;
+ tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
+ tem->tvs_r_cursor.col, credp, called_from);
+ tem->tvs_state = A_STATE_START;
return;
case 'p': /* sunbow */
- tem_send_data(tem, credp, called_from);
+ tem_safe_send_data(tem, credp, called_from);
/*
* Don't set anything if we are
* already as we want to be.
*/
- if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) {
- tems->a_flags &= ~TEM_ATTR_SCREEN_REVERSE;
+ if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
+ tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
/*
* If we have switched the characters to be the
* inverse from the screen, then switch them as
* well to keep them the inverse of the screen.
*/
- if (tems->a_flags & TEM_ATTR_REVERSE) {
- tems->a_flags &= ~TEM_ATTR_REVERSE;
- } else {
- tems->a_flags |= TEM_ATTR_REVERSE;
- }
+ if (tem->tvs_flags & TEM_ATTR_REVERSE)
+ tem->tvs_flags &= ~TEM_ATTR_REVERSE;
+ else
+ tem->tvs_flags |= TEM_ATTR_REVERSE;
}
- tem_cls(tem, credp, called_from);
- tems->a_state = A_STATE_START;
+ tem_safe_cls(tem, credp, called_from);
+ tem->tvs_state = A_STATE_START;
return;
case 'q': /* sunwob */
- tem_send_data(tem, credp, called_from);
+ tem_safe_send_data(tem, credp, called_from);
/*
* Don't set anything if we are
* already where as we want to be.
*/
- if (!(tems->a_flags & TEM_ATTR_SCREEN_REVERSE)) {
- tems->a_flags |= TEM_ATTR_SCREEN_REVERSE;
+ if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
+ tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
/*
* If we have switched the characters to be the
* inverse from the screen, then switch them as
* well to keep them the inverse of the screen.
*/
- if (!(tems->a_flags & TEM_ATTR_REVERSE)) {
- tems->a_flags |= TEM_ATTR_REVERSE;
- } else {
- tems->a_flags &= ~TEM_ATTR_REVERSE;
- }
+ if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
+ tem->tvs_flags |= TEM_ATTR_REVERSE;
+ else
+ tem->tvs_flags &= ~TEM_ATTR_REVERSE;
}
- tem_cls(tem, credp, called_from);
- tems->a_state = A_STATE_START;
+ tem_safe_cls(tem, credp, called_from);
+ tem->tvs_state = A_STATE_START;
return;
case 'r': /* sunscrl */
/*
* Rule exception: check for validity here.
*/
- tems->a_nscroll = tems->a_paramval;
- if (tems->a_nscroll > tems->a_c_dimension.height)
- tems->a_nscroll = tems->a_c_dimension.height;
- if (tems->a_nscroll < 0)
- tems->a_nscroll = 1;
- tems->a_state = A_STATE_START;
+ tem->tvs_nscroll = tem->tvs_paramval;
+ if (tem->tvs_nscroll > tems.ts_c_dimension.height)
+ tem->tvs_nscroll = tems.ts_c_dimension.height;
+ if (tem->tvs_nscroll < 0)
+ tem->tvs_nscroll = 1;
+ tem->tvs_state = A_STATE_START;
return;
default:
- tem_getparams(tem, ch, credp, called_from);
+ tem_safe_getparams(tem, ch, credp, called_from);
return;
}
}
/* Previous char was <ESC> */
if (ch == '[') {
- tems->a_curparam = 0;
- tems->a_paramval = 0;
- tems->a_gotparam = B_FALSE;
+ tem->tvs_curparam = 0;
+ tem->tvs_paramval = 0;
+ tem->tvs_gotparam = B_FALSE;
/* clear the parameters */
for (i = 0; i < TEM_MAXPARAMS; i++)
- tems->a_params[i] = -1;
- tems->a_state = A_STATE_CSI;
+ tem->tvs_params[i] = -1;
+ tem->tvs_state = A_STATE_CSI;
} else if (ch == 'Q') { /* <ESC>Q ? */
- tems->a_state = A_STATE_START;
+ tem->tvs_state = A_STATE_START;
} else if (ch == 'C') { /* <ESC>C ? */
- tems->a_state = A_STATE_START;
+ tem->tvs_state = A_STATE_START;
} else {
- tems->a_state = A_STATE_START;
- if (ch == 'c')
+ tem->tvs_state = A_STATE_START;
+ if (ch == 'c') {
/* ESC c resets display */
- tem_reset_display(tem, credp, called_from, 1, NULL);
- else if (ch == 'H')
+ tem_safe_reset_display(tem, credp, called_from,
+ B_TRUE, B_TRUE);
+ } else if (ch == 'H') {
/* ESC H sets a tab */
- tem_set_tab(tem);
- else if (ch == '7') {
+ tem_safe_set_tab(tem);
+ } else if (ch == '7') {
/* ESC 7 Save Cursor position */
- tems->a_r_cursor.row = tems->a_c_cursor.row;
- tems->a_r_cursor.col = tems->a_c_cursor.col;
- } else if (ch == '8')
+ tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
+ tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
+ } else if (ch == '8') {
/* ESC 8 Restore Cursor position */
- tem_mv_cursor(tem, tems->a_r_cursor.row,
- tems->a_r_cursor.col, credp, called_from);
+ tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
+ tem->tvs_r_cursor.col, credp, called_from);
/* check for control chars */
- else if (ch < ' ')
- tem_control(tem, ch, credp, called_from);
- else
- tem_outch(tem, ch, credp, called_from);
+ } else if (ch < ' ') {
+ tem_safe_control(tem, ch, credp, called_from);
+ } else {
+ tem_safe_outch(tem, ch, credp, called_from);
+ }
}
}
/* ARGSUSED */
static void
-tem_bell(struct tem *tem, enum called_from called_from)
+tem_safe_bell(struct tem_vt_state *tem, enum called_from called_from)
{
if (called_from == CALLED_FROM_STANDALONE)
(void) beep_polled(BEEP_CONSOLE);
@@ -1126,15 +1153,15 @@ tem_bell(struct tem *tem, enum called_from called_from)
static void
-tem_scroll(tem_t *tem, int start, int end, int count, int direction,
+tem_safe_scroll(struct tem_vt_state *tem, int start, int end, int count,
+ int direction,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int row;
int lines_affected;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
lines_affected = end - start + 1;
if (count > lines_affected)
@@ -1145,25 +1172,25 @@ tem_scroll(tem_t *tem, int start, int end, int count, int direction,
switch (direction) {
case TEM_SCROLL_UP:
if (count < lines_affected) {
- tem_copy_area(tem, 0, start + count,
- tems->a_c_dimension.width - 1, end,
+ tem_safe_copy_area(tem, 0, start + count,
+ tems.ts_c_dimension.width - 1, end,
0, start, credp, called_from);
}
for (row = (end - count) + 1; row <= end; row++) {
- tem_clear_chars(tem, tems->a_c_dimension.width,
+ tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
break;
case TEM_SCROLL_DOWN:
if (count < lines_affected) {
- tem_copy_area(tem, 0, start,
- tems->a_c_dimension.width - 1,
+ tem_safe_copy_area(tem, 0, start,
+ tems.ts_c_dimension.width - 1,
end - count, 0, start + count,
credp, called_from);
}
for (row = start; row < start + count; row++) {
- tem_clear_chars(tem, tems->a_c_dimension.width,
+ tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
break;
@@ -1171,28 +1198,27 @@ tem_scroll(tem_t *tem, int start, int end, int count, int direction,
}
static void
-tem_copy_area(struct tem *tem,
+tem_safe_copy_area(struct tem_vt_state *tem,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int rows;
int cols;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
if (s_col < 0 || s_row < 0 ||
e_col < 0 || e_row < 0 ||
t_col < 0 || t_row < 0 ||
- s_col >= tems->a_c_dimension.width ||
- e_col >= tems->a_c_dimension.width ||
- t_col >= tems->a_c_dimension.width ||
- s_row >= tems->a_c_dimension.height ||
- e_row >= tems->a_c_dimension.height ||
- t_row >= tems->a_c_dimension.height)
+ s_col >= tems.ts_c_dimension.width ||
+ e_col >= tems.ts_c_dimension.width ||
+ t_col >= tems.ts_c_dimension.width ||
+ s_row >= tems.ts_c_dimension.height ||
+ e_row >= tems.ts_c_dimension.height ||
+ t_row >= tems.ts_c_dimension.height)
return;
if (s_row > e_row || s_col > e_col)
@@ -1200,25 +1226,31 @@ tem_copy_area(struct tem *tem,
rows = e_row - s_row + 1;
cols = e_col - s_col + 1;
- if (t_row + rows > tems->a_c_dimension.height ||
- t_col + cols > tems->a_c_dimension.width)
+ if (t_row + rows > tems.ts_c_dimension.height ||
+ t_col + cols > tems.ts_c_dimension.width)
+ return;
+
+ tem_safe_virtual_copy(tem,
+ s_col, s_row,
+ e_col, e_row,
+ t_col, t_row);
+
+ if (!tem->tvs_isactive)
return;
- (*tems->in_fp.f_copy)(tem, s_col, s_row,
+ tem_safe_callback_copy(tem, s_col, s_row,
e_col, e_row, t_col, t_row, credp, called_from);
}
static void
-tem_clear_chars(struct tem *tem, int count, screen_pos_t row,
+tem_safe_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
screen_pos_t col, cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
-
- if (row < 0 || row >= tems->a_c_dimension.height ||
- col < 0 || col >= tems->a_c_dimension.width ||
+ if (row < 0 || row >= tems.ts_c_dimension.height ||
+ col < 0 || col >= tems.ts_c_dimension.width ||
count < 0)
return;
@@ -1226,30 +1258,39 @@ tem_clear_chars(struct tem *tem, int count, screen_pos_t row,
* Note that very large values of "count" could cause col+count
* to overflow, so we check "count" independently.
*/
- if (count > tems->a_c_dimension.width ||
- col + count > tems->a_c_dimension.width)
- count = tems->a_c_dimension.width - col;
+ if (count > tems.ts_c_dimension.width ||
+ col + count > tems.ts_c_dimension.width)
+ count = tems.ts_c_dimension.width - col;
- (*tems->in_fp.f_cls)(tem, count, row, col, credp, called_from);
+ tem_safe_virtual_cls(tem, count, row, col);
+
+ if (!tem->tvs_isactive)
+ return;
+
+ tem_safe_callback_cls(tem, count, row, col, credp, called_from);
}
+/*ARGSUSED*/
void
-tem_text_display(struct tem *tem, uchar_t *string,
+tem_safe_text_display(struct tem_vt_state *tem, uchar_t *string,
int count, screen_pos_t row, screen_pos_t col,
text_color_t fg_color, text_color_t bg_color,
cred_t *credp, enum called_from called_from)
{
struct vis_consdisplay da;
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
+
da.data = string;
- da.width = count;
+ da.width = (screen_size_t)count;
da.row = row;
da.col = col;
da.fg_color = fg_color;
da.bg_color = bg_color;
- tem_display(tem, &da, credp, called_from);
+ tems_safe_display(&da, credp, called_from);
}
/*
@@ -1262,25 +1303,33 @@ tem_text_display(struct tem *tem, uchar_t *string,
*
* This function is unused now.
*/
-void
-tem_image_display(struct tem *tem, uchar_t *image,
+/*ARGSUSED*/
+static void
+tem_safe_image_display(struct tem_vt_state *tem, uchar_t *image,
int height, int width, screen_pos_t row, screen_pos_t col,
cred_t *credp, enum called_from called_from)
{
struct vis_consdisplay da;
+ mutex_enter(&tems.ts_lock);
+ mutex_enter(&tem->tvs_lock);
+
da.data = image;
- da.width = width;
- da.height = height;
+ da.width = (screen_size_t)width;
+ da.height = (screen_size_t)height;
da.row = row;
da.col = col;
- tem_display(tem, &da, credp, called_from);
+ tems_safe_display(&da, credp, called_from);
+
+ mutex_exit(&tem->tvs_lock);
+ mutex_exit(&tems.ts_lock);
}
+/*ARGSUSED*/
void
-tem_text_copy(struct tem *tem,
+tem_safe_text_copy(struct tem_vt_state *tem,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row,
@@ -1288,6 +1337,9 @@ tem_text_copy(struct tem *tem,
{
struct vis_conscopy da;
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
+
da.s_row = s_row;
da.s_col = s_col;
da.e_row = e_row;
@@ -1295,131 +1347,158 @@ tem_text_copy(struct tem *tem,
da.t_row = t_row;
da.t_col = t_col;
- tem_copy(tem, &da, credp, called_from);
+ tems_safe_copy(&da, credp, called_from);
}
void
-tem_text_cls(struct tem *tem,
+tem_safe_text_cls(struct tem_vt_state *tem,
int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
enum called_from called_from)
{
struct vis_consdisplay da;
- da.data = tem->state->a_blank_line;
- da.width = count;
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
+
+ da.data = tems.ts_blank_line;
+ da.width = (screen_size_t)count;
da.row = row;
da.col = col;
- tem_get_color(tem, &da.fg_color, &da.bg_color);
- tem_display(tem, &da, credp, called_from);
+ tem_safe_get_color(tem, &da.fg_color, &da.bg_color,
+ TEM_ATTR_SCREEN_REVERSE);
+ tems_safe_display(&da, credp, called_from);
}
void
-tem_pix_display(struct tem *tem,
+tem_safe_pix_display(struct tem_vt_state *tem,
uchar_t *string, int count,
screen_pos_t row, screen_pos_t col,
text_color_t fg_color, text_color_t bg_color,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
struct vis_consdisplay da;
int i;
- da.data = (uchar_t *)tems->a_pix_data;
- da.width = tems->a_font.width;
- da.height = tems->a_font.height;
- da.row = (row * da.height) + tems->a_p_offset.y;
- da.col = (col * da.width) + tems->a_p_offset.x;
+
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
+
+ da.data = (uchar_t *)tem->tvs_pix_data;
+ da.width = tems.ts_font.width;
+ da.height = tems.ts_font.height;
+ da.row = (row * da.height) + tems.ts_p_offset.y;
+ da.col = (col * da.width) + tems.ts_p_offset.x;
for (i = 0; i < count; i++) {
- BIT_TO_PIX(tem, string[i], fg_color, bg_color);
- tem_display(tem, &da, credp, called_from);
+ tem_safe_callback_bit2pix(tem, string[i], fg_color, bg_color);
+ tems_safe_display(&da, credp, called_from);
da.col += da.width;
}
}
void
-tem_pix_copy(struct tem *tem,
+tem_safe_pix_copy(struct tem_vt_state *tem,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row,
cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
struct vis_conscopy ma;
static boolean_t need_clear = B_TRUE;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- if (need_clear && tems->first_line > 0) {
+ if (need_clear && tem->tvs_first_line > 0) {
/*
* Clear OBP output above our kernel console term
* when our kernel console term begins to scroll up,
* we hope it is user friendly.
- * (Also see comments on tem_pix_clear_prom_output)
+ * (Also see comments on tem_safe_pix_clear_prom_output)
*
* This is only one time call.
*/
- tem_pix_clear_prom_output(tem, credp, called_from);
+ tem_safe_pix_clear_prom_output(tem, credp, called_from);
}
need_clear = B_FALSE;
- ma.s_row = s_row * tems->a_font.height + tems->a_p_offset.y;
- ma.e_row = (e_row + 1) * tems->a_font.height + tems->a_p_offset.y - 1;
- ma.t_row = t_row * tems->a_font.height + tems->a_p_offset.y;
+ ma.s_row = s_row * tems.ts_font.height + tems.ts_p_offset.y;
+ ma.e_row = (e_row + 1) * tems.ts_font.height + tems.ts_p_offset.y - 1;
+ ma.t_row = t_row * tems.ts_font.height + tems.ts_p_offset.y;
/*
* Check if we're in process of clearing OBP's columns area,
* which only happens when term scrolls up a whole line.
*/
- if (tems->first_line > 0 && t_row < s_row && t_col == 0 &&
- e_col == tems->a_c_dimension.width - 1) {
+ if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
+ e_col == tems.ts_c_dimension.width - 1) {
/*
* We need to clear OBP's columns area outside our kernel
* console term. So that we set ma.e_col to entire row here.
*/
- ma.s_col = s_col * tems->a_font.width;
- ma.e_col = tems->a_p_dimension.width - 1;
+ ma.s_col = s_col * tems.ts_font.width;
+ ma.e_col = tems.ts_p_dimension.width - 1;
- ma.t_col = t_col * tems->a_font.width;
+ ma.t_col = t_col * tems.ts_font.width;
} else {
- ma.s_col = s_col * tems->a_font.width + tems->a_p_offset.x;
- ma.e_col = (e_col + 1) * tems->a_font.width +
- tems->a_p_offset.x - 1;
- ma.t_col = t_col * tems->a_font.width + tems->a_p_offset.x;
+ ma.s_col = s_col * tems.ts_font.width + tems.ts_p_offset.x;
+ ma.e_col = (e_col + 1) * tems.ts_font.width +
+ tems.ts_p_offset.x - 1;
+ ma.t_col = t_col * tems.ts_font.width + tems.ts_p_offset.x;
}
- tem_copy(tem, &ma, credp, called_from);
+ tems_safe_copy(&ma, credp, called_from);
- if (tems->first_line > 0 && t_row < s_row) {
+ if (tem->tvs_first_line > 0 && t_row < s_row) {
/* We have scrolled up (s_row - t_row) rows. */
- tems->first_line -= (s_row - t_row);
- if (tems->first_line <= 0) {
+ tem->tvs_first_line -= (s_row - t_row);
+ if (tem->tvs_first_line <= 0) {
/* All OBP rows have been cleared. */
- tems->first_line = 0;
+ tem->tvs_first_line = 0;
}
}
}
+void
+tem_safe_pix_bit2pix(struct tem_vt_state *tem, unsigned char c,
+ unsigned char fg, unsigned char bg)
+{
+ void (*fp)(struct tem_vt_state *, unsigned char,
+ unsigned char, unsigned char);
+
+ switch (tems.ts_pdepth) {
+ case 4:
+ fp = bit_to_pix4;
+ break;
+ case 8:
+ fp = bit_to_pix8;
+ break;
+ case 24:
+ case 32:
+ fp = bit_to_pix24;
+ }
+
+ fp(tem, c, fg, bg);
+}
+
+
/*
* This function only clears count of columns in one row
*/
void
-tem_pix_cls(struct tem *tem, int count,
+tem_safe_pix_cls(struct tem_vt_state *tem, int count,
screen_pos_t row, screen_pos_t col, cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
-
- tem_pix_cls_range(tem, row, 1, tems->a_p_offset.y,
- col, count, tems->a_p_offset.x, B_FALSE, credp, called_from);
+ tem_safe_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
+ col, count, tems.ts_p_offset.x, B_FALSE, credp, called_from);
}
/*
@@ -1446,182 +1525,182 @@ tem_pix_cls(struct tem *tem, int count,
* console term.
*/
static void
-tem_pix_clear_prom_output(struct tem *tem, cred_t *credp,
+tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int nrows, ncols, width, height;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- width = tems->a_font.width;
- height = tems->a_font.height;
+ width = tems.ts_font.width;
+ height = tems.ts_font.height;
- nrows = (tems->a_p_offset.y + (height - 1))/ height;
- ncols = (tems->a_p_dimension.width + (width - 1))/ width;
+ nrows = (tems.ts_p_offset.y + (height - 1))/ height;
+ ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
- tem_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
+ tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
B_FALSE, credp, called_from);
}
/*
- * clear the whole screen for pixel mode
+ * clear the whole screen for pixel mode, just clear the
+ * physical screen.
*/
-static void
-tem_pix_clear_entire_screen(struct tem *tem, cred_t *credp,
+void
+tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int nrows, ncols, width, height;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- width = tems->a_font.width;
- height = tems->a_font.height;
+ width = tems.ts_font.width;
+ height = tems.ts_font.height;
- nrows = (tems->a_p_dimension.height + (height - 1))/ height;
- ncols = (tems->a_p_dimension.width + (width - 1))/ width;
+ nrows = (tems.ts_p_dimension.height + (height - 1))/ height;
+ ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
- tem_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
+ tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
B_FALSE, credp, called_from);
- tems->a_c_cursor.row = 0;
- tems->a_c_cursor.col = 0;
- tem_align_cursor(tem);
-
/*
* Since the whole screen is cleared, we don't need
* to clear OBP output later.
*/
- if (tems->first_line > 0) {
- tems->first_line = 0;
- }
+ if (tem->tvs_first_line > 0)
+ tem->tvs_first_line = 0;
}
/*
- * clear the whole screen
+ * clear the whole screen, including the virtual screen buffer,
+ * and reset the cursor to start point.
*/
static void
-tem_cls(struct tem *tem,
+tem_safe_cls(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int row;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- if (tems->display_mode == VIS_TEXT) {
- for (row = 0; row < tems->a_c_dimension.height; row++) {
- tem_clear_chars(tem, tems->a_c_dimension.width,
+ if (tems.ts_display_mode == VIS_TEXT) {
+ for (row = 0; row < tems.ts_c_dimension.height; row++) {
+ tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
- tems->a_c_cursor.row = 0;
- tems->a_c_cursor.col = 0;
- tem_align_cursor(tem);
+ tem->tvs_c_cursor.row = 0;
+ tem->tvs_c_cursor.col = 0;
+ tem_safe_align_cursor(tem);
return;
}
- ASSERT(tems->display_mode == VIS_PIXEL);
+ ASSERT(tems.ts_display_mode == VIS_PIXEL);
+
+ for (row = 0; row < tems.ts_c_dimension.height; row++) {
+ tem_safe_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
+ }
+ tem->tvs_c_cursor.row = 0;
+ tem->tvs_c_cursor.col = 0;
+ tem_safe_align_cursor(tem);
+
+ if (!tem->tvs_isactive)
+ return;
- tem_pix_clear_entire_screen(tem, credp, called_from);
+ tem_safe_pix_clear_entire_screen(tem, credp, called_from);
}
static void
-tem_back_tab(struct tem *tem,
+tem_safe_back_tab(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int i;
screen_pos_t tabstop;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
tabstop = 0;
- for (i = tems->a_ntabs - 1; i >= 0; i--) {
- if (tems->a_tabs[i] < tems->a_c_cursor.col) {
- tabstop = tems->a_tabs[i];
+ for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
+ if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
+ tabstop = tem->tvs_tabs[i];
break;
}
}
- tem_mv_cursor(tem, tems->a_c_cursor.row,
+ tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
tabstop, credp, called_from);
}
static void
-tem_tab(struct tem *tem,
+tem_safe_tab(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int i;
screen_pos_t tabstop;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- tabstop = tems->a_c_dimension.width - 1;
+ tabstop = tems.ts_c_dimension.width - 1;
- for (i = 0; i < tems->a_ntabs; i++) {
- if (tems->a_tabs[i] > tems->a_c_cursor.col) {
- tabstop = tems->a_tabs[i];
+ for (i = 0; i < tem->tvs_ntabs; i++) {
+ if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
+ tabstop = tem->tvs_tabs[i];
break;
}
}
- tem_mv_cursor(tem, tems->a_c_cursor.row,
+ tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
tabstop, credp, called_from);
}
static void
-tem_set_tab(struct tem *tem)
+tem_safe_set_tab(struct tem_vt_state *tem)
{
- struct tem_state *tems = tem->state;
int i;
int j;
- if (tems->a_ntabs == TEM_MAXTAB)
- return;
- if (tems->a_ntabs == 0 ||
- tems->a_tabs[tems->a_ntabs] < tems->a_c_cursor.col) {
- tems->a_tabs[tems->a_ntabs++] = tems->a_c_cursor.col;
+ if (tem->tvs_ntabs == TEM_MAXTAB)
return;
+ if (tem->tvs_ntabs == 0 ||
+ tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
+ tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
+ return;
}
- for (i = 0; i < tems->a_ntabs; i++) {
- if (tems->a_tabs[i] == tems->a_c_cursor.col)
+ for (i = 0; i < tem->tvs_ntabs; i++) {
+ if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
return;
- if (tems->a_tabs[i] > tems->a_c_cursor.col) {
- for (j = tems->a_ntabs - 1; j >= i; j--)
- tems->a_tabs[j+ 1] = tems->a_tabs[j];
- tems->a_tabs[i] = tems->a_c_cursor.col;
- tems->a_ntabs++;
+ if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
+ for (j = tem->tvs_ntabs - 1; j >= i; j--)
+ tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
+ tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
+ tem->tvs_ntabs++;
return;
}
}
}
static void
-tem_clear_tabs(struct tem *tem, int action)
+tem_safe_clear_tabs(struct tem_vt_state *tem, int action)
{
- struct tem_state *tems = tem->state;
int i;
int j;
switch (action) {
case 3: /* clear all tabs */
- tems->a_ntabs = 0;
+ tem->tvs_ntabs = 0;
break;
case 0: /* clr tab at cursor */
- for (i = 0; i < tems->a_ntabs; i++) {
- if (tems->a_tabs[i] == tems->a_c_cursor.col) {
- tems->a_ntabs--;
- for (j = i; j < tems->a_ntabs; j++)
- tems->a_tabs[j] = tems->a_tabs[j + 1];
+ for (i = 0; i < tem->tvs_ntabs; i++) {
+ if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
+ tem->tvs_ntabs--;
+ for (j = i; j < tem->tvs_ntabs; j++)
+ tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
return;
}
}
@@ -1630,13 +1709,11 @@ tem_clear_tabs(struct tem *tem, int action)
}
static void
-tem_mv_cursor(struct tem *tem, int row, int col,
+tem_safe_mv_cursor(struct tem_vt_state *tem, int row, int col,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
-
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
/*
* Sanity check and bounds enforcement. Out of bounds requests are
@@ -1645,109 +1722,98 @@ tem_mv_cursor(struct tem *tem, int row, int col,
*/
if (row < 0)
row = 0;
- if (row >= tems->a_c_dimension.height)
- row = tems->a_c_dimension.height - 1;
+ if (row >= tems.ts_c_dimension.height)
+ row = tems.ts_c_dimension.height - 1;
if (col < 0)
col = 0;
- if (col >= tems->a_c_dimension.width)
- col = tems->a_c_dimension.width - 1;
+ if (col >= tems.ts_c_dimension.width)
+ col = tems.ts_c_dimension.width - 1;
- tem_send_data(tem, credp, called_from);
- tems->a_c_cursor.row = row;
- tems->a_c_cursor.col = col;
- tem_align_cursor(tem);
+ tem_safe_send_data(tem, credp, called_from);
+ tem->tvs_c_cursor.row = (screen_pos_t)row;
+ tem->tvs_c_cursor.col = (screen_pos_t)col;
+ tem_safe_align_cursor(tem);
}
/* ARGSUSED */
void
-tem_reset_emulator(struct tem *tem,
+tem_safe_reset_emulator(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from,
- tem_color_t *pcolor)
+ boolean_t init_color)
{
- struct tem_state *tems = tem->state;
int j;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
-
- tems->a_c_cursor.row = 0;
- tems->a_c_cursor.col = 0;
- tems->a_r_cursor.row = 0;
- tems->a_r_cursor.col = 0;
- tems->a_s_cursor.row = 0;
- tems->a_s_cursor.col = 0;
- tems->a_outindex = 0;
- tems->a_state = A_STATE_START;
- tems->a_gotparam = B_FALSE;
- tems->a_curparam = 0;
- tems->a_paramval = 0;
- tems->a_nscroll = 1;
-
- if (pcolor != NULL) {
- /* use customized settings */
- tems->fg_color = pcolor->fg_color;
- tems->bg_color = pcolor->bg_color;
- tems->a_flags = pcolor->a_flags;
- } else {
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
+
+ tem->tvs_c_cursor.row = 0;
+ tem->tvs_c_cursor.col = 0;
+ tem->tvs_r_cursor.row = 0;
+ tem->tvs_r_cursor.col = 0;
+ tem->tvs_s_cursor.row = 0;
+ tem->tvs_s_cursor.col = 0;
+ tem->tvs_outindex = 0;
+ tem->tvs_state = A_STATE_START;
+ tem->tvs_gotparam = B_FALSE;
+ tem->tvs_curparam = 0;
+ tem->tvs_paramval = 0;
+ tem->tvs_nscroll = 1;
+
+ if (init_color) {
/* use initial settings */
- tems->fg_color = tem->init_color.fg_color;
- tems->bg_color = tem->init_color.bg_color;
- tems->a_flags = tem->init_color.a_flags;
+ tem->tvs_fg_color = tems.ts_init_color.fg_color;
+ tem->tvs_bg_color = tems.ts_init_color.bg_color;
+ tem->tvs_flags = tems.ts_init_color.a_flags;
}
/*
* set up the initial tab stops
*/
- tems->a_ntabs = 0;
- for (j = 8; j < tems->a_c_dimension.width; j += 8)
- tems->a_tabs[tems->a_ntabs++] = (screen_pos_t)j;
+ tem->tvs_ntabs = 0;
+ for (j = 8; j < tems.ts_c_dimension.width; j += 8)
+ tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
for (j = 0; j < TEM_MAXPARAMS; j++)
- tems->a_params[j] = 0;
+ tem->tvs_params[j] = 0;
}
void
-tem_reset_display(struct tem *tem,
- cred_t *credp, enum called_from called_from, int clear_txt,
- tem_color_t *pcolor)
+tem_safe_reset_display(struct tem_vt_state *tem,
+ cred_t *credp, enum called_from called_from,
+ boolean_t clear_txt, boolean_t init_color)
{
- struct tem_state *tems = tem->state;
-
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- tem_reset_emulator(tem, credp, called_from, pcolor);
- tem_reset_colormap(tem, credp, called_from);
+ tem_safe_reset_emulator(tem, credp, called_from, init_color);
if (clear_txt) {
- (*tems->in_fp.f_cursor)(tem,
- VIS_HIDE_CURSOR, credp, called_from);
+ if (tem->tvs_isactive)
+ tem_safe_callback_cursor(tem,
+ VIS_HIDE_CURSOR, credp, called_from);
- tem_cls(tem, credp, called_from);
+ tem_safe_cls(tem, credp, called_from);
- (*tems->in_fp.f_cursor)(tem,
- VIS_DISPLAY_CURSOR, credp, called_from);
+ if (tem->tvs_isactive)
+ tem_safe_callback_cursor(tem,
+ VIS_DISPLAY_CURSOR, credp, called_from);
}
-
- tems->a_initialized = 1;
}
-
static void
-tem_shift(
- struct tem *tem,
+tem_safe_shift(
+ struct tem_vt_state *tem,
int count,
int direction,
cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
int rest_of_line;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- rest_of_line = tems->a_c_dimension.width - tems->a_c_cursor.col;
+ rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
if (count > rest_of_line)
count = rest_of_line;
@@ -1757,87 +1823,84 @@ tem_shift(
switch (direction) {
case TEM_SHIFT_LEFT:
if (count < rest_of_line) {
- tem_copy_area(tem,
- tems->a_c_cursor.col + count,
- tems->a_c_cursor.row,
- tems->a_c_dimension.width - 1,
- tems->a_c_cursor.row,
- tems->a_c_cursor.col,
- tems->a_c_cursor.row,
+ tem_safe_copy_area(tem,
+ tem->tvs_c_cursor.col + count,
+ tem->tvs_c_cursor.row,
+ tems.ts_c_dimension.width - 1,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col,
+ tem->tvs_c_cursor.row,
credp, called_from);
}
- tem_clear_chars(tem, count, tems->a_c_cursor.row,
- (tems->a_c_dimension.width - count), credp,
+ tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
+ (tems.ts_c_dimension.width - count), credp,
called_from);
break;
case TEM_SHIFT_RIGHT:
if (count < rest_of_line) {
- tem_copy_area(tem,
- tems->a_c_cursor.col,
- tems->a_c_cursor.row,
- tems->a_c_dimension.width - count - 1,
- tems->a_c_cursor.row,
- tems->a_c_cursor.col + count,
- tems->a_c_cursor.row,
+ tem_safe_copy_area(tem,
+ tem->tvs_c_cursor.col,
+ tem->tvs_c_cursor.row,
+ tems.ts_c_dimension.width - count - 1,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col + count,
+ tem->tvs_c_cursor.row,
credp, called_from);
}
- tem_clear_chars(tem, count, tems->a_c_cursor.row,
- tems->a_c_cursor.col, credp, called_from);
+ tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col, credp, called_from);
break;
}
}
void
-tem_text_cursor(struct tem *tem, short action,
+tem_safe_text_cursor(struct tem_vt_state *tem, short action,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
struct vis_conscursor ca;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
- ca.row = tems->a_c_cursor.row;
- ca.col = tems->a_c_cursor.col;
+ ca.row = tem->tvs_c_cursor.row;
+ ca.col = tem->tvs_c_cursor.col;
ca.action = action;
- tem_cursor(tem, &ca, credp, called_from);
+ tems_safe_cursor(&ca, credp, called_from);
if (action == VIS_GET_CURSOR) {
- tems->a_c_cursor.row = ca.row;
- tems->a_c_cursor.col = ca.col;
+ tem->tvs_c_cursor.row = ca.row;
+ tem->tvs_c_cursor.col = ca.col;
}
}
-
void
-tem_pix_cursor(struct tem *tem, short action,
+tem_safe_pix_cursor(struct tem_vt_state *tem, short action,
cred_t *credp, enum called_from called_from)
{
- struct tem_state *tems = tem->state;
struct vis_conscursor ca;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
-
- ca.row = tems->a_c_cursor.row * tems->a_font.height +
- tems->a_p_offset.y;
- ca.col = tems->a_c_cursor.col * tems->a_font.width +
- tems->a_p_offset.x;
- ca.width = tems->a_font.width;
- ca.height = tems->a_font.height;
- if (tems->a_pdepth == 8 || tems->a_pdepth == 4) {
- if (tems->a_flags & TEM_ATTR_REVERSE) {
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
+
+ ca.row = tem->tvs_c_cursor.row * tems.ts_font.height +
+ tems.ts_p_offset.y;
+ ca.col = tem->tvs_c_cursor.col * tems.ts_font.width +
+ tems.ts_p_offset.x;
+ ca.width = tems.ts_font.width;
+ ca.height = tems.ts_font.height;
+ if (tems.ts_pdepth == 8 || tems.ts_pdepth == 4) {
+ if (tem->tvs_flags & TEM_ATTR_REVERSE) {
ca.fg_color.mono = TEM_TEXT_WHITE;
ca.bg_color.mono = TEM_TEXT_BLACK;
} else {
ca.fg_color.mono = TEM_TEXT_BLACK;
ca.bg_color.mono = TEM_TEXT_WHITE;
}
- } else if (tems->a_pdepth == 24 || tems->a_pdepth == 32) {
- if (tems->a_flags & TEM_ATTR_REVERSE) {
+ } else if (tems.ts_pdepth == 24 || tems.ts_pdepth == 32) {
+ if (tem->tvs_flags & TEM_ATTR_REVERSE) {
ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
@@ -1858,7 +1921,7 @@ tem_pix_cursor(struct tem *tem, short action,
ca.action = action;
- tem_cursor(tem, &ca, credp, called_from);
+ tems_safe_cursor(&ca, credp, called_from);
}
#define BORDER_PIXELS 10
@@ -1916,14 +1979,13 @@ set_font(struct font *f, short *rows, short *cols, short height, short width)
* 00000001 00000001 00000000 00010001.
*/
-void
+static void
bit_to_pix4(
- struct tem *tem,
+ struct tem_vt_state *tem,
uchar_t c,
text_color_t fg_color,
text_color_t bg_color)
{
- struct tem_state *tems = tem->state;
int row;
int byte;
int i;
@@ -1933,12 +1995,12 @@ bit_to_pix4(
int bytes_wide;
uint8_t *dest;
- dest = (uint8_t *)tems->a_pix_data;
+ dest = (uint8_t *)tem->tvs_pix_data;
- cp = tems->a_font.char_ptr[c];
- bytes_wide = (tems->a_font.width + 7) / 8;
+ cp = tems.ts_font.char_ptr[c];
+ bytes_wide = (tems.ts_font.width + 7) / 8;
- for (row = 0; row < tems->a_font.height; row++) {
+ for (row = 0; row < tems.ts_font.height; row++) {
for (byte = 0; byte < bytes_wide; byte++) {
data = *cp++;
for (i = 0; i < 4; i++) {
@@ -1972,14 +2034,13 @@ bit_to_pix4(
* 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
*/
-void
+static void
bit_to_pix8(
- struct tem *tem,
+ struct tem_vt_state *tem,
uchar_t c,
text_color_t fg_color,
text_color_t bg_color)
{
- struct tem_state *tems = tem->state;
int row;
int byte;
int i;
@@ -1990,13 +2051,13 @@ bit_to_pix8(
int bitsleft, nbits;
uint8_t *dest;
- dest = (uint8_t *)tems->a_pix_data;
+ dest = (uint8_t *)tem->tvs_pix_data;
- cp = tems->a_font.char_ptr[c];
- bytes_wide = (tems->a_font.width + 7) / 8;
+ cp = tems.ts_font.char_ptr[c];
+ bytes_wide = (tems.ts_font.width + 7) / 8;
- for (row = 0; row < tems->a_font.height; row++) {
- bitsleft = tems->a_font.width;
+ for (row = 0; row < tems.ts_font.height; row++) {
+ bitsleft = tems.ts_font.width;
for (byte = 0; byte < bytes_wide; byte++) {
data = *cp++;
mask = 0x80;
@@ -2033,14 +2094,13 @@ bit_to_pix8(
*/
typedef uint32_t pixel32_t;
-void
+static void
bit_to_pix24(
- struct tem *tem,
+ struct tem_vt_state *tem,
uchar_t c,
text_color_t fg_color4,
text_color_t bg_color4)
{
- struct tem_state *tems = tem->state;
int row;
int byte;
int i;
@@ -2056,12 +2116,12 @@ bit_to_pix24(
fg_color32 = PIX4TO32(fg_color4);
bg_color32 = PIX4TO32(bg_color4);
- destp = (pixel32_t *)tems->a_pix_data;
- cp = tems->a_font.char_ptr[c];
- bytes_wide = (tems->a_font.width + 7) / 8;
+ destp = (pixel32_t *)tem->tvs_pix_data;
+ cp = tems.ts_font.char_ptr[c];
+ bytes_wide = (tems.ts_font.width + 7) / 8;
- for (row = 0; row < tems->a_font.height; row++) {
- bitsleft = tems->a_font.width;
+ for (row = 0; row < tems.ts_font.height; row++) {
+ bitsleft = tems.ts_font.width;
for (byte = 0; byte < bytes_wide; byte++) {
data = *cp++;
nbits = MIN(8, bitsleft);
@@ -2075,34 +2135,38 @@ bit_to_pix24(
}
/* ARGSUSED */
-text_color_t
-ansi_bg_to_solaris(struct tem *tem, int ansi)
+static text_color_t
+ansi_bg_to_solaris(struct tem_vt_state *tem, int ansi)
{
return (bg_xlate[ansi]);
}
-text_color_t
-ansi_fg_to_solaris(struct tem *tem, int ansi)
+static text_color_t
+ansi_fg_to_solaris(struct tem_vt_state *tem, int ansi)
{
- if (tem->state->a_flags & TEM_ATTR_BOLD)
+ if (tem->tvs_flags & TEM_ATTR_BOLD)
return (fg_brt_xlate[ansi]);
else
return (fg_dim_xlate[ansi]);
}
-static void
-tem_get_color(struct tem *tem, text_color_t *fg, text_color_t *bg)
+/*
+ * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
+ */
+void
+tem_safe_get_color(struct tem_vt_state *tem, text_color_t *fg,
+ text_color_t *bg, uint8_t flag)
{
- if (tem->state->a_flags & TEM_ATTR_SCREEN_REVERSE) {
+ if (tem->tvs_flags & flag) {
*fg = ansi_fg_to_solaris(tem,
- DEFAULT_ANSI_BACKGROUND);
+ tem->tvs_bg_color);
*bg = ansi_bg_to_solaris(tem,
- DEFAULT_ANSI_FOREGROUND);
+ tem->tvs_fg_color);
} else {
*fg = ansi_fg_to_solaris(tem,
- DEFAULT_ANSI_FOREGROUND);
+ tem->tvs_fg_color);
*bg = ansi_bg_to_solaris(tem,
- DEFAULT_ANSI_BACKGROUND);
+ tem->tvs_bg_color);
}
}
@@ -2120,39 +2184,266 @@ tem_get_color(struct tem *tem, text_color_t *fg, text_color_t *bg)
* which is called only once.
*/
void
-tem_pix_cls_range(tem_t *tem,
+tem_safe_pix_cls_range(struct tem_vt_state *tem,
screen_pos_t row, int nrows, int offset_y,
screen_pos_t col, int ncols, int offset_x,
boolean_t sroll_up, cred_t *credp,
enum called_from called_from)
{
- struct tem_state *tems = tem->state;
struct vis_consdisplay da;
int i, j;
int row_add = 0;
text_color_t fg_color;
text_color_t bg_color;
- ASSERT((called_from == CALLED_FROM_STANDALONE) ||
- MUTEX_HELD(&tem->lock));
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
if (sroll_up)
- row_add = tems->a_c_dimension.height - 1;
+ row_add = tems.ts_c_dimension.height - 1;
- da.width = tems->a_font.width;
- da.height = tems->a_font.height;
+ da.width = tems.ts_font.width;
+ da.height = tems.ts_font.height;
- tem_get_color(tem, &fg_color, &bg_color);
+ tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
- BIT_TO_PIX(tem, ' ', fg_color, bg_color);
- da.data = (uchar_t *)tems->a_pix_data;
+ tem_safe_callback_bit2pix(tem, ' ', fg_color, bg_color);
+ da.data = (uchar_t *)tem->tvs_pix_data;
for (i = 0; i < nrows; i++, row++) {
da.row = (row + row_add) * da.height + offset_y;
da.col = col * da.width + offset_x;
for (j = 0; j < ncols; j++) {
- tem_display(tem, &da, credp, called_from);
+ tems_safe_display(&da, credp, called_from);
da.col += da.width;
}
}
}
+
+/*
+ * virtual screen operations
+ */
+static void
+tem_safe_virtual_display(struct tem_vt_state *tem, unsigned char *string,
+ int count, screen_pos_t row, screen_pos_t col,
+ text_color_t fg_color, text_color_t bg_color)
+{
+ int i, width;
+ unsigned char *addr;
+ text_color_t *pfgcolor;
+ text_color_t *pbgcolor;
+
+ if (row < 0 || row >= tems.ts_c_dimension.height ||
+ col < 0 || col >= tems.ts_c_dimension.width ||
+ col + count > tems.ts_c_dimension.width)
+ return;
+
+ width = tems.ts_c_dimension.width;
+ addr = tem->tvs_screen_buf + (row * width + col);
+ pfgcolor = tem->tvs_fg_buf + (row * width + col);
+ pbgcolor = tem->tvs_bg_buf + (row * width + col);
+ for (i = 0; i < count; i++) {
+ *addr++ = string[i];
+ *pfgcolor++ = fg_color;
+ *pbgcolor++ = bg_color;
+ }
+}
+
+static void
+i_virtual_copy(unsigned char *base,
+ screen_pos_t s_col, screen_pos_t s_row,
+ screen_pos_t e_col, screen_pos_t e_row,
+ screen_pos_t t_col, screen_pos_t t_row)
+{
+ unsigned char *from;
+ unsigned char *to;
+ int cnt;
+ screen_size_t chars_per_row;
+ unsigned char *to_row_start;
+ unsigned char *from_row_start;
+ screen_size_t rows_to_move;
+ int cols = tems.ts_c_dimension.width;
+
+ chars_per_row = e_col - s_col + 1;
+ rows_to_move = e_row - s_row + 1;
+
+ to_row_start = base + ((t_row * cols) + t_col);
+ from_row_start = base + ((s_row * cols) + s_col);
+
+ if (to_row_start < from_row_start) {
+ while (rows_to_move-- > 0) {
+ to = to_row_start;
+ from = from_row_start;
+ to_row_start += cols;
+ from_row_start += cols;
+ for (cnt = chars_per_row; cnt-- > 0; )
+ *to++ = *from++;
+ }
+ } else {
+ /*
+ * Offset to the end of the region and copy backwards.
+ */
+ cnt = rows_to_move * cols + chars_per_row;
+ to_row_start += cnt;
+ from_row_start += cnt;
+
+ while (rows_to_move-- > 0) {
+ to_row_start -= cols;
+ from_row_start -= cols;
+ to = to_row_start;
+ from = from_row_start;
+ for (cnt = chars_per_row; cnt-- > 0; )
+ *--to = *--from;
+ }
+ }
+}
+
+static void
+tem_safe_virtual_copy(struct tem_vt_state *tem,
+ screen_pos_t s_col, screen_pos_t s_row,
+ screen_pos_t e_col, screen_pos_t e_row,
+ screen_pos_t t_col, screen_pos_t t_row)
+{
+ screen_size_t chars_per_row;
+ screen_size_t rows_to_move;
+ int rows = tems.ts_c_dimension.height;
+ int cols = tems.ts_c_dimension.width;
+
+ if (s_col < 0 || s_col >= cols ||
+ s_row < 0 || s_row >= rows ||
+ e_col < 0 || e_col >= cols ||
+ e_row < 0 || e_row >= rows ||
+ t_col < 0 || t_col >= cols ||
+ t_row < 0 || t_row >= rows ||
+ s_col > e_col ||
+ s_row > e_row)
+ return;
+
+ chars_per_row = e_col - s_col + 1;
+ rows_to_move = e_row - s_row + 1;
+
+ /* More sanity checks. */
+ if (t_row + rows_to_move > rows ||
+ t_col + chars_per_row > cols)
+ return;
+
+ i_virtual_copy(tem->tvs_screen_buf, s_col, s_row,
+ e_col, e_row, t_col, t_row);
+
+ /* text_color_t is the same size as char */
+ i_virtual_copy((unsigned char *)tem->tvs_fg_buf,
+ s_col, s_row, e_col, e_row, t_col, t_row);
+ i_virtual_copy((unsigned char *)tem->tvs_bg_buf,
+ s_col, s_row, e_col, e_row, t_col, t_row);
+
+}
+
+static void
+tem_safe_virtual_cls(struct tem_vt_state *tem,
+ int count, screen_pos_t row, screen_pos_t col)
+{
+ text_color_t fg_color;
+ text_color_t bg_color;
+
+ tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
+ tem_safe_virtual_display(tem, tems.ts_blank_line, count, row, col,
+ fg_color, bg_color);
+}
+
+/*
+ * only blank screen, not clear our screen buffer
+ */
+void
+tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp,
+ enum called_from called_from)
+{
+ int row;
+
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
+
+ if (tems.ts_display_mode == VIS_PIXEL) {
+ tem_safe_pix_clear_entire_screen(tem, credp, called_from);
+ return;
+ }
+
+ for (row = 0; row < tems.ts_c_dimension.height; row++) {
+ tem_safe_callback_cls(tem,
+ tems.ts_c_dimension.width,
+ row, 0, credp, called_from);
+ }
+}
+
+/*
+ * unblank screen with associated tem from its screen buffer
+ */
+void
+tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp,
+ enum called_from called_from)
+{
+ text_color_t fg_color, fg_last;
+ text_color_t bg_color, bg_last;
+ size_t tc_size = sizeof (text_color_t);
+ int row, col, count, col_start;
+ int width;
+ unsigned char *buf;
+
+ ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
+ called_from == CALLED_FROM_STANDALONE);
+
+ if (tems.ts_display_mode == VIS_PIXEL)
+ tem_safe_pix_clear_entire_screen(tem, credp, called_from);
+
+ tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from);
+
+ width = tems.ts_c_dimension.width;
+
+ /*
+ * Display data in tvs_screen_buf to the actual framebuffer in a
+ * row by row way.
+ * When dealing with one row, output data with the same foreground
+ * and background color all together.
+ */
+ for (row = 0; row < tems.ts_c_dimension.height; row++) {
+ buf = tem->tvs_screen_buf + (row * width);
+ count = col_start = 0;
+ for (col = 0; col < width; col++) {
+ fg_color =
+ tem->tvs_fg_buf[(row * width + col) * tc_size];
+ bg_color =
+ tem->tvs_bg_buf[(row * width + col) * tc_size];
+ if (col == 0) {
+ fg_last = fg_color;
+ bg_last = bg_color;
+ }
+
+ if ((fg_color != fg_last) || (bg_color != bg_last)) {
+ /*
+ * Call the primitive to render this data.
+ */
+ tem_safe_callback_display(tem,
+ buf, count, row, col_start,
+ fg_last, bg_last, credp, called_from);
+ buf += count;
+ count = 1;
+ col_start = col;
+ fg_last = fg_color;
+ bg_last = bg_color;
+ } else {
+ count++;
+ }
+ }
+
+ if (col_start == (width - 1))
+ continue;
+
+ /*
+ * Call the primitive to render this data.
+ */
+ tem_safe_callback_display(tem,
+ buf, count, row, col_start,
+ fg_last, bg_last, credp, called_from);
+ }
+
+ tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from);
+}
diff --git a/usr/src/uts/common/io/vcons.c b/usr/src/uts/common/io/vcons.c
new file mode 100644
index 0000000000..3646057465
--- /dev/null
+++ b/usr/src/uts/common/io/vcons.c
@@ -0,0 +1,1308 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/termios.h>
+#include <sys/termio.h>
+#include <sys/ttold.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/tty.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+#include <sys/procset.h>
+#include <sys/fault.h>
+#include <sys/siginfo.h>
+#include <sys/debug.h>
+#include <sys/kd.h>
+#include <sys/vt.h>
+#include <sys/vtdaemon.h>
+#include <sys/session.h>
+#include <sys/door.h>
+#include <sys/kmem.h>
+#include <sys/cpuvar.h>
+#include <sys/kbio.h>
+#include <sys/strredir.h>
+#include <sys/fs/snode.h>
+#include <sys/consdev.h>
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/console.h>
+#include <sys/promif.h>
+#include <sys/note.h>
+#include <sys/polled_io.h>
+#include <sys/systm.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/esunddi.h>
+#include <sys/sunldi.h>
+#include <sys/debug.h>
+#include <sys/console.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/policy.h>
+#include <sys/tem.h>
+#include <sys/wscons.h>
+#include <sys/systm.h>
+#include <sys/modctl.h>
+#include <sys/vt_impl.h>
+#include <sys/consconfig_dacf.h>
+
+/*
+ * This file belongs to wc STREAMS module which has a D_MTPERMODE
+ * inner perimeter. See "Locking Policy" comment in wscons.c for
+ * more information.
+ */
+
+/*
+ * Minor name device file Hotkeys
+ *
+ * 0 the system console /dev/console Alt + F1
+ * 0: virtual console #1 /dev/vt/0 Alt + F1
+ *
+ * 2: virtual console #2 /dev/vt/2 Alt + F2
+ * 3: virtual console #3 /dev/vt/3 Alt + F3
+ * ......
+ * n: virtual console #n /dev/vt/n Alt + Fn
+ *
+ * Note that vtdaemon is running on /dev/vt/1 (minor=1),
+ * which is not available to end users.
+ *
+ */
+
+#define VT_DAEMON_MINOR 1
+#define VT_IS_DAEMON(minor) ((minor) == VT_DAEMON_MINOR)
+
+extern void wc_get_size(vc_state_t *pvc);
+extern boolean_t consconfig_console_is_tipline(void);
+
+
+minor_t vc_last_console = VT_MINOR_INVALID; /* the last used console */
+volatile uint_t vc_target_console; /* arg (1..n) */
+
+static volatile minor_t vc_inuse_max_minor = 0;
+static list_t vc_waitactive_list;
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_target_console))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_last_console))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_inuse_max_minor))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_waitactive_list))
+
+static int vt_pending_vtno = -1;
+kmutex_t vt_pending_vtno_lock;
+_NOTE(MUTEX_PROTECTS_DATA(vt_pending_vtno_lock, vt_pending_vtno))
+
+static int vt_activate(uint_t vt_no, cred_t *credp);
+static void vt_copyout(queue_t *qp, mblk_t *mp, mblk_t *tmp, uint_t size);
+static void vt_copyin(queue_t *qp, mblk_t *mp, uint_t size);
+static void vt_iocnak(queue_t *qp, mblk_t *mp, int error);
+static void vt_iocack(queue_t *qp, mblk_t *mp);
+
+static uint_t vt_minor2arg(minor_t minor);
+static minor_t vt_arg2minor(uint_t arg);
+
+/*
+ * If the system console is directed to tipline, consider /dev/vt/0 as
+ * not being used.
+ * For other VT, if it is opened and tty is initialized, consider it
+ * as being used.
+ */
+#define VT_IS_INUSE(id) \
+ (((vt_minor2vc(id))->vc_flags & WCS_ISOPEN) && \
+ ((vt_minor2vc(id))->vc_flags & WCS_INIT) && \
+ (id != 0 || !consconfig_console_is_tipline()))
+
+/*
+ * the vt switching message is encoded as:
+ *
+ * -------------------------------------------------------------
+ * | \033 | 'Q' | vtno + 'A' | opcode | 'z' | '\0' |
+ * -------------------------------------------------------------
+ */
+#define VT_MSG_SWITCH(mp) \
+ ((int)((mp)->b_wptr - (mp)->b_rptr) >= 5 && \
+ *((mp)->b_rptr) == '\033' && \
+ *((mp)->b_rptr + 1) == 'Q' && \
+ *((mp)->b_rptr + 4) == 'z')
+
+#define VT_MSG_VTNO(mp) (*((mp)->b_rptr + 2) - 'A')
+#define VT_MSG_OPCODE(mp) (*((mp)->b_rptr + 3))
+
+#define VT_DOORCALL_MAX_RETRY 3
+
+static void
+vt_init_ttycommon(tty_common_t *pcommon)
+{
+ struct termios *termiosp;
+ int len;
+
+ mutex_init(&pcommon->t_excl, NULL, MUTEX_DEFAULT, NULL);
+ pcommon->t_iflag = 0;
+
+ /*
+ * Get the default termios settings (cflag).
+ * These are stored as a property in the
+ * "options" node.
+ */
+ if (ddi_getlongprop(DDI_DEV_T_ANY,
+ ddi_root_node(), 0, "ttymodes",
+ (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS) {
+
+ if (len == sizeof (struct termios))
+ pcommon->t_cflag = termiosp->c_cflag;
+ else
+ cmn_err(CE_WARN,
+ "wc: Couldn't get ttymodes property!");
+
+ kmem_free(termiosp, len);
+ } else {
+ /*
+ * Gack! Whine about it.
+ */
+ cmn_err(CE_WARN,
+ "wc: Couldn't get ttymodes property!");
+ }
+
+ pcommon->t_iocpending = NULL;
+}
+
+static int
+vt_config(uint_t count)
+{
+ if (consmode != CONS_KFB)
+ return (ENOTSUP);
+
+ /* one for system console, one for vtdaemon */
+ if (count < 2)
+ return (ENXIO);
+
+ /*
+ * Shouldn't allow to shrink the max vt minor to be smaller than
+ * the max in used minor.
+ */
+ if (count <= vc_inuse_max_minor)
+ return (EBUSY);
+
+ mutex_enter(&vc_lock);
+ vt_resize(count);
+ mutex_exit(&vc_lock);
+
+ return (0);
+}
+
+void
+vt_clean(queue_t *q, vc_state_t *pvc)
+{
+ ASSERT(MUTEX_HELD(&pvc->vc_state_lock));
+
+ if (pvc->vc_bufcallid != 0) {
+ qunbufcall(q, pvc->vc_bufcallid);
+ pvc->vc_bufcallid = 0;
+ }
+ if (pvc->vc_timeoutid != 0) {
+ (void) quntimeout(q, pvc->vc_timeoutid);
+ pvc->vc_timeoutid = 0;
+ }
+ ttycommon_close(&pvc->vc_ttycommon);
+
+ pvc->vc_flags &= ~WCS_INIT;
+}
+
+/*
+ * Reply the VT_WAITACTIVE ioctl.
+ * Argument 'close' usage:
+ * B_TRUE: the vt designated by argument 'minor' is being closed.
+ * B_FALSE: the vt designated by argument 'minor' has been activated just now.
+ */
+static void
+vc_waitactive_reply(int minor, boolean_t close)
+{
+ vc_waitactive_msg_t *index, *tmp;
+ vc_state_t *pvc;
+
+ index = list_head(&vc_waitactive_list);
+
+ while (index != NULL) {
+ tmp = index;
+ index = list_next(&vc_waitactive_list, index);
+
+ if ((close && tmp->wa_msg_minor == minor) ||
+ (!close && tmp->wa_wait_minor == minor)) {
+ list_remove(&vc_waitactive_list, tmp);
+ pvc = vt_minor2vc(tmp->wa_msg_minor);
+
+ if (close)
+ vt_iocnak(pvc->vc_wq, tmp->wa_mp, ENXIO);
+ else
+ vt_iocack(pvc->vc_wq, tmp->wa_mp);
+
+ kmem_free(tmp, sizeof (vc_waitactive_msg_t));
+ }
+ }
+}
+
+void
+vt_close(queue_t *q, vc_state_t *pvc, cred_t *credp)
+{
+ minor_t index;
+
+ mutex_enter(&pvc->vc_state_lock);
+ vt_clean(q, pvc);
+ pvc->vc_flags &= ~WCS_ISOPEN;
+ mutex_exit(&pvc->vc_state_lock);
+
+ tem_destroy(pvc->vc_tem, credp);
+ pvc->vc_tem = NULL;
+
+ index = pvc->vc_minor;
+ if (index == vc_inuse_max_minor) {
+ while ((--index > 0) && !VT_IS_INUSE(index))
+ ;
+ vc_inuse_max_minor = index;
+ }
+
+ vc_waitactive_reply(pvc->vc_minor, B_TRUE);
+}
+
+static void
+vt_init_tty(vc_state_t *pvc)
+{
+ ASSERT(MUTEX_HELD(&pvc->vc_state_lock));
+
+ pvc->vc_flags |= WCS_INIT;
+ vt_init_ttycommon(&pvc->vc_ttycommon);
+ wc_get_size(pvc);
+}
+
+/*
+ * minor 0: /dev/vt/0 (index = 0, indicating the system console)
+ * minor 1: /dev/vt/1 (index = 1, vtdaemon special console)
+ * minor 2: /dev/vt/2 (index = 2, virtual consoles)
+ * ......
+ * minor n: /dev/vt/n (index = n)
+ *
+ *
+ * The system console (minor 0), is opened firstly and used during console
+ * configuration. It also acts as the system hard console even when all
+ * virtual consoles go off.
+ *
+ * In tipline case, minor 0 (/dev/vt/0) is reserved, and cannot be switched to.
+ * And the system console is redirected to the tipline. During normal cases,
+ * we can switch from virtual consoles to it by pressing 'Alt + F1'.
+ *
+ * minor 1 (/dev/vt/1) is reserved for vtdaemon special console, and it's
+ * not available to end users.
+ *
+ * During early console configuration, consconfig_dacf opens wscons and then
+ * issue a WC_OPEN_FB ioctl to kick off terminal init process. So during
+ * consconfig_dacf first opening of wscons, tems (of type tem_state_t) is
+ * not initialized. We do not initialize the tem_vt_state_t instance returned
+ * by tem_init() for this open, since we do not have enough info to handle
+ * normal terminal operation at this moment. This tem_vt_state_t instance
+ * will get initialized when handling WC_OPEN_FB.
+ */
+int
+vt_open(minor_t minor, queue_t *rq, cred_t *crp)
+{
+ vc_state_t *pvc;
+
+ if (!vt_minor_valid(minor))
+ return (ENXIO);
+
+ pvc = vt_minor2vc(minor);
+ if (pvc == NULL)
+ return (ENXIO);
+
+ mutex_enter(&vc_lock);
+ mutex_enter(&pvc->vc_state_lock);
+
+ if (!(pvc->vc_flags & WCS_ISOPEN)) {
+ /*
+ * vc_tem might not be intialized if !tems.ts_initialized,
+ * and this only happens during console configuration.
+ */
+ pvc->vc_tem = tem_init(crp);
+ }
+
+ if (!(pvc->vc_flags & WCS_INIT))
+ vt_init_tty(pvc);
+
+ /*
+ * In normal case, the first screen is the system console;
+ * In tipline case, the first screen is the first VT that gets started.
+ */
+ if (vc_active_console == VT_MINOR_INVALID && minor != VT_DAEMON_MINOR)
+ if (minor == 0 || consmode == CONS_KFB) {
+ boolean_t unblank = B_FALSE;
+
+ vc_active_console = minor;
+ vc_last_console = minor;
+ if (minor != 0) {
+ /*
+ * If we are not opening the system console
+ * as the first console, clear the phyical
+ * screen.
+ */
+ unblank = B_TRUE;
+ }
+
+ tem_activate(pvc->vc_tem, unblank, crp);
+ }
+
+ if ((pvc->vc_ttycommon.t_flags & TS_XCLUDE) &&
+ (secpolicy_excl_open(crp) != 0)) {
+ mutex_exit(&pvc->vc_state_lock);
+ mutex_exit(&vc_lock);
+ return (EBUSY);
+ }
+
+ if (minor > vc_inuse_max_minor)
+ vc_inuse_max_minor = minor;
+
+ pvc->vc_flags |= WCS_ISOPEN;
+ pvc->vc_ttycommon.t_readq = rq;
+ pvc->vc_ttycommon.t_writeq = WR(rq);
+
+ mutex_exit(&pvc->vc_state_lock);
+ mutex_exit(&vc_lock);
+
+ rq->q_ptr = pvc;
+ WR(rq)->q_ptr = pvc;
+ pvc->vc_wq = WR(rq);
+
+ qprocson(rq);
+ return (0);
+}
+
+static minor_t
+vt_find_prev(minor_t cur)
+{
+ minor_t i, t, max;
+
+ ASSERT(vc_active_console != VT_MINOR_INVALID);
+
+ max = VC_INSTANCES_COUNT;
+
+ for (i = cur - 1; (t = (i + max) % max) != cur; i--)
+ if (!VT_IS_DAEMON(t) && VT_IS_INUSE(t))
+ return (t);
+
+ return (VT_MINOR_INVALID);
+}
+
+static minor_t
+vt_find_next(minor_t cur)
+{
+ minor_t i, t, max;
+
+ ASSERT(vc_active_console != VT_MINOR_INVALID);
+
+ max = VC_INSTANCES_COUNT;
+
+ for (i = cur + 1; (t = (i + max) % max) != cur; i++)
+ if (!VT_IS_DAEMON(t) && VT_IS_INUSE(t))
+ return (t);
+
+ return (VT_MINOR_INVALID);
+}
+
+/* ARGSUSED */
+void
+vt_send_hotkeys(void *timeout_arg)
+{
+ door_handle_t door;
+ vt_cmd_arg_t arg;
+ int error = 0;
+ int retries = 0;
+ door_arg_t door_arg;
+
+ mutex_enter(&vt_pending_vtno_lock);
+
+ arg.vt_ev = VT_EV_HOTKEYS;
+ arg.vt_num = vt_pending_vtno;
+
+ /* only available in kernel context or user context */
+ if (door_ki_open(VT_DAEMON_DOOR_FILE, &door) != 0) {
+ vt_pending_vtno = -1;
+ mutex_exit(&vt_pending_vtno_lock);
+ return;
+ }
+
+ door_arg.rbuf = NULL;
+ door_arg.rsize = 0;
+ door_arg.data_ptr = (void *)&arg;
+ door_arg.data_size = sizeof (arg);
+ door_arg.desc_ptr = NULL;
+ door_arg.desc_num = 0;
+
+ /*
+ * Make door upcall
+ */
+ while ((error = door_ki_upcall(door, &door_arg)) != 0 &&
+ retries < VT_DOORCALL_MAX_RETRY)
+ if (error == EAGAIN || error == EINTR)
+ retries++;
+ else
+ break;
+
+ door_ki_rele(door);
+
+ vt_pending_vtno = -1;
+
+ mutex_exit(&vt_pending_vtno_lock);
+}
+
+static boolean_t
+vt_validate_hotkeys(int minor)
+{
+ /*
+ * minor should not succeed the existing minor numbers range.
+ */
+ if (!vt_minor_valid(minor))
+ return (B_FALSE);
+
+ /*
+ * Shouldn't switch to /dev/vt/1 or an unused vt.
+ */
+ if (!VT_IS_DAEMON(minor) && VT_IS_INUSE(minor))
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+static void
+vt_trigger_hotkeys(int vtno)
+{
+ mutex_enter(&vt_pending_vtno_lock);
+
+ if (vt_pending_vtno != -1) {
+ mutex_exit(&vt_pending_vtno_lock);
+ return;
+ }
+
+ vt_pending_vtno = vtno;
+ mutex_exit(&vt_pending_vtno_lock);
+ (void) timeout(vt_send_hotkeys, NULL, 1);
+}
+
+/*
+ * return value:
+ * 0: non msg of vt hotkeys
+ * 1: msg of vt hotkeys
+ */
+int
+vt_check_hotkeys(mblk_t *mp)
+{
+ int vtno = 0;
+ minor_t minor = 0;
+
+ /* LINTED E_PTRDIFF_OVERFLOW */
+ if (!VT_MSG_SWITCH(mp))
+ return (0);
+
+ switch (VT_MSG_OPCODE(mp)) {
+ case 'B':
+ /* find out the previous vt */
+ if (vc_active_console == VT_MINOR_INVALID)
+ return (1);
+
+ if (VT_IS_DAEMON(vc_active_console)) {
+ minor = vt_find_prev(vt_arg2minor(vc_target_console));
+ break;
+ }
+
+ minor = vt_find_prev(vc_active_console);
+ break;
+ case 'F':
+ /* find out the next vt */
+ if (vc_active_console == VT_MINOR_INVALID)
+ return (1);
+
+ if (VT_IS_DAEMON(vc_active_console)) {
+ minor = vt_find_next(vt_arg2minor(vc_target_console));
+ break;
+ }
+
+ minor = vt_find_next(vc_active_console);
+ break;
+ case 'H':
+ /* find out the specified vt */
+ minor = VT_MSG_VTNO(mp);
+
+ /* check for system console, Alt + F1 */
+ if (minor == 1)
+ minor = 0;
+ break;
+ case 'L':
+ /* find out the last vt */
+ if ((minor = vc_last_console) == VT_MINOR_INVALID)
+ return (1);
+ break;
+ default:
+ return (1);
+ }
+
+ if (!vt_validate_hotkeys(minor))
+ return (1);
+
+ /*
+ * for system console, the argument of vtno for
+ * vt_activate is 1, though its minor is 0
+ */
+ if (minor == 0)
+ vtno = 1; /* for system console */
+ else
+ vtno = minor;
+
+ vt_trigger_hotkeys(vtno);
+ return (1);
+}
+
+static void
+vt_proc_sendsig(pid_t pid, int sig)
+{
+ register proc_t *p;
+
+ if (pid <= 0)
+ return;
+
+ mutex_enter(&pidlock);
+ if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) {
+ mutex_exit(&pidlock);
+ return;
+ }
+
+ psignal(p, sig);
+ mutex_exit(&pidlock);
+}
+
+static int
+vt_proc_exists(pid_t pid)
+{
+ register proc_t *p;
+
+ if (pid <= 0)
+ return (EINVAL);
+
+ mutex_enter(&pidlock);
+ if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) {
+ mutex_exit(&pidlock);
+ return (ESRCH);
+ }
+ mutex_exit(&pidlock);
+
+ return (0);
+}
+
+#define SIG_VALID(x) (((x) > 0) && ((x) < _SIGRTMAX) && \
+ ((x) != SIGKILL) && ((x) != SIGSTOP))
+
+static int
+vt_setmode(vc_state_t *pvc, struct vt_mode *pmode)
+{
+ if ((pmode->mode != VT_PROCESS) && (pmode->mode != VT_AUTO))
+ return (EINVAL);
+
+ if (!SIG_VALID(pmode->relsig) || !SIG_VALID(pmode->acqsig))
+ return (EINVAL);
+
+ if (pmode->mode == VT_PROCESS) {
+ pvc->vc_pid = curproc->p_pid;
+ } else {
+ pvc->vc_dispnum = 0;
+ pvc->vc_login = 0;
+ }
+
+ pvc->vc_switch_mode = pmode->mode;
+ pvc->vc_waitv = pmode->waitv;
+ pvc->vc_relsig = pmode->relsig;
+ pvc->vc_acqsig = pmode->acqsig;
+
+ return (0);
+}
+
+static void
+vt_reset(vc_state_t *pvc)
+{
+ pvc->vc_switch_mode = VT_AUTO;
+ pvc->vc_pid = -1;
+ pvc->vc_dispnum = 0;
+ pvc->vc_login = 0;
+ pvc->vc_switchto = VT_MINOR_INVALID;
+}
+
+/*
+ * switch to vt_no from vc_active_console
+ */
+static void
+vt_switch(uint_t vt_no, cred_t *credp)
+{
+ vc_state_t *pvc_active = vt_minor2vc(vc_active_console);
+ vc_state_t *pvc = vt_minor2vc(vt_no);
+ minor_t index;
+
+ ASSERT(pvc_active && pvc);
+
+ mutex_enter(&vc_lock);
+
+ tem_switch(pvc_active->vc_tem, pvc->vc_tem, credp);
+
+ if (!VT_IS_DAEMON(vc_active_console))
+ vc_last_console = vc_active_console;
+ else
+ vc_last_console = vt_arg2minor(vc_target_console);
+
+ vc_active_console = pvc->vc_minor;
+
+ if (pvc->vc_switch_mode == VT_PROCESS) {
+ pvc->vc_switchto = pvc->vc_minor;
+
+ /* send it an acquired signal */
+ vt_proc_sendsig(pvc->vc_pid, pvc->vc_acqsig);
+ }
+
+ vc_waitactive_reply(vc_active_console, B_FALSE);
+
+ mutex_exit(&vc_lock);
+
+ if (!VT_IS_DAEMON(vt_no)) {
+ /*
+ * Applications that open the virtual console device may request
+ * asynchronous notification of VT switching from a previous VT
+ * to another one by setting the S_MSG flag in an I_SETSIG
+ * STREAMS ioctl. Such processes receive a SIGPOLL signal when
+ * a VT switching succeeds.
+ */
+ for (index = 0; index < VC_INSTANCES_COUNT; index++) {
+ vc_state_t *tmp_pvc = vt_minor2vc(index);
+ mblk_t *mp;
+
+ if ((tmp_pvc->vc_flags & WCS_ISOPEN) &&
+ (tmp_pvc->vc_flags & WCS_INIT) &&
+ (mp = allocb(sizeof (unsigned char), BPRI_HI))) {
+ mp->b_datap->db_type = M_PCSIG;
+ *mp->b_wptr = SIGPOLL;
+ mp->b_wptr += sizeof (unsigned char);
+ putnext(RD(tmp_pvc->vc_wq), mp);
+ }
+ }
+ }
+
+}
+
+/*
+ * vt_no from 0 to n
+ *
+ * 0 for the vtdaemon sepcial console (only vtdaemon will use it)
+ * 1 for the system console (Alt + F1, or Alt + Ctrl + F1),
+ * aka Virtual Console #1
+ *
+ * 2 for Virtual Console #2
+ * n for Virtual Console #n
+ */
+static minor_t
+vt_arg2minor(uint_t arg)
+{
+ if (arg == 0)
+ return (1);
+
+ if (arg == 1)
+ return (0);
+
+ return (arg);
+}
+
+static uint_t
+vt_minor2arg(minor_t minor)
+{
+ if (minor == 0)
+ return (1);
+
+ if (VT_IS_DAEMON(minor)) {
+ /* here it should be the real console */
+ return (vc_target_console);
+ }
+
+ return (minor);
+}
+
+static int
+vt_activate(uint_t vt_no, cred_t *credp)
+{
+ vc_state_t *pvc;
+ minor_t minor;
+
+ minor = vt_arg2minor(vt_no);
+ if (!vt_minor_valid(minor))
+ return (ENXIO);
+ if (minor == vc_active_console) {
+ if (VT_IS_DAEMON(minor)) {
+ /*
+ * vtdaemon is reactivating itself to do locking
+ * on behalf of another console, so record current
+ * target console as the last console.
+ */
+ vc_last_console = vt_arg2minor(vc_target_console);
+ }
+
+ return (0);
+ }
+
+ /*
+ * In tipline case, the system console is redirected to tipline
+ * and thus is always available.
+ */
+ if (minor == 0 && consconfig_console_is_tipline())
+ return (0);
+
+ if (!VT_IS_INUSE(minor))
+ return (ENXIO);
+
+ pvc = vt_minor2vc(minor);
+ if (pvc == NULL)
+ return (ENXIO);
+ if (pvc->vc_tem == NULL)
+ return (ENXIO);
+
+ pvc = vt_minor2vc(vc_active_console);
+ if (pvc == NULL)
+ return (ENXIO);
+ if (pvc->vc_switch_mode != VT_PROCESS) {
+ vt_switch(minor, credp);
+ return (0);
+ }
+
+ /*
+ * Validate the process, reset the
+ * vt to auto mode if failed.
+ */
+ if (pvc->vc_pid == -1 || vt_proc_exists(pvc->vc_pid) != 0) {
+ /*
+ * Xserver has not started up yet,
+ * or it dose not exist.
+ */
+ vt_reset(pvc);
+ return (0);
+ }
+
+ /*
+ * Send the release signal to the process,
+ * and wait VT_RELDISP ioctl from Xserver
+ * after its leaving VT.
+ */
+ vt_proc_sendsig(pvc->vc_pid, pvc->vc_relsig);
+ pvc->vc_switchto = minor;
+
+ /*
+ * We don't need a timeout here, for if Xserver refuses
+ * or fails to respond to release signal using VT_RELDISP,
+ * we cannot successfully switch to our text mode. Actually
+ * users can try again. At present we don't support force
+ * switch.
+ */
+ return (0);
+}
+
+static int
+vt_reldisp(vc_state_t *pvc, int arg, cred_t *credp)
+{
+ minor_t target_vtno = pvc->vc_switchto;
+
+ if ((pvc->vc_switch_mode != VT_PROCESS) ||
+ (pvc->vc_minor != vc_active_console))
+ return (EACCES);
+
+ if (target_vtno == VT_MINOR_INVALID)
+ return (EINVAL);
+
+ pvc->vc_switchto = VT_MINOR_INVALID;
+
+ if (arg == VT_ACKACQ)
+ return (0);
+
+ if (arg == 0)
+ return (0); /* refuse to release */
+
+ /* Xserver has left VT */
+ vt_switch(target_vtno, credp);
+ return (0);
+}
+
+void
+vt_ioctl(queue_t *q, mblk_t *mp)
+{
+ vc_state_t *pvc = (vc_state_t *)q->q_ptr;
+ struct iocblk *iocp;
+ struct vt_mode vtmode;
+ struct vt_stat vtinfo;
+ struct vt_dispinfo vtdisp;
+ mblk_t *tmp;
+ int minor;
+ int arg;
+ int error = 0;
+ vc_waitactive_msg_t *wait_msg;
+
+ iocp = (struct iocblk *)(void *)mp->b_rptr;
+ if (consmode != CONS_KFB && iocp->ioc_cmd != VT_ENABLED) {
+ vt_iocnak(q, mp, EINVAL);
+ return;
+ }
+
+ switch (iocp->ioc_cmd) {
+ case VT_ENABLED:
+ if (!(tmp = allocb(sizeof (int), BPRI_MED))) {
+ error = ENOMEM;
+ break;
+ }
+ *(int *)(void *)tmp->b_rptr = consmode;
+ tmp->b_wptr += sizeof (int);
+ vt_copyout(q, mp, tmp, sizeof (int));
+ return;
+
+ case KDSETMODE:
+ arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
+ if (arg != KD_TEXT && arg != KD_GRAPHICS) {
+ error = EINVAL;
+ break;
+ }
+ if (tem_get_fbmode(pvc->vc_tem) == arg)
+ break;
+
+ tem_set_fbmode(pvc->vc_tem, (uchar_t)arg, iocp->ioc_cr);
+
+ break;
+
+ case KDGETMODE:
+ if (!(tmp = allocb(sizeof (int), BPRI_MED))) {
+ error = ENOMEM;
+ break;
+ }
+ *(int *)(void *)tmp->b_rptr = tem_get_fbmode(pvc->vc_tem);
+ tmp->b_wptr += sizeof (int);
+ vt_copyout(q, mp, tmp, sizeof (int));
+ return;
+
+ case VT_OPENQRY: /* return number of first free VT */
+ if (!(tmp = allocb(sizeof (int), BPRI_MED))) {
+ error = ENOMEM;
+ break;
+ }
+
+ /* minors of 0 and 1 are not available to end users */
+ for (minor = 2; vt_minor_valid(minor); minor++)
+ if (!VT_IS_INUSE(minor))
+ break;
+
+ if (!vt_minor_valid(minor))
+ minor = -1;
+ *(int *)(void *)tmp->b_rptr = minor; /* /dev/vt/minor */
+ tmp->b_wptr += sizeof (int);
+ vt_copyout(q, mp, tmp, sizeof (int));
+ return;
+
+ case VT_GETMODE:
+ vtmode.mode = pvc->vc_switch_mode;
+ vtmode.waitv = pvc->vc_waitv;
+ vtmode.relsig = pvc->vc_relsig;
+ vtmode.acqsig = pvc->vc_acqsig;
+ vtmode.frsig = 0;
+ if (!(tmp = allocb(sizeof (struct vt_mode), BPRI_MED))) {
+ error = ENOMEM;
+ break;
+ }
+ *(struct vt_mode *)(void *)tmp->b_rptr = vtmode;
+ tmp->b_wptr += sizeof (struct vt_mode);
+ vt_copyout(q, mp, tmp, sizeof (struct vt_mode));
+ return;
+
+ case VT_SETMODE:
+ vt_copyin(q, mp, sizeof (struct vt_mode));
+ return;
+
+ case VT_SETDISPINFO:
+ /* always enforce sys_devices privilege for setdispinfo */
+ if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
+ break;
+
+ pvc->vc_dispnum = *(intptr_t *)(void *)mp->b_cont->b_rptr;
+ break;
+
+ case VT_SETDISPLOGIN:
+ pvc->vc_login = *(intptr_t *)(void *)mp->b_cont->b_rptr;
+ break;
+
+ case VT_GETDISPINFO:
+ vtdisp.v_pid = pvc->vc_pid;
+ vtdisp.v_dispnum = pvc->vc_dispnum;
+ vtdisp.v_login = pvc->vc_login;
+ if (!(tmp = allocb(sizeof (struct vt_dispinfo), BPRI_MED))) {
+ error = ENOMEM;
+ break;
+ }
+ *(struct vt_dispinfo *)(void *)tmp->b_rptr = vtdisp;
+ tmp->b_wptr += sizeof (struct vt_dispinfo);
+ vt_copyout(q, mp, tmp, sizeof (struct vt_dispinfo));
+ return;
+
+ case VT_RELDISP:
+ arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
+ error = vt_reldisp(pvc, arg, iocp->ioc_cr);
+ break;
+
+ case VT_CONFIG:
+ /* always enforce sys_devices privilege for config */
+ if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
+ break;
+
+ arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
+ error = vt_config(arg);
+ break;
+
+ case VT_ACTIVATE:
+ /* always enforce sys_devices privilege for secure switch */
+ if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
+ break;
+
+ arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
+ error = vt_activate(arg, iocp->ioc_cr);
+ break;
+
+ case VT_WAITACTIVE:
+ arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
+ arg = vt_arg2minor(arg);
+ if (!vt_minor_valid(arg)) {
+ error = ENXIO;
+ break;
+ }
+ if (arg == vc_active_console)
+ break;
+
+ wait_msg = kmem_zalloc(sizeof (vc_waitactive_msg_t),
+ KM_NOSLEEP);
+ if (wait_msg == NULL) {
+ error = ENXIO;
+ break;
+ }
+
+ wait_msg->wa_mp = mp;
+ wait_msg->wa_msg_minor = pvc->vc_minor;
+ wait_msg->wa_wait_minor = arg;
+ list_insert_head(&vc_waitactive_list, wait_msg);
+
+ return;
+
+ case VT_GETSTATE:
+ /*
+ * Here v_active is the argument for vt_activate,
+ * not minor.
+ */
+ vtinfo.v_active = vt_minor2arg(vc_active_console);
+ vtinfo.v_state = 3; /* system console and vtdaemon */
+
+ /* we only support 16 vt states since the v_state is short */
+ for (minor = 2; minor < 16; minor++) {
+ pvc = vt_minor2vc(minor);
+ if (pvc == NULL)
+ break;
+ if (VT_IS_INUSE(minor))
+ vtinfo.v_state |= (1 << pvc->vc_minor);
+ }
+
+ if (!(tmp = allocb(sizeof (struct vt_stat), BPRI_MED))) {
+ error = ENOMEM;
+ break;
+ }
+ *(struct vt_stat *)(void *)tmp->b_rptr = vtinfo;
+ tmp->b_wptr += sizeof (struct vt_stat);
+ vt_copyout(q, mp, tmp, sizeof (struct vt_stat));
+ return;
+
+ case VT_SET_TARGET:
+ /* always enforce sys_devices privilege */
+ if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
+ break;
+
+ arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
+
+ /* vtdaemon is doing authentication for this target console */
+ vc_target_console = arg;
+ break;
+
+ case VT_GETACTIVE: /* get real active console (minor) */
+ if (!(tmp = allocb(sizeof (int), BPRI_MED))) {
+ error = ENOMEM;
+ break;
+ }
+ *(int *)(void *)tmp->b_rptr = vc_active_console;
+ tmp->b_wptr += sizeof (int);
+ vt_copyout(q, mp, tmp, sizeof (int));
+ return;
+
+ default:
+ error = ENXIO;
+ break;
+ }
+
+ if (error != 0)
+ vt_iocnak(q, mp, error);
+ else
+ vt_iocack(q, mp);
+}
+
+void
+vt_miocdata(queue_t *qp, mblk_t *mp)
+{
+ vc_state_t *pvc = (vc_state_t *)qp->q_ptr;
+ struct copyresp *copyresp;
+ struct vt_mode *pmode;
+ int error = 0;
+
+ copyresp = (struct copyresp *)(void *)mp->b_rptr;
+ if (copyresp->cp_rval) {
+ vt_iocnak(qp, mp, EAGAIN);
+ return;
+ }
+
+ switch (copyresp->cp_cmd) {
+ case VT_SETMODE:
+ pmode = (struct vt_mode *)(void *)mp->b_cont->b_rptr;
+ error = vt_setmode(pvc, pmode);
+ break;
+
+ case KDGETMODE:
+ case VT_OPENQRY:
+ case VT_GETMODE:
+ case VT_GETDISPINFO:
+ case VT_GETSTATE:
+ case VT_ENABLED:
+ case VT_GETACTIVE:
+ break;
+
+ default:
+ error = ENXIO;
+ break;
+ }
+
+ if (error != 0)
+ vt_iocnak(qp, mp, error);
+ else
+ vt_iocack(qp, mp);
+}
+
+static void
+vt_iocack(queue_t *qp, mblk_t *mp)
+{
+ struct iocblk *iocbp = (struct iocblk *)(void *)mp->b_rptr;
+
+ mp->b_datap->db_type = M_IOCACK;
+ mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
+ iocbp->ioc_error = 0;
+ iocbp->ioc_count = 0;
+ iocbp->ioc_rval = 0;
+ if (mp->b_cont != NULL) {
+ freemsg(mp->b_cont);
+ mp->b_cont = NULL;
+ }
+ qreply(qp, mp);
+}
+
+static void
+vt_iocnak(queue_t *qp, mblk_t *mp, int error)
+{
+ struct iocblk *iocp = (struct iocblk *)(void *)mp->b_rptr;
+
+ mp->b_datap->db_type = M_IOCNAK;
+ iocp->ioc_rval = 0;
+ iocp->ioc_count = 0;
+ iocp->ioc_error = error;
+ if (mp->b_cont != NULL) {
+ freemsg(mp->b_cont);
+ mp->b_cont = NULL;
+ }
+ qreply(qp, mp);
+}
+
+static void
+vt_copyin(queue_t *qp, mblk_t *mp, uint_t size)
+{
+ struct copyreq *cqp;
+
+ cqp = (struct copyreq *)(void *)mp->b_rptr;
+ cqp->cq_addr = *((caddr_t *)(void *)mp->b_cont->b_rptr);
+ cqp->cq_size = size;
+ cqp->cq_flag = 0;
+ cqp->cq_private = (mblk_t *)NULL;
+ mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
+ mp->b_datap->db_type = M_COPYIN;
+ if (mp->b_cont)
+ freemsg(mp->b_cont);
+ mp->b_cont = (mblk_t *)NULL;
+ qreply(qp, mp);
+}
+
+static void
+vt_copyout(queue_t *qp, mblk_t *mp, mblk_t *tmp, uint_t size)
+{
+ struct copyreq *cqp;
+
+ cqp = (struct copyreq *)(void *)mp->b_rptr;
+ cqp->cq_size = size;
+ cqp->cq_addr = *((caddr_t *)(void *)mp->b_cont->b_rptr);
+ cqp->cq_flag = 0;
+ cqp->cq_private = (mblk_t *)NULL;
+ mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
+ mp->b_datap->db_type = M_COPYOUT;
+ if (mp->b_cont)
+ freemsg(mp->b_cont);
+ mp->b_cont = tmp;
+ qreply(qp, mp);
+}
+
+/*
+ * Get vc state from minor.
+ * Once a caller gets a vc_state_t from this function,
+ * the vc_state_t is guaranteed not being freed before
+ * the caller leaves this STREAMS module by the D_MTPERMOD
+ * perimeter.
+ */
+vc_state_t *
+vt_minor2vc(minor_t minor)
+{
+ avl_index_t where;
+ vc_state_t target;
+
+ if (minor != VT_ACTIVE) {
+ target.vc_minor = minor;
+ return (avl_find(&vc_avl_root, &target, &where));
+ }
+
+ if (vc_active_console == VT_MINOR_INVALID)
+ target.vc_minor = 0;
+ else
+ target.vc_minor = vc_active_console;
+
+ return (avl_find(&vc_avl_root, &target, &where));
+}
+
+static void
+vt_state_init(vc_state_t *vcptr, minor_t minor)
+{
+ mutex_init(&vcptr->vc_state_lock, NULL, MUTEX_DRIVER, NULL);
+
+ mutex_enter(&vcptr->vc_state_lock);
+ vcptr->vc_flags = 0;
+ mutex_exit(&vcptr->vc_state_lock);
+
+ vcptr->vc_pid = -1;
+ vcptr->vc_dispnum = 0;
+ vcptr->vc_login = 0;
+ vcptr->vc_switchto = VT_MINOR_INVALID;
+ vcptr->vc_switch_mode = VT_AUTO;
+ vcptr->vc_relsig = SIGUSR1;
+ vcptr->vc_acqsig = SIGUSR1;
+ vcptr->vc_tem = NULL;
+ vcptr->vc_bufcallid = 0;
+ vcptr->vc_timeoutid = 0;
+ vcptr->vc_wq = NULL;
+ vcptr->vc_minor = minor;
+}
+
+void
+vt_resize(uint_t count)
+{
+ uint_t vc_num, i;
+
+ ASSERT(MUTEX_HELD(&vc_lock));
+
+ vc_num = VC_INSTANCES_COUNT;
+
+ if (count == vc_num)
+ return;
+
+ if (count > vc_num) {
+ for (i = vc_num; i < count; i++) {
+ vc_state_t *vcptr = kmem_zalloc(sizeof (vc_state_t),
+ KM_SLEEP);
+ vt_state_init(vcptr, i);
+ avl_add(&vc_avl_root, vcptr);
+ }
+ return;
+ }
+
+ for (i = vc_num; i > count; i--) {
+ avl_index_t where;
+ vc_state_t target, *found;
+
+ target.vc_minor = i - 1;
+ found = avl_find(&vc_avl_root, &target, &where);
+ ASSERT(found != NULL && found->vc_flags == 0);
+ avl_remove(&vc_avl_root, found);
+ kmem_free(found, sizeof (vc_state_t));
+ }
+}
+
+static int
+vc_avl_compare(const void *first, const void *second)
+{
+ const vc_state_t *vcptr1 = first;
+ const vc_state_t *vcptr2 = second;
+
+ if (vcptr1->vc_minor < vcptr2->vc_minor)
+ return (-1);
+
+ if (vcptr1->vc_minor == vcptr2->vc_minor)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * Only called from wc init().
+ */
+void
+vt_init(void)
+{
+#ifdef __lock_lint
+ ASSERT(NO_COMPETING_THREADS);
+#endif
+
+ avl_create(&vc_avl_root, vc_avl_compare, sizeof (vc_state_t),
+ offsetof(vc_state_t, vc_avl_node));
+
+ list_create(&vc_waitactive_list, sizeof (vc_waitactive_msg_t),
+ offsetof(vc_waitactive_msg_t, wa_list_node));
+
+ mutex_init(&vc_lock, NULL, MUTEX_DRIVER, NULL);
+ mutex_init(&vt_pending_vtno_lock, NULL, MUTEX_DRIVER, NULL);
+}
diff --git a/usr/src/uts/common/io/vcons_conf.c b/usr/src/uts/common/io/vcons_conf.c
new file mode 100644
index 0000000000..c4b9a9db3b
--- /dev/null
+++ b/usr/src/uts/common/io/vcons_conf.c
@@ -0,0 +1,116 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/termios.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/kmem.h>
+#include <sys/stat.h>
+#include <sys/sunddi.h>
+#include <sys/ddi.h>
+#include <sys/bitmap.h>
+#include <sys/sysmacros.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/zone.h>
+#include <sys/thread.h>
+#ifdef DEBUG
+#include <sys/strlog.h>
+#endif
+
+#include <sys/consdev.h>
+#include <sys/console.h>
+#include <sys/wscons.h>
+#include <sys/vt_impl.h>
+#include <sys/note.h>
+#include <sys/avl.h>
+
+/* set if console driver is attached */
+dev_info_t *wc_dip = NULL;
+/* active virtual console minor number */
+minor_t vc_active_console = VT_MINOR_INVALID;
+/* vc_state_t AVL tree */
+avl_tree_t vc_avl_root;
+/* virtual console global lock */
+kmutex_t vc_lock;
+
+_NOTE(MUTEX_PROTECTS_DATA(vc_lock, wc_dip vc_avl_root vc_active_console))
+
+/*
+ * Called from vt devname part. Checks if dip is attached. If it is,
+ * return its major number.
+ */
+major_t
+vt_wc_attached(void)
+{
+ major_t maj = (major_t)-1;
+
+ mutex_enter(&vc_lock);
+
+ if (wc_dip)
+ maj = ddi_driver_major(wc_dip);
+
+ mutex_exit(&vc_lock);
+
+ return (maj);
+}
+
+void
+vt_getactive(char *buf, int buflen)
+{
+ ASSERT(buf);
+ ASSERT(buflen != 0);
+
+ mutex_enter(&vc_lock);
+
+ if (vc_active_console == 0 || vc_active_console == VT_MINOR_INVALID)
+ (void) snprintf(buf, buflen, "/dev/console");
+ else
+ (void) snprintf(buf, buflen, "%d", vc_active_console);
+
+ mutex_exit(&vc_lock);
+}
+
+boolean_t
+vt_minor_valid(minor_t minor)
+{
+ if (consmode == CONS_FW) {
+ if (minor == 0)
+ return (B_TRUE);
+
+ return (B_FALSE);
+ }
+
+ mutex_enter(&vc_lock);
+ if (minor < VC_INSTANCES_COUNT) {
+ mutex_exit(&vc_lock);
+ return (B_TRUE);
+ }
+
+ mutex_exit(&vc_lock);
+ return (B_FALSE);
+
+}
diff --git a/usr/src/uts/common/io/warlock/tem.wlcmd b/usr/src/uts/common/io/warlock/tem.wlcmd
new file mode 100644
index 0000000000..488aef0ed3
--- /dev/null
+++ b/usr/src/uts/common/io/warlock/tem.wlcmd
@@ -0,0 +1,61 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+add bus_ops::bus_add_eventcall target warlock_dummy
+add bus_ops::bus_config target warlock_dummy
+add bus_ops::bus_get_eventcookie target warlock_dummy
+add bus_ops::bus_intr_ctl target warlock_dummy
+add bus_ops::bus_post_event target warlock_dummy
+add bus_ops::bus_remove_eventcall target warlock_dummy
+add bus_ops::bus_unconfig target warlock_dummy
+add tems_modechange_callback/cb target warlock_dummy
+add vis_polledio::copy target warlock_dummy
+add vis_polledio::cursor target warlock_dummy
+add vis_polledio::display target warlock_dummy
+add tem_safe_callbacks::tsc_display target tem_safe_text_display
+add tem_safe_callbacks::tsc_display target tem_safe_pix_display
+add tem_safe_callbacks::tsc_copy target tem_safe_text_copy
+add tem_safe_callbacks::tsc_copy target tem_safe_pix_copy
+add tem_safe_callbacks::tsc_cursor target tem_safe_text_cursor
+add tem_safe_callbacks::tsc_cursor target tem_safe_pix_cursor
+add tem_safe_callbacks::tsc_bit2pix target tem_safe_pix_bit2pix
+add tem_safe_callbacks::tsc_cls target tem_safe_text_cls
+add tem_safe_callbacks::tsc_cls target tem_safe_pix_cls
+
+root tem_initialized
+root tem_get_size
+root tem_info_init
+root tem_init
+root tem_register_modechg_cb
+root tem_write
+root tems_modechange_callback
+root tem_safe_polled_write
+root tem_activate
+root tem_destroy
+root tem_safe_image_display
+root tem_switch
+root tem_get_fbmode
+root tem_set_fbmode
diff --git a/usr/src/uts/common/io/warlock/wc.wlcmd b/usr/src/uts/common/io/warlock/wc.wlcmd
new file mode 100644
index 0000000000..4283c1ce03
--- /dev/null
+++ b/usr/src/uts/common/io/warlock/wc.wlcmd
@@ -0,0 +1,88 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+add bus_ops::bus_add_eventcall target warlock_dummy
+add bus_ops::bus_config target warlock_dummy
+add bus_ops::bus_get_eventcookie target warlock_dummy
+add bus_ops::bus_intr_ctl target warlock_dummy
+add bus_ops::bus_post_event target warlock_dummy
+add bus_ops::bus_remove_eventcall target warlock_dummy
+add bus_ops::bus_unconfig target warlock_dummy
+
+root wcuwput
+root wcopen
+root wclrput
+root wc_polled_enter
+root wc_polled_exit
+root wc_polled_getchar
+root wc_polled_ischar
+root wc_polled_putchar
+root wcclose
+root wcreioctl
+root wcrstrt
+root wc_modechg_cb
+root vc_avl_compare
+
+if test `uname -p` = "sparc"; then
+root wc_cons_wrtvec
+root wconsout
+root wcopoll
+fi
+
+#
+# The devfs part of virtual console only reads these three variables,
+# so we only have to hold the lock when writing to these variables.
+#
+readable wc_dip
+readable vc_active_console
+readable vc_state::vc_flags
+
+#
+# Only called from sdev_vtops.c, will be checked in wc_devfs.wlcmd
+#
+ignore vt_getactive
+ignore vt_wc_attached
+
+#
+# Protected by D_MTPERMODE
+#
+ignore vc_state::vc_acqsig
+ignore vc_state::vc_bufcallid
+ignore vc_state::vc_dispnum
+ignore vc_state::vc_fb_mode
+ignore vc_state::vc_login
+ignore vc_state::vc_minor
+ignore vc_state::vc_pid
+ignore vc_state::vc_relsig
+ignore vc_state::vc_switch_mode
+ignore vc_state::vc_switchto
+ignore vc_state::vc_tem
+ignore vc_state::vc_timeoutid
+ignore vc_state::vc_ttycommon.t_iocpending
+ignore vc_state::vc_ttycommon.t_readq
+ignore vc_state::vc_ttycommon.t_writeq
+ignore vc_state::vc_waitv
+ignore vc_state::vc_wq
diff --git a/usr/src/uts/common/io/warlock/wc_devfs.wlcmd b/usr/src/uts/common/io/warlock/wc_devfs.wlcmd
new file mode 100644
index 0000000000..baca059abe
--- /dev/null
+++ b/usr/src/uts/common/io/warlock/wc_devfs.wlcmd
@@ -0,0 +1,45 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This file only checks those virtual console variables
+# which are shared with devfs.
+#
+
+
+add bus_ops::bus_add_eventcall target warlock_dummy
+add bus_ops::bus_config target warlock_dummy
+add bus_ops::bus_get_eventcookie target warlock_dummy
+add bus_ops::bus_intr_ctl target warlock_dummy
+add bus_ops::bus_post_event target warlock_dummy
+add bus_ops::bus_remove_eventcall target warlock_dummy
+add bus_ops::bus_unconfig target warlock_dummy
+
+root devvt_getvnodeops
+root devvt_validate
+root devvt_readdir
+root devvt_lookup
+root devvt_create
diff --git a/usr/src/uts/common/io/wscons.c b/usr/src/uts/common/io/wscons.c
index 21b4b3fdd7..21ea9bf2a6 100644
--- a/usr/src/uts/common/io/wscons.c
+++ b/usr/src/uts/common/io/wscons.c
@@ -24,7 +24,6 @@
* Use is subject to license terms.
*/
-
/*
* "Workstation console" multiplexor driver for Sun.
*
@@ -33,6 +32,54 @@
* driver", below which is linked the primary keyboard.
*/
+/*
+ * Locking Policy:
+ * This module has a D_MTPERMOD inner perimeter which means STREAMS
+ * only allows one thread to enter this module through STREAMS entry
+ * points each time -- open() close() put() srv() qtimeout().
+ * So for the most time we do not need locking in this module, but with
+ * the following exceptions:
+ *
+ * - wc shares three global variables (wc_dip, vc_active_consle, vc_avl_root)
+ * with virtual console devname part (fs/dev/sdev_vtops.c) which get
+ * compiled into genunix.
+ *
+ * - wc_modechg_cb() is a callback function which will triggered when
+ * framebuffer display mode is changed.
+ *
+ * - vt_send_hotkeys() is triggered by timeout() which is not STREAMS MT
+ * safe.
+ *
+ * Based on the fact that virtual console devname part and wc_modechg_cb()
+ * only do read access to the above mentioned shared three global variables,
+ * It is safe to do locking this way:
+ * 1) all read access to the three global variables in THIS WC MODULE do not
+ * need locking;
+ * 2) all write access to the three global variables in THIS WC MODULE must
+ * hold vc_lock;
+ * 3) any access to the three global variables in either DEVNAME PART or the
+ * CALLBACK must hold vc_lock;
+ * 4) other global variables which are only shared in this wc module and only
+ * accessible through STREAMS entry points such as "vc_last_console",
+ * "vc_inuse_max_minor", "vc_target_console" and "vc_waitactive_list"
+ * do not need explict locking.
+ *
+ * wc_modechg_cb() does read access to vc_state_t::vc_flags,
+ * vc_state_t::vc_state_lock is used to protect concurrently accesses to
+ * vc_state_t::vc_flags which may happen from both through STREAMS entry
+ * points and wc_modechg_cb().
+ * Since wc_modechg_cb() only does read access to vc_state_t::vc_flags,
+ * The other parts of wc module (except wc_modechg_cb()) only has to hold
+ * vc_state_t::vc_flags when writing to vc_state_t::vc_flags.
+ *
+ * vt_send_hotkeys() could access vt_pending_vtno at the same time with
+ * the rest of wc module, vt_pending_vtno_lock is used to protect
+ * vt_pending_vtno.
+ *
+ * Lock order: vc_lock -> vc_state_t::vc_state_lock.
+ * No overlap between vc_lock and vt_pending_vtno_lock.
+ */
+
#include <sys/types.h>
#include <sys/param.h>
#include <sys/signal.h>
@@ -48,6 +95,14 @@
#include <sys/buf.h>
#include <sys/uio.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+#include <sys/procset.h>
+#include <sys/fault.h>
+#include <sys/siginfo.h>
+#include <sys/debug.h>
+#include <sys/session.h>
#include <sys/kmem.h>
#include <sys/cpuvar.h>
#include <sys/kbio.h>
@@ -55,15 +110,33 @@
#include <sys/fs/snode.h>
#include <sys/consdev.h>
#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/console.h>
+#include <sys/promif.h>
+#include <sys/note.h>
+#include <sys/polled_io.h>
+#include <sys/systm.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/esunddi.h>
+#include <sys/sunldi.h>
#include <sys/debug.h>
#include <sys/console.h>
#include <sys/ddi_impldefs.h>
-#include <sys/promif.h>
#include <sys/policy.h>
+#include <sys/modctl.h>
#include <sys/tem.h>
#include <sys/wscons.h>
+#include <sys/vt_impl.h>
+
+/* streams stuff */
+_NOTE(SCHEME_PROTECTS_DATA("Unshared data", copyreq))
+_NOTE(SCHEME_PROTECTS_DATA("Unshared data", copyresp))
+_NOTE(SCHEME_PROTECTS_DATA("Unshared data", datab))
+_NOTE(SCHEME_PROTECTS_DATA("Unshared data", iocblk))
+_NOTE(SCHEME_PROTECTS_DATA("Unshared data", msgb))
+_NOTE(SCHEME_PROTECTS_DATA("Unshared data", queue))
#define MINLINES 10
#define MAXLINES 48
@@ -75,30 +148,37 @@
#define LOSCREENCOLS 80
#define HISCREENCOLS 120
-struct wscons {
- struct tem *wc_tem; /* Terminal emulator state */
- int wc_flags; /* random flags (protected by */
- /* write-side exclusion lock */
+struct wscons_state {
dev_t wc_dev; /* major/minor for this device */
- tty_common_t wc_ttycommon; /* data common to all tty drivers */
#ifdef _HAVE_TEM_FIRMWARE
- int wc_pendc; /* pending output character */
int wc_defer_output; /* set if output device is "slow" */
#endif /* _HAVE_TEM_FIRMWARE */
queue_t *wc_kbdqueue; /* "console keyboard" device queue */
/* below us */
- bufcall_id_t wc_bufcallid; /* id returned by qbufcall */
- timeout_id_t wc_timeoutid; /* id returned by qtimeout */
cons_polledio_t wc_polledio; /* polled I/O function pointers */
cons_polledio_t *wc_kb_polledio; /* keyboard's polledio */
unsigned int wc_kb_getpolledio_id; /* id for kb CONSOPENPOLLEDIO */
+ queue_t *wc_pending_wq;
mblk_t *wc_pending_link; /* I_PLINK pending for kb polledio */
} wscons;
-#define WCS_ISOPEN 0x00000001 /* open is complete */
-#define WCS_STOPPED 0x00000002 /* output is stopped */
-#define WCS_DELAY 0x00000004 /* waiting for delay to finish */
-#define WCS_BUSY 0x00000008 /* waiting for transmission to finish */
+/*
+ * This module has a D_MTPERMOD inner perimeter, so we don't need to protect
+ * the variables only shared within this module
+ */
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", wscons))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", wscons_state))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vt_stat))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_waitactive_msg))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", tty_common))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vt_mode))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vt_dispinfo))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", winsize))
+_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_last_console))
+
+#ifdef _HAVE_TEM_FIRMWARE
+ssize_t wc_cons_wrtvec(promif_redir_arg_t arg, uchar_t *s, size_t n);
+#endif /* _HAVE_TEM_FIRMWARE */
static int wcopen(queue_t *, dev_t *, int, int, cred_t *);
static int wcclose(queue_t *, int, cred_t *);
@@ -166,7 +246,6 @@ static struct streamtab wcinfo = {
static int wc_info(dev_info_t *, ddi_info_cmd_t, void *, void **result);
static int wc_attach(dev_info_t *, ddi_attach_cmd_t);
-static dev_info_t *wc_dip;
DDI_DEFINE_STREAM_OPS(wc_ops, nulldev, nulldev, wc_attach, nodev, nodev,
wc_info, D_MTPERMOD | D_MP, &wcinfo, ddi_quiesce_not_supported);
@@ -178,24 +257,20 @@ static void wcopoll(void *);
static void wconsout(void *);
#endif /* _HAVE_TEM_FIRMWARE */
static void wcrstrt(void *);
-static void wcstart(void);
-static void wc_open_kb_polledio(struct wscons *wc, queue_t *q, mblk_t *mp);
-static void wc_close_kb_polledio(struct wscons *wc, queue_t *q, mblk_t *mp);
-static void wc_polled_putchar(cons_polledio_arg_t arg, unsigned char c);
+static void wcstart(void *);
+static void wc_open_kb_polledio(struct wscons_state *wc, queue_t *q,
+ mblk_t *mp);
+static void wc_close_kb_polledio(struct wscons_state *wc, queue_t *q,
+ mblk_t *mp);
+static void wc_polled_putchar(cons_polledio_arg_t arg,
+ unsigned char c);
static boolean_t wc_polled_ischar(cons_polledio_arg_t arg);
static int wc_polled_getchar(cons_polledio_arg_t arg);
static void wc_polled_enter(cons_polledio_arg_t arg);
static void wc_polled_exit(cons_polledio_arg_t arg);
-static void wc_get_size(struct wscons *wscons);
+void wc_get_size(vc_state_t *pvc);
static void wc_modechg_cb(tem_modechg_cb_arg_t arg);
-#include <sys/types.h>
-#include <sys/conf.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/modctl.h>
-
static struct dev_ops wc_ops;
/*
@@ -209,7 +284,6 @@ static void wc_dprintf(const char *fmt, ...) __KPRINTFLIKE(1);
(((l) >= wc_errlevel) && ((m) & wc_errmask) ? \
wc_dprintf args : \
(void) 0)
-
/*
* Severity levels for printing
*/
@@ -232,7 +306,6 @@ uint_t wc_errlevel = PRINT_L2;
/*
* Module linkage information for the kernel.
*/
-
static struct modldrv modldrv = {
&mod_driverops, /* Type of module. This one is a pseudo driver */
"Workstation multiplexer Driver 'wc'",
@@ -248,7 +321,10 @@ static struct modlinkage modlinkage = {
int
_init(void)
{
- return (mod_install(&modlinkage));
+ int rc;
+ if ((rc = mod_install(&modlinkage)) == 0)
+ vt_init();
+ return (rc);
}
int
@@ -267,15 +343,23 @@ _info(struct modinfo *modinfop)
static int
wc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
+ /* create minor node for workstation hard console */
if (ddi_create_minor_node(devi, "wscons", S_IFCHR,
0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
ddi_remove_minor_node(devi, NULL);
- return (-1);
+ return (DDI_FAILURE);
}
+
+ mutex_enter(&vc_lock);
+
wc_dip = devi;
bzero(&(wscons.wc_polledio), sizeof (wscons.wc_polledio));
+ vt_resize(VC_DEFAULT_COUNT);
+
+ mutex_exit(&vc_lock);
+
return (DDI_SUCCESS);
}
@@ -313,104 +397,95 @@ wc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
static char obuf[MAXHIWAT];
#endif /* _HAVE_TEM_FIRMWARE */
-/*ARGSUSED*/
-static int
-wcopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
+static void
+wc_init_polledio(void)
{
static boolean_t polledio_inited = B_FALSE;
- struct termios *termiosp;
- int len;
-
- if (getminor(*devp) != 0)
- return (ENXIO); /* sorry, only one per customer */
+ _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data",
+ polledio_inited))
- if (!(wscons.wc_flags & WCS_ISOPEN)) {
- mutex_init(&wscons.wc_ttycommon.t_excl, NULL, MUTEX_DEFAULT,
- NULL);
- wscons.wc_ttycommon.t_iflag = 0;
- /*
- * Get the default termios settings (cflag).
- * These are stored as a property in the
- * "options" node.
- */
- if (ddi_getlongprop(DDI_DEV_T_ANY,
- ddi_root_node(), 0, "ttymodes",
- (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
- len == sizeof (struct termios)) {
-
- wscons.wc_ttycommon.t_cflag = termiosp->c_cflag;
- kmem_free(termiosp, len);
- } else {
- /*
- * Gack! Whine about it.
- */
- cmn_err(CE_WARN,
- "wc: Couldn't get ttymodes property!\n");
- }
- wscons.wc_ttycommon.t_iocpending = NULL;
- wscons.wc_flags = WCS_ISOPEN;
-
- wscons.wc_dev = *devp;
- wc_get_size(&wscons);
+ if (polledio_inited)
+ return;
- if (!polledio_inited) {
- polledio_inited = B_TRUE;
+ polledio_inited = B_TRUE;
- /*
- * Initialize the parts of the polled I/O struct that
- * are common to both input and output modes, but which
- * don't flag to the upper layers, which if any of the
- * two modes are available. We don't know at this point
- * if system is configured CONS_KFB, but we will when
- * consconfig_dacf asks us with CONSOPENPOLLED I/O.
- */
- wscons.wc_polledio.cons_polledio_version =
- CONSPOLLEDIO_V0;
- wscons.wc_polledio.cons_polledio_argument =
- (cons_polledio_arg_t)&wscons;
- wscons.wc_polledio.cons_polledio_enter =
- wc_polled_enter;
- wscons.wc_polledio.cons_polledio_exit =
- wc_polled_exit;
+ /*
+ * Initialize the parts of the polled I/O struct that
+ * are common to both input and output modes, but which
+ * don't flag to the upper layers, which if any of the
+ * two modes are available. We don't know at this point
+ * if system is configured CONS_KFB, but we will when
+ * consconfig_dacf asks us with CONSOPENPOLLED I/O.
+ */
+ bzero(&(wscons.wc_polledio), sizeof (wscons.wc_polledio));
+ wscons.wc_polledio.cons_polledio_version =
+ CONSPOLLEDIO_V0;
+ wscons.wc_polledio.cons_polledio_argument =
+ (cons_polledio_arg_t)&wscons;
+ wscons.wc_polledio.cons_polledio_enter =
+ wc_polled_enter;
+ wscons.wc_polledio.cons_polledio_exit =
+ wc_polled_exit;
#ifdef _HAVE_TEM_FIRMWARE
- /*
- * If we're talking directly to a framebuffer, we assume
- * that it's a "slow" device, so that rendering should
- * be deferred to a timeout or softcall so that we write
- * a bunch of characters at once.
- */
- wscons.wc_defer_output = prom_stdout_is_framebuffer();
+ /*
+ * If we're talking directly to a framebuffer, we assume
+ * that it's a "slow" device, so that rendering should
+ * be deferred to a timeout or softcall so that we write
+ * a bunch of characters at once.
+ */
+ wscons.wc_defer_output = prom_stdout_is_framebuffer();
#endif /* _HAVE_TEM_FIRMWARE */
- }
- }
+}
- if (wscons.wc_ttycommon.t_flags & TS_XCLUDE) {
- if (secpolicy_excl_open(crp) != 0) {
- return (EBUSY);
- }
- }
- wscons.wc_ttycommon.t_readq = q;
- wscons.wc_ttycommon.t_writeq = WR(q);
- qprocson(q);
- return (0);
+/*ARGSUSED*/
+static int
+wcopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
+{
+ int minor;
+
+ wc_init_polledio();
+ minor = (int)getminor(*devp);
+ return (vt_open(minor, q, crp));
}
/*ARGSUSED*/
static int
wcclose(queue_t *q, int flag, cred_t *crp)
{
+ vc_state_t *pvc = (vc_state_t *)q->q_ptr;
+
qprocsoff(q);
- if (wscons.wc_bufcallid != 0) {
- qunbufcall(q, wscons.wc_bufcallid);
- wscons.wc_bufcallid = 0;
- }
- if (wscons.wc_timeoutid != 0) {
- (void) quntimeout(q, wscons.wc_timeoutid);
- wscons.wc_timeoutid = 0;
+
+ mutex_enter(&vc_lock);
+
+ if (pvc->vc_minor == 0 || pvc->vc_minor == vc_active_console) {
+
+ /*
+ * If we lose the system console,
+ * no any other active consoles.
+ */
+ if (pvc->vc_minor == 0 && pvc->vc_minor == vc_active_console) {
+ vc_active_console = VT_MINOR_INVALID;
+ vc_last_console = VT_MINOR_INVALID;
+ }
+
+ /*
+ * just clean for our primary console
+ * and active console
+ */
+ mutex_enter(&pvc->vc_state_lock);
+ vt_clean(q, pvc);
+ mutex_exit(&pvc->vc_state_lock);
+
+ mutex_exit(&vc_lock);
+
+ return (0);
}
- ttycommon_close(&wscons.wc_ttycommon);
- wscons.wc_flags = 0;
+ vt_close(q, pvc, crp);
+
+ mutex_exit(&vc_lock);
+
return (0);
}
@@ -424,16 +499,24 @@ wcclose(queue_t *q, int flag, cred_t *crp)
static int
wcuwput(queue_t *q, mblk_t *mp)
{
+ vc_state_t *pvc = (vc_state_t *)q->q_ptr;
+
switch (mp->b_datap->db_type) {
case M_STOP:
- wscons.wc_flags |= WCS_STOPPED;
+ mutex_enter(&pvc->vc_state_lock);
+ pvc->vc_flags |= WCS_STOPPED;
+ mutex_exit(&pvc->vc_state_lock);
+
freemsg(mp);
break;
case M_START:
- wscons.wc_flags &= ~WCS_STOPPED;
- wcstart();
+ mutex_enter(&pvc->vc_state_lock);
+ pvc->vc_flags &= ~WCS_STOPPED;
+ mutex_exit(&pvc->vc_state_lock);
+
+ wcstart(pvc);
freemsg(mp);
break;
@@ -441,7 +524,7 @@ wcuwput(queue_t *q, mblk_t *mp)
struct iocblk *iocp;
struct linkblk *linkp;
- iocp = (void *)mp->b_rptr;
+ iocp = (struct iocblk *)(void *)mp->b_rptr;
switch (iocp->ioc_cmd) {
case I_LINK: /* stupid, but permitted */
@@ -451,7 +534,7 @@ wcuwput(queue_t *q, mblk_t *mp)
miocnak(q, mp, 0, EINVAL);
return (0);
}
- linkp = (void *)mp->b_cont->b_rptr;
+ linkp = (struct linkblk *)(void *)mp->b_cont->b_rptr;
wscons.wc_kbdqueue = WR(linkp->l_qbot);
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_count = 0;
@@ -460,7 +543,7 @@ wcuwput(queue_t *q, mblk_t *mp)
case I_UNLINK: /* stupid, but permitted */
case I_PUNLINK:
- linkp = (void *)mp->b_cont->b_rptr;
+ linkp = (struct linkblk *)(void *)mp->b_cont->b_rptr;
if (wscons.wc_kbdqueue != WR(linkp->l_qbot)) {
/* not us */
miocnak(q, mp, 0, EINVAL);
@@ -486,13 +569,14 @@ wcuwput(queue_t *q, mblk_t *mp)
* start routine, just in case.
*/
(void) putq(q, mp);
- wcstart();
+ wcstart(pvc);
break;
case CONSSETABORTENABLE:
case CONSGETABORTENABLE:
case KIOCSDIRECT:
if (wscons.wc_kbdqueue != NULL) {
+ wscons.wc_pending_wq = q;
(void) putnext(wscons.wc_kbdqueue, mp);
break;
}
@@ -537,7 +621,11 @@ wcuwput(queue_t *q, mblk_t *mp)
* and poke the start routine.
*/
(void) putq(q, mp);
- wcstart();
+ wcstart(pvc);
+ break;
+
+ case M_IOCDATA:
+ vt_miocdata(q, mp);
break;
default:
@@ -560,14 +648,15 @@ wcuwput(queue_t *q, mblk_t *mp)
static void
wcreioctl(void *arg)
{
+ vc_state_t *pvc = (vc_state_t *)arg;
queue_t *q;
mblk_t *mp;
- wscons.wc_bufcallid = 0;
- q = wscons.wc_ttycommon.t_writeq;
- if ((mp = wscons.wc_ttycommon.t_iocpending) != NULL) {
+ pvc->vc_bufcallid = 0;
+ q = pvc->vc_ttycommon.t_writeq;
+ if ((mp = pvc->vc_ttycommon.t_iocpending) != NULL) {
/* not pending any more */
- wscons.wc_ttycommon.t_iocpending = NULL;
+ pvc->vc_ttycommon.t_iocpending = NULL;
wcioctl(q, mp);
}
}
@@ -618,12 +707,19 @@ wc_getterm(mblk_t *mp)
static void
wcioctl(queue_t *q, mblk_t *mp)
{
+ vc_state_t *pvc = (vc_state_t *)q->q_ptr;
struct iocblk *iocp;
size_t datasize;
int error;
long len;
- iocp = (void *)mp->b_rptr;
+ iocp = (struct iocblk *)(void *)mp->b_rptr;
+
+ if ((iocp->ioc_cmd & VTIOC) == VTIOC ||
+ (iocp->ioc_cmd & KDIOC) == KDIOC) {
+ vt_ioctl(q, mp);
+ return;
+ }
switch (iocp->ioc_cmd) {
case TIOCSWINSZ:
@@ -698,21 +794,17 @@ wcioctl(queue_t *q, mblk_t *mp)
iocp->ioc_error = EINVAL;
/*
- * If we're already open, fail.
- */
- if (wscons.wc_tem != NULL)
- goto open_fail;
-
- /*
* If we don't have exactly one continuation block, fail.
*/
- if (mp->b_cont == NULL || mp->b_cont->b_cont != NULL)
+ if (mp->b_cont == NULL ||
+ mp->b_cont->b_cont != NULL)
goto open_fail;
/*
* If there's no null terminator in the string, fail.
*/
- len = MBLKL(mp->b_cont);
+ /* LINTED E_PTRDIFF_OVERFLOW */
+ len = mp->b_cont->b_wptr - mp->b_cont->b_rptr;
if (memchr(mp->b_cont->b_rptr, 0, len) == NULL)
goto open_fail;
@@ -720,8 +812,8 @@ wcioctl(queue_t *q, mblk_t *mp)
* NOTE: should eventually get default
* dimensions from a property, e.g. screen-#rows.
*/
- iocp->ioc_error = tem_init(&wscons.wc_tem,
- (char *)mp->b_cont->b_rptr, iocp->ioc_cr);
+ iocp->ioc_error = tem_info_init((char *)mp->b_cont->b_rptr,
+ iocp->ioc_cr);
/*
* Of course, if the terminal emulator initialization
* failed, fail.
@@ -729,13 +821,23 @@ wcioctl(queue_t *q, mblk_t *mp)
if (iocp->ioc_error != 0)
goto open_fail;
- tem_register_modechg_cb(wscons.wc_tem, wc_modechg_cb,
- (tem_modechg_cb_arg_t)&wscons);
+#ifdef _HAVE_TEM_FIRMWARE
+ if (prom_stdout_is_framebuffer()) {
+ /*
+ * Drivers in the console stream may emit additional
+ * messages before we are ready. This causes text
+ * overwrite on the screen. So we set the redirection
+ * here. It is safe because the ioctl in consconfig_dacf
+ * will succeed and consmode will be set to CONS_KFB.
+ */
+ prom_set_stdout_redirect(wc_cons_wrtvec,
+ (promif_redir_arg_t)NULL);
- /*
- * Refresh terminal size with info from terminal emulator.
- */
- wc_get_size(&wscons);
+ }
+#endif /* _HAVE_TEM_FIRMWARE */
+
+ tem_register_modechg_cb(wc_modechg_cb,
+ (tem_modechg_cb_arg_t)&wscons);
/*
* ... and succeed.
@@ -779,12 +881,12 @@ close_fail:
* request that we be called back when we stand a
* better chance of allocating the data.
*/
- datasize = ttycommon_ioctl(&wscons.wc_ttycommon, q, mp, &error);
+ datasize = ttycommon_ioctl(&pvc->vc_ttycommon, q, mp, &error);
if (datasize != 0) {
- if (wscons.wc_bufcallid != 0)
- qunbufcall(q, wscons.wc_bufcallid);
- wscons.wc_bufcallid = qbufcall(q, datasize, BPRI_HI,
- wcreioctl, NULL);
+ if (pvc->vc_bufcallid != 0)
+ qunbufcall(q, pvc->vc_bufcallid);
+ pvc->vc_bufcallid = qbufcall(q, datasize, BPRI_HI,
+ wcreioctl, pvc);
return;
}
@@ -810,7 +912,7 @@ close_fail:
* the lower driver services this message.
*/
static void
-wc_open_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp)
+wc_open_kb_polledio(struct wscons_state *wscons, queue_t *q, mblk_t *mp)
{
mblk_t *mp2;
struct iocblk *iocp;
@@ -838,12 +940,13 @@ wc_open_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp)
goto nomem;
}
- iocp = (void *)mp2->b_rptr;
+ iocp = (struct iocblk *)(void *)mp2->b_rptr;
iocp->ioc_count = sizeof (struct cons_polledio *);
mp2->b_cont->b_wptr = mp2->b_cont->b_rptr +
sizeof (struct cons_polledio *);
+ wscons->wc_pending_wq = q;
wscons->wc_pending_link = mp;
wscons->wc_kb_getpolledio_id = iocp->ioc_id;
@@ -852,7 +955,7 @@ wc_open_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp)
return;
nomem:
- iocp = (void *)mp->b_rptr;
+ iocp = (struct iocblk *)(void *)mp->b_rptr;
iocp->ioc_error = ENOMEM;
mp->b_datap->db_type = M_IOCNAK;
qreply(q, mp);
@@ -865,7 +968,7 @@ nomem:
* driver services this message.
*/
static void
-wc_close_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp)
+wc_close_kb_polledio(struct wscons_state *wscons, queue_t *q, mblk_t *mp)
{
mblk_t *mp2;
struct iocblk *iocp;
@@ -894,10 +997,11 @@ wc_close_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp)
goto nomem;
}
- iocp = (void *)mp2->b_rptr;
+ iocp = (struct iocblk *)(void *)mp2->b_rptr;
iocp->ioc_count = 0;
+ wscons->wc_pending_wq = q;
wscons->wc_pending_link = mp;
wscons->wc_kb_getpolledio_id = iocp->ioc_id;
@@ -906,7 +1010,7 @@ wc_close_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp)
return;
nomem:
- iocp = (void *)mp->b_rptr;
+ iocp = (struct iocblk *)(void *)mp->b_rptr;
iocp->ioc_error = ENOMEM;
mp->b_datap->db_type = M_IOCNAK;
qreply(q, mp);
@@ -917,20 +1021,26 @@ nomem:
static void
wcopoll(void *arg)
{
+ vc_state_t *pvc = (vc_state_t *)arg;
queue_t *q;
- q = wscons.wc_ttycommon.t_writeq;
- wscons.wc_timeoutid = 0;
+ q = pvc->vc_ttycommon.t_writeq;
+ pvc->vc_timeoutid = 0;
+
+ mutex_enter(&pvc->vc_state_lock);
+
/* See if we can continue output */
- if ((wscons.wc_flags & WCS_BUSY) && wscons.wc_pendc != -1) {
- if (prom_mayput((char)wscons.wc_pendc) == 0) {
- wscons.wc_pendc = -1;
- wscons.wc_flags &= ~WCS_BUSY;
- if (!(wscons.wc_flags&(WCS_DELAY|WCS_STOPPED)))
- wcstart();
+ if ((pvc->vc_flags & WCS_BUSY) && pvc->vc_pendc != -1) {
+ if (prom_mayput((char)pvc->vc_pendc) == 0) {
+ pvc->vc_pendc = -1;
+ pvc->vc_flags &= ~WCS_BUSY;
+ if (!(pvc->vc_flags&(WCS_DELAY|WCS_STOPPED)))
+ wcstart(pvc);
} else
- wscons.wc_timeoutid = qtimeout(q, wcopoll, NULL, 1);
+ pvc->vc_timeoutid = qtimeout(q, wcopoll, pvc, 1);
}
+
+ mutex_exit(&pvc->vc_state_lock);
}
#endif /* _HAVE_TEM_FIRMWARE */
@@ -941,17 +1051,38 @@ wcopoll(void *arg)
static void
wcrstrt(void *arg)
{
- ASSERT(wscons.wc_ttycommon.t_writeq != NULL);
- wscons.wc_flags &= ~WCS_DELAY;
- wcstart();
+ vc_state_t *pvc = (vc_state_t *)arg;
+
+ ASSERT(pvc->vc_ttycommon.t_writeq != NULL);
+
+ mutex_enter(&pvc->vc_state_lock);
+ pvc->vc_flags &= ~WCS_DELAY;
+ mutex_exit(&pvc->vc_state_lock);
+
+ wcstart(pvc);
+}
+
+/*
+ * get screen terminal for current output
+ */
+static tem_vt_state_t
+wc_get_screen_tem(vc_state_t *pvc)
+{
+ if (!tem_initialized(pvc->vc_tem) ||
+ tem_get_fbmode(pvc->vc_tem) != KD_TEXT)
+ return (NULL);
+
+ return (pvc->vc_tem);
}
/*
* Start console output
*/
static void
-wcstart(void)
+wcstart(void *arg)
{
+ vc_state_t *pvc = (vc_state_t *)arg;
+ tem_vt_state_t ptem = NULL;
#ifdef _HAVE_TEM_FIRMWARE
int c;
ssize_t cc;
@@ -966,14 +1097,14 @@ wcstart(void)
* restarted, output to finish draining), don't grab anything
* new.
*/
- if (wscons.wc_flags & (WCS_DELAY|WCS_BUSY|WCS_STOPPED))
+ if (pvc->vc_flags & (WCS_DELAY|WCS_BUSY|WCS_STOPPED))
return;
- q = wscons.wc_ttycommon.t_writeq;
+ q = pvc->vc_ttycommon.t_writeq;
/*
* assumes that we have been called by whoever holds the
* exclusionary lock on the write-side queue (protects
- * wc_flags and wc_pendc).
+ * vc_flags and vc_pendc).
*/
for (;;) {
if ((bp = getq(q)) == NULL)
@@ -993,11 +1124,15 @@ wcstart(void)
* delay expires; it will turn WCS_DELAY off,
* and call "wcstart" to grab the next message.
*/
- if (wscons.wc_timeoutid != 0)
- (void) quntimeout(q, wscons.wc_timeoutid);
- wscons.wc_timeoutid = qtimeout(q, wcrstrt, NULL,
+ if (pvc->vc_timeoutid != 0)
+ (void) quntimeout(q, pvc->vc_timeoutid);
+ pvc->vc_timeoutid = qtimeout(q, wcrstrt, pvc,
(clock_t)(*(unsigned char *)bp->b_rptr + 6));
- wscons.wc_flags |= WCS_DELAY;
+
+ mutex_enter(&pvc->vc_state_lock);
+ pvc->vc_flags |= WCS_DELAY;
+ mutex_exit(&pvc->vc_state_lock);
+
freemsg(bp);
return; /* wait for this to finish */
@@ -1014,23 +1149,34 @@ wcstart(void)
#ifdef _HAVE_TEM_FIRMWARE
if (consmode == CONS_KFB) {
#endif /* _HAVE_TEM_FIRMWARE */
- if (wscons.wc_tem != NULL) {
+ if ((ptem = wc_get_screen_tem(pvc)) != NULL) {
+
for (nbp = bp; nbp != NULL; nbp = nbp->b_cont) {
if (nbp->b_wptr > nbp->b_rptr) {
- (void) tem_write(wscons.wc_tem,
+ (void) tem_write(ptem,
nbp->b_rptr,
- MBLKL(nbp),
+ /* LINTED */
+ nbp->b_wptr - nbp->b_rptr,
kcred);
}
}
- freemsg(bp);
+
}
+
+ freemsg(bp);
+
#ifdef _HAVE_TEM_FIRMWARE
continue;
}
/* consmode = CONS_FW */
- if ((cc = MBLKL(bp)) == 0) {
+ if (pvc->vc_minor != 0) {
+ freemsg(bp);
+ continue;
+ }
+
+ /* LINTED E_PTRDIFF_OVERFLOW */
+ if ((cc = bp->b_wptr - bp->b_rptr) == 0) {
freemsg(bp);
continue;
}
@@ -1043,17 +1189,20 @@ wcstart(void)
* Never do output here;
* it takes forever.
*/
- wscons.wc_flags |= WCS_BUSY;
- wscons.wc_pendc = -1;
+ mutex_enter(&pvc->vc_state_lock);
+ pvc->vc_flags |= WCS_BUSY;
+ mutex_exit(&pvc->vc_state_lock);
+
+ pvc->vc_pendc = -1;
(void) putbq(q, bp);
if (q->q_count > 128) { /* do it soon */
- softcall(wconsout, NULL);
+ softcall(wconsout, pvc);
} else { /* wait a bit */
- if (wscons.wc_timeoutid != 0)
+ if (pvc->vc_timeoutid != 0)
(void) quntimeout(q,
- wscons.wc_timeoutid);
- wscons.wc_timeoutid = qtimeout(q, wconsout,
- NULL, hz / 30);
+ pvc->vc_timeoutid);
+ pvc->vc_timeoutid = qtimeout(q, wconsout,
+ pvc, hz / 30);
}
return;
}
@@ -1061,13 +1210,17 @@ wcstart(void)
c = *bp->b_rptr++;
cc--;
if (prom_mayput((char)c) != 0) {
- wscons.wc_flags |= WCS_BUSY;
- wscons.wc_pendc = c;
- if (wscons.wc_timeoutid != 0)
+
+ mutex_enter(&pvc->vc_state_lock);
+ pvc->vc_flags |= WCS_BUSY;
+ mutex_exit(&pvc->vc_state_lock);
+
+ pvc->vc_pendc = c;
+ if (pvc->vc_timeoutid != 0)
(void) quntimeout(q,
- wscons.wc_timeoutid);
- wscons.wc_timeoutid = qtimeout(q, wcopoll,
- NULL, 1);
+ pvc->vc_timeoutid);
+ pvc->vc_timeoutid = qtimeout(q, wcopoll,
+ pvc, 1);
if (bp != NULL)
/* not done with this message yet */
(void) putbq(q, bp);
@@ -1079,7 +1232,8 @@ wcstart(void)
freeb(nbp);
if (bp == NULL)
return;
- cc = MBLKL(bp);
+ /* LINTED E_PTRDIFF_OVERFLOW */
+ cc = bp->b_wptr - bp->b_rptr;
}
}
#endif /* _HAVE_TEM_FIRMWARE */
@@ -1093,8 +1247,9 @@ wcstart(void)
*/
/* ARGSUSED */
static void
-wconsout(void *dummy)
+wconsout(void *arg)
{
+ vc_state_t *pvc = (vc_state_t *)arg;
uchar_t *cp;
ssize_t cc;
queue_t *q;
@@ -1103,7 +1258,7 @@ wconsout(void *dummy)
char *current_position;
ssize_t bytes_left;
- if ((q = wscons.wc_ttycommon.t_writeq) == NULL) {
+ if ((q = pvc->vc_ttycommon.t_writeq) == NULL) {
return; /* not attached to a stream */
}
@@ -1126,7 +1281,8 @@ wconsout(void *dummy)
do {
cp = bp->b_rptr;
- cc = MBLKL(bp);
+ /* LINTED E_PTRDIFF_OVERFLOW */
+ cc = bp->b_wptr - cp;
while (cc != 0) {
if (bytes_left == 0) {
/*
@@ -1152,8 +1308,11 @@ transmit:
if ((cc = MAXHIWAT - bytes_left) != 0)
console_puts(obuf, cc);
- wscons.wc_flags &= ~WCS_BUSY;
- wcstart();
+ mutex_enter(&pvc->vc_state_lock);
+ pvc->vc_flags &= ~WCS_BUSY;
+ mutex_exit(&pvc->vc_state_lock);
+
+ wcstart(pvc);
}
#endif /* _HAVE_TEM_FIRMWARE */
@@ -1164,9 +1323,12 @@ transmit:
static int
wclrput(queue_t *q, mblk_t *mp)
{
+ vc_state_t *pvc;
queue_t *upq;
struct iocblk *iocp;
+ pvc = vt_minor2vc(VT_ACTIVE);
+
DPRINTF(PRINT_L1, PRINT_MASK_ALL,
("wclrput: wclrput type = 0x%x\n", mp->b_datap->db_type));
@@ -1190,20 +1352,26 @@ wclrput(queue_t *q, mblk_t *mp)
break;
case M_DATA:
- if ((upq = wscons.wc_ttycommon.t_readq) != NULL) {
+ if (consmode == CONS_KFB && vt_check_hotkeys(mp)) {
+ freemsg(mp);
+ break;
+ }
+
+ if ((upq = pvc->vc_ttycommon.t_readq) != NULL) {
if (!canput(upq->q_next)) {
- ttycommon_qfull(&wscons.wc_ttycommon, upq);
- wcstart();
+ ttycommon_qfull(&pvc->vc_ttycommon, upq);
+ wcstart(pvc);
freemsg(mp);
- } else
+ } else {
putnext(upq, mp);
+ }
} else
freemsg(mp);
break;
case M_IOCACK:
case M_IOCNAK:
- iocp = (void *)mp->b_rptr;
+ iocp = (struct iocblk *)(void *)mp->b_rptr;
if (wscons.wc_pending_link != NULL &&
iocp->ioc_id == wscons.wc_kb_getpolledio_id) {
switch (mp->b_datap->db_type) {
@@ -1211,14 +1379,13 @@ wclrput(queue_t *q, mblk_t *mp)
case M_IOCACK:
switch (iocp->ioc_cmd) {
-
case CONSOPENPOLLEDIO:
DPRINTF(PRINT_L1, PRINT_MASK_ALL,
("wclrput: "
"ACK CONSOPENPOLLEDIO\n"));
wscons.wc_kb_polledio =
- *(struct cons_polledio **)(void *)
- mp->b_cont->b_rptr;
+ *(struct cons_polledio **)
+ (void *)mp->b_cont->b_rptr;
wscons.wc_polledio.
cons_polledio_getchar =
wc_polled_getchar;
@@ -1240,7 +1407,8 @@ wclrput(queue_t *q, mblk_t *mp)
break;
default:
DPRINTF(PRINT_L1, PRINT_MASK_ALL,
- ("wclrput: ACK UNKNOWN\n"));
+ ("wclrput: "
+ "ACK UNKNOWN\n"));
}
break;
@@ -1282,11 +1450,17 @@ wclrput(queue_t *q, mblk_t *mp)
/* FALLTHROUGH */
default: /* inc M_ERROR, M_HANGUP, M_IOCACK, M_IOCNAK, ... */
- DPRINTF(PRINT_L1, PRINT_MASK_ALL,
- ("wclrput: Message DISCARDED\n"));
- if ((upq = wscons.wc_ttycommon.t_readq) != NULL) {
+ if (wscons.wc_pending_wq != NULL) {
+ qreply(wscons.wc_pending_wq, mp);
+ wscons.wc_pending_wq = NULL;
+ break;
+ }
+
+ if ((upq = pvc->vc_ttycommon.t_readq) != NULL) {
putnext(upq, mp);
} else {
+ DPRINTF(PRINT_L1, PRINT_MASK_ALL,
+ ("wclrput: Message DISCARDED\n"));
freemsg(mp);
}
break;
@@ -1295,6 +1469,38 @@ wclrput(queue_t *q, mblk_t *mp)
return (0);
}
+#ifdef _HAVE_TEM_FIRMWARE
+/*
+ * This routine exists so that prom_write() can redirect writes
+ * to the framebuffer through the kernel terminal emulator, if
+ * that configuration is selected during consconfig.
+ * When the kernel terminal emulator is enabled, consconfig_dacf
+ * sets up the PROM output redirect vector to enter this function.
+ * During panic the console will already be powered up as part of
+ * calling into the prom_*() layer.
+ */
+/* ARGSUSED */
+ssize_t
+wc_cons_wrtvec(promif_redir_arg_t arg, uchar_t *s, size_t n)
+{
+ vc_state_t *pvc;
+
+ pvc = vt_minor2vc(VT_ACTIVE);
+
+ if (pvc->vc_tem == NULL)
+ return (0);
+
+ ASSERT(consmode == CONS_KFB);
+
+ if (panicstr)
+ polled_io_cons_write(s, n);
+ else
+ (void) tem_write(pvc->vc_tem, s, n, kcred);
+
+ return (n);
+}
+#endif /* _HAVE_TEM_FIRMWARE */
+
/*
* These are for systems without OBP, and for devices that cannot be
* shared between Solaris and the OBP.
@@ -1302,10 +1508,14 @@ wclrput(queue_t *q, mblk_t *mp)
static void
wc_polled_putchar(cons_polledio_arg_t arg, unsigned char c)
{
+ vc_state_t *pvc;
+
+ pvc = vt_minor2vc(VT_ACTIVE);
+
if (c == '\n')
wc_polled_putchar(arg, '\r');
- if (wscons.wc_tem == NULL) {
+ if (pvc->vc_tem == NULL) {
/*
* We have no terminal emulator configured. We have no
* recourse but to drop the output on the floor.
@@ -1313,7 +1523,7 @@ wc_polled_putchar(cons_polledio_arg_t arg, unsigned char c)
return;
}
- tem_polled_write(wscons.wc_tem, &c, 1);
+ tem_safe_polled_write(pvc->vc_tem, &c, 1);
}
/*
@@ -1323,7 +1533,7 @@ wc_polled_putchar(cons_polledio_arg_t arg, unsigned char c)
static int
wc_polled_getchar(cons_polledio_arg_t arg)
{
- struct wscons *wscons = (struct wscons *)arg;
+ struct wscons_state *wscons = (struct wscons_state *)arg;
if (wscons->wc_kb_polledio == NULL) {
prom_printf("wscons: getchar with no keyboard support");
@@ -1339,7 +1549,7 @@ wc_polled_getchar(cons_polledio_arg_t arg)
static boolean_t
wc_polled_ischar(cons_polledio_arg_t arg)
{
- struct wscons *wscons = (struct wscons *)arg;
+ struct wscons_state *wscons = (struct wscons_state *)arg;
if (wscons->wc_kb_polledio == NULL)
return (B_FALSE);
@@ -1351,7 +1561,7 @@ wc_polled_ischar(cons_polledio_arg_t arg)
static void
wc_polled_enter(cons_polledio_arg_t arg)
{
- struct wscons *wscons = (struct wscons *)arg;
+ struct wscons_state *wscons = (struct wscons_state *)arg;
if (wscons->wc_kb_polledio == NULL)
return;
@@ -1365,7 +1575,7 @@ wc_polled_enter(cons_polledio_arg_t arg)
static void
wc_polled_exit(cons_polledio_arg_t arg)
{
- struct wscons *wscons = (struct wscons *)arg;
+ struct wscons_state *wscons = (struct wscons_state *)arg;
if (wscons->wc_kb_polledio == NULL)
return;
@@ -1392,41 +1602,69 @@ wc_dprintf(const char *fmt, ...)
}
#endif
+/*ARGSUSED*/
static void
-update_property(struct wscons *wscons, char *name, ushort_t value)
+update_property(vc_state_t *pvc, char *name, ushort_t value)
{
char data[8];
(void) snprintf(data, sizeof (data), "%u", value);
- (void) ddi_prop_update_string(wscons->wc_dev, wc_dip, name, data);
+
+ (void) ddi_prop_update_string(wscons.wc_dev, wc_dip, name, data);
}
/*
* Gets the number of text rows and columns and the
* width and height (in pixels) of the console.
*/
-static void
-wc_get_size(struct wscons *wscons)
+void
+wc_get_size(vc_state_t *pvc)
{
- struct winsize *t = &wscons->wc_ttycommon.t_size;
+ struct winsize *t = &pvc->vc_ttycommon.t_size;
ushort_t r = LOSCREENLINES, c = LOSCREENCOLS, x = 0, y = 0;
- if (wscons->wc_tem != NULL)
- tem_get_size(wscons->wc_tem, &r, &c, &x, &y);
+ if (pvc->vc_tem != NULL)
+ tem_get_size(&r, &c, &x, &y);
#ifdef _HAVE_TEM_FIRMWARE
- else {
+ else
console_get_size(&r, &c, &x, &y);
- }
#endif /* _HAVE_TEM_FIRMWARE */
- update_property(wscons, "screen-#cols", t->ws_col = c);
- update_property(wscons, "screen-#rows", t->ws_row = r);
- update_property(wscons, "screen-width", t->ws_xpixel = x);
- update_property(wscons, "screen-height", t->ws_ypixel = y);
+ mutex_enter(&pvc->vc_ttycommon.t_excl);
+ t->ws_col = c;
+ t->ws_row = r;
+ t->ws_xpixel = x;
+ t->ws_ypixel = y;
+ mutex_exit(&pvc->vc_ttycommon.t_excl);
+
+ if (pvc->vc_minor != 0)
+ return;
+
+ /* only for the wscons:0 */
+ update_property(pvc, "screen-#cols", c);
+ update_property(pvc, "screen-#rows", r);
+ update_property(pvc, "screen-width", x);
+ update_property(pvc, "screen-height", y);
}
+/*ARGSUSED*/
static void
wc_modechg_cb(tem_modechg_cb_arg_t arg)
{
- wc_get_size((struct wscons *)arg);
+ minor_t index;
+ vc_state_t *pvc;
+
+ mutex_enter(&vc_lock);
+ for (index = 0; index < VC_INSTANCES_COUNT; index++) {
+ pvc = vt_minor2vc(index);
+
+ mutex_enter(&pvc->vc_state_lock);
+
+ if ((pvc->vc_flags & WCS_ISOPEN) &&
+ (pvc->vc_flags & WCS_INIT))
+ wc_get_size(pvc);
+
+ mutex_exit(&pvc->vc_state_lock);
+ }
+ mutex_exit(&vc_lock);
}
diff --git a/usr/src/uts/common/os/console.c b/usr/src/uts/common/os/console.c
index 91f5de218d..9145eaf808 100644
--- a/usr/src/uts/common/os/console.c
+++ b/usr/src/uts/common/os/console.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/varargs.h>
#include <sys/modctl.h>
@@ -168,32 +166,6 @@ console_rele(void)
rw_exit(&console_lock);
}
-#ifdef _HAVE_TEM_FIRMWARE
-/*
- * This routine exists so that prom_write() can redirect writes
- * to the framebuffer through the kernel terminal emulator, if
- * that configuration is selected during consconfig.
- * When the kernel terminal emulator is enabled, consconfig_dacf
- * sets up the PROM output redirect vector to enter this function.
- * During panic the console will already be powered up as part of
- * calling into the prom_*() layer.
- */
-ssize_t
-console_prom_write_cb(promif_redir_arg_t arg, uchar_t *s, size_t n)
-{
- struct tem *tem = (struct tem *)arg;
-
- ASSERT(consmode == CONS_KFB);
-
- if (panicstr)
- polled_io_cons_write(s, n);
- else
- tem->cons_wrtvec(tem, s, n, kcred);
-
- return (n);
-}
-#endif /* _HAVE_TEM_FIRMWARE */
-
static void
console_getprop(dev_t dev, dev_info_t *dip, char *name, ushort_t *sp)
{
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index 966e485e43..367e2c0211 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -126,6 +126,9 @@ CHKHDRS= \
consdev.h \
console.h \
consplat.h \
+ vt.h \
+ vtdaemon.h \
+ kd.h \
contract.h \
contract_impl.h \
copyops.h \
diff --git a/usr/src/uts/common/sys/console.h b/usr/src/uts/common/sys/console.h
index d0b25941db..9f60764092 100644
--- a/usr/src/uts/common/sys/console.h
+++ b/usr/src/uts/common/sys/console.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_CONSOLE_H
#define _SYS_CONSOLE_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -77,14 +75,6 @@ extern void console_exit(int, int);
extern vnode_t *console_vnode;
extern taskq_t *console_taskq;
-/*
- * PROM interface callback routine
- */
-#ifdef _HAVE_TEM_FIRMWARE
-#include <sys/promif.h>
-extern ssize_t console_prom_write_cb(promif_redir_arg_t, uchar_t *, size_t);
-#endif /* _HAVE_TEM_FIRMWARE */
-
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/fs/sdev_impl.h b/usr/src/uts/common/sys/fs/sdev_impl.h
index ce86e0d5c0..7bf24fb96a 100644
--- a/usr/src/uts/common/sys/fs/sdev_impl.h
+++ b/usr/src/uts/common/sys/fs/sdev_impl.h
@@ -26,8 +26,6 @@
#ifndef _SYS_SDEV_IMPL_H
#define _SYS_SDEV_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -333,6 +331,7 @@ extern int devname_lookup_func(struct sdev_node *, char *, struct vnode **,
#define SDEV_PATH 0x1 /* callback returning /devices physical path */
#define SDEV_VNODE 0x2 /* callback returning backing store vnode */
#define SDEV_VATTR 0x4 /* callback returning node vattr */
+#define SDEV_VLINK 0x8 /* callback returning /dev link */
/*
* devname_readdir_func()
@@ -429,6 +428,7 @@ extern int devname_profile_update(char *, size_t);
extern struct sdev_data *sdev_find_mntinfo(char *);
void sdev_mntinfo_rele(struct sdev_data *);
extern struct vnodeops *devpts_getvnodeops(void);
+extern struct vnodeops *devvt_getvnodeops(void);
/*
* Directory Based Device Naming (DBNR) defines
@@ -626,6 +626,7 @@ extern int prof_lookup();
extern void prof_filldir(struct sdev_node *);
extern int devpts_validate(struct sdev_node *dv);
extern int devnet_validate(struct sdev_node *dv);
+extern int devvt_validate(struct sdev_node *dv);
extern void *sdev_get_vtor(struct sdev_node *dv);
/*
@@ -656,10 +657,12 @@ extern kmem_cache_t *sdev_node_cache;
extern struct vnodeops *sdev_vnodeops;
extern struct vnodeops *devpts_vnodeops;
extern struct vnodeops *devnet_vnodeops;
+extern struct vnodeops *devvt_vnodeops;
extern struct sdev_data *sdev_origins; /* mount info for global /dev instance */
extern const fs_operation_def_t sdev_vnodeops_tbl[];
extern const fs_operation_def_t devpts_vnodeops_tbl[];
extern const fs_operation_def_t devnet_vnodeops_tbl[];
+extern const fs_operation_def_t devvt_vnodeops_tbl[];
extern const fs_operation_def_t devsys_vnodeops_tbl[];
extern const fs_operation_def_t devpseudo_vnodeops_tbl[];
diff --git a/usr/src/uts/intel/sys/kd.h b/usr/src/uts/common/sys/kd.h
index 4daffa1e4f..b34b326a31 100644
--- a/usr/src/uts/intel/sys/kd.h
+++ b/usr/src/uts/common/sys/kd.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,8 +31,6 @@
#ifndef _SYS_KD_H
#define _SYS_KD_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Minimal compatibility support for "kd" ioctls.
*
diff --git a/usr/src/uts/common/sys/tem.h b/usr/src/uts/common/sys/tem.h
index 202e692b52..0b11b4ff4c 100644
--- a/usr/src/uts/common/sys/tem.h
+++ b/usr/src/uts/common/sys/tem.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_TEM_H
#define _SYS_TEM_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -42,19 +40,31 @@ extern "C" {
typedef struct __tem_modechg_cb_arg *tem_modechg_cb_arg_t;
typedef void (*tem_modechg_cb_t) (tem_modechg_cb_arg_t arg);
-struct tem;
-int tem_init(struct tem **,
- char *, cred_t *);
-void tem_write(struct tem *,
- uchar_t *, ssize_t, cred_t *);
-void tem_polled_write(struct tem *,
- unsigned char *, int);
-void tem_get_size(struct tem *, ushort_t *, ushort_t *,
- ushort_t *, ushort_t *);
-int tem_fini(struct tem *);
-
-void tem_register_modechg_cb(struct tem *, tem_modechg_cb_t,
- tem_modechg_cb_arg_t);
+typedef struct __tem_vt_state *tem_vt_state_t;
+
+int tem_initialized(tem_vt_state_t);
+
+tem_vt_state_t tem_init(cred_t *);
+
+void tem_destroy(tem_vt_state_t, cred_t *);
+
+int tem_info_init(char *, cred_t *);
+
+void tem_write(tem_vt_state_t, uchar_t *, ssize_t, cred_t *);
+
+void tem_safe_polled_write(tem_vt_state_t, unsigned char *, int);
+
+void tem_get_size(ushort_t *, ushort_t *, ushort_t *, ushort_t *);
+
+void tem_register_modechg_cb(tem_modechg_cb_t, tem_modechg_cb_arg_t);
+
+void tem_activate(tem_vt_state_t, boolean_t, cred_t *);
+
+void tem_switch(tem_vt_state_t, tem_vt_state_t, cred_t *);
+
+uchar_t tem_get_fbmode(tem_vt_state_t);
+
+void tem_set_fbmode(tem_vt_state_t, uchar_t, cred_t *);
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/sys/tem_impl.h b/usr/src/uts/common/sys/tem_impl.h
index 804caf4c85..31e5187cea 100644
--- a/usr/src/uts/common/sys/tem_impl.h
+++ b/usr/src/uts/common/sys/tem_impl.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,8 +32,6 @@
#ifndef _SYS_TEM_IMPL_H
#define _SYS_TEM_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -43,7 +41,9 @@ extern "C" {
#include <sys/sunldi.h>
#include <sys/visual_io.h>
#include <sys/font.h>
+#include <sys/list.h>
#include <sys/tem.h>
+#include <sys/note.h>
/*
* definitions for ANSI x3.64 terminal control language parser
@@ -93,6 +93,7 @@ extern "C" {
/*
* Default foreground/background color
*/
+
#ifdef _HAVE_TEM_FIRMWARE
#define DEFAULT_ANSI_FOREGROUND ANSI_COLOR_BLACK
#define DEFAULT_ANSI_BACKGROUND ANSI_COLOR_WHITE
@@ -101,6 +102,7 @@ extern "C" {
#define DEFAULT_ANSI_BACKGROUND ANSI_COLOR_BLACK
#endif
+
#define BUF_LEN 160 /* Two lines of data can be processed at a time */
typedef uint8_t text_color_t;
@@ -111,6 +113,8 @@ typedef struct tem_color {
unsigned short a_flags;
} tem_color_t;
+enum called_from { CALLED_FROM_NORMAL, CALLED_FROM_STANDALONE };
+
struct tem_pix_pos {
screen_pos_t x;
screen_pos_t y;
@@ -134,131 +138,165 @@ typedef struct {
extern text_cmap_t cmap4_to_24;
-struct tem; /* Forward declare */
-
-enum called_from { CALLED_FROM_NORMAL, CALLED_FROM_STANDALONE };
+/*
+ * State structure for each virtual terminal emulator
+ */
+struct tem_vt_state {
+ kmutex_t tvs_lock;
+ uchar_t tvs_fbmode; /* framebuffer mode */
+ unsigned short tvs_flags; /* flags for this x3.64 terminal */
+ int tvs_state; /* state in output esc seq processing */
+ boolean_t tvs_gotparam; /* does output esc seq have a param */
+
+ int tvs_curparam; /* current param # of output esc seq */
+ int tvs_paramval; /* value of current param */
+ int tvs_params[TEM_MAXPARAMS]; /* parameters of output esc seq */
+ screen_pos_t tvs_tabs[TEM_MAXTAB]; /* tab stops */
+ int tvs_ntabs; /* number of tabs used */
+ int tvs_nscroll; /* number of lines to scroll */
+
+ struct tem_char_pos tvs_s_cursor; /* start cursor position */
+ struct tem_char_pos tvs_c_cursor; /* current cursor position */
+ struct tem_char_pos tvs_r_cursor; /* remembered cursor position */
+
+ unsigned char *tvs_outbuf; /* place to keep incomplete lines */
+ int tvs_outbuf_size;
+ int tvs_outindex; /* index into a_outbuf */
+ void *tvs_pix_data; /* pointer to tmp bitmap area */
+ int tvs_pix_data_size;
+ text_color_t tvs_fg_color;
+ text_color_t tvs_bg_color;
+ int tvs_first_line; /* kernel console output begins */
+
+ unsigned char *tvs_screen_buf; /* whole screen buffer */
+ int tvs_screen_buf_size;
+ text_color_t *tvs_fg_buf; /* fg_color attribute cache */
+ text_color_t *tvs_bg_buf; /* bg_color attribute cache */
+ int tvs_color_buf_size;
+
+ boolean_t tvs_isactive;
+ int tvs_initialized; /* initialization flag */
+
+ list_node_t tvs_list_node;
+};
+_NOTE(MUTEX_PROTECTS_DATA(tem_vt_state::tvs_lock, tem_vt_state))
-struct in_func_ptrs {
- void (*f_display)(struct tem *, unsigned char *, int,
+typedef struct tem_safe_callbacks {
+ void (*tsc_display)(struct tem_vt_state *, unsigned char *, int,
screen_pos_t, screen_pos_t, unsigned char, unsigned char,
cred_t *, enum called_from);
- void (*f_copy)(struct tem *,
+ void (*tsc_copy)(struct tem_vt_state *,
screen_pos_t, screen_pos_t, screen_pos_t, screen_pos_t,
screen_pos_t, screen_pos_t, cred_t *, enum called_from);
- void (*f_cursor)(struct tem *, short, cred_t *,
+ void (*tsc_cursor)(struct tem_vt_state *, short, cred_t *,
enum called_from);
- void (*f_bit2pix)(struct tem *, unsigned char,
+ void (*tsc_bit2pix)(struct tem_vt_state *, unsigned char,
unsigned char, unsigned char);
- void (*f_cls)(struct tem *, int,
+ void (*tsc_cls)(struct tem_vt_state *, int,
screen_pos_t, screen_pos_t, cred_t *, enum called_from);
-};
+} tem_safe_callbacks_t;
/*
- * State structure for terminal emulator
+ * common term soft state structure shared by all virtual terminal emulators
*/
-typedef struct tem_state { /* state for tem x3.64 emulator */
- int display_mode; /* What mode we are in */
- screen_size_t linebytes; /* Layered on bytes per scan line */
- unsigned short a_flags; /* flags for this x3.64 terminal */
- int a_state; /* state in output esc seq processing */
- boolean_t a_gotparam; /* does output esc seq have a param */
- int a_curparam; /* current param # of output esc seq */
- int a_paramval; /* value of current param */
- int a_params[TEM_MAXPARAMS]; /* parameters of output esc seq */
- screen_pos_t a_tabs[TEM_MAXTAB]; /* tab stops */
- int a_ntabs; /* number of tabs used */
- int a_nscroll; /* number of lines to scroll */
- struct tem_char_pos a_s_cursor; /* start cursor position */
- struct tem_char_pos a_c_cursor; /* current cursor position */
- struct tem_char_pos a_r_cursor; /* remembered cursor position */
- struct tem_size a_c_dimension; /* window dimensions in characters */
- struct tem_size a_p_dimension; /* screen dimensions in pixels */
- struct tem_pix_pos a_p_offset; /* pix offset to center the display */
- unsigned char *a_outbuf; /* place to keep incomplete lines */
- unsigned char *a_blank_line; /* a blank line for scrolling */
- int a_outindex; /* index into a_outbuf */
- struct in_func_ptrs in_fp; /* internal output functions */
- struct font a_font; /* font table */
- int a_pdepth; /* pixel depth */
- int a_initialized; /* initialization flag */
- void *a_pix_data; /* pointer to tmp bitmap area */
- int a_pix_data_size; /* size of bitmap data areas */
- text_color_t fg_color;
- text_color_t bg_color;
- int first_line; /* kernel console output begins */
+typedef struct tem_state {
+ ldi_handle_t ts_hdl; /* Framework handle for layered on dev */
+ screen_size_t ts_linebytes; /* Layered on bytes per scan line */
+
+ int ts_display_mode; /* What mode we are in */
+ struct vis_polledio *ts_fb_polledio;
+
+ struct tem_size ts_c_dimension; /* window dimensions in characters */
+ struct tem_size ts_p_dimension; /* screen dimensions in pixels */
+ struct tem_pix_pos ts_p_offset; /* pix offset to center the display */
+
+ int ts_pix_data_size; /* size of bitmap data areas */
+ int ts_pdepth; /* pixel depth */
+ struct font ts_font; /* font table */
+
+ unsigned char *ts_blank_line; /* a blank line for scrolling */
+ tem_safe_callbacks_t *ts_callbacks; /* internal output functions */
+
+ int ts_initialized; /* initialization flag */
+
+ tem_modechg_cb_t ts_modechg_cb;
+ tem_modechg_cb_arg_t ts_modechg_arg;
+
+ tem_color_t ts_init_color; /* initial color and attributes */
+
+ struct tem_vt_state *ts_active;
+ kmutex_t ts_lock;
+ list_t ts_list; /* chain of all tems */
} tem_state_t;
+extern tem_state_t tems;
+extern tem_safe_callbacks_t tem_safe_text_callbacks;
+extern tem_safe_callbacks_t tem_safe_pix_callbacks;
+
+
/*
- * State structure for terminal emulator
+ * tems_* fuctions mean that they just operate on the common soft state
+ * (tem_state_t), and tem_* functions mean that they operate on the
+ * per-tem structure (tem_vt_state). All "safe" interfaces are in tem_safe.c.
*/
-typedef struct tem {
-#ifdef _HAVE_TEM_FIRMWARE
- void (*cons_wrtvec) /* PROM output gets redirected thru this vec. */
- (struct tem *, uchar_t *, ssize_t, cred_t *);
-#endif /* _HAVE_TEM_FIRMWARE */
- ldi_handle_t hdl; /* Framework handle for layered on dev */
- dev_info_t *dip; /* Our dip */
- kmutex_t lock;
- struct vis_polledio *fb_polledio;
- tem_state_t *state;
- tem_modechg_cb_t modechg_cb;
- tem_modechg_cb_arg_t modechg_arg;
- tem_color_t init_color; /* initial color and attributes */
-} tem_t;
-
-void tem_check_first_time(tem_t *tem, cred_t *, enum called_from);
-void tem_reset_colormap(tem_t *, cred_t *, enum called_from);
-void tem_align_cursor(tem_t *);
-void tem_reset_emulator(tem_t *, cred_t *, enum called_from, tem_color_t *);
-void tem_reset_display(tem_t *, cred_t *, enum called_from, int,
- tem_color_t *);
-void tem_display_layered(tem_t *, struct vis_consdisplay *, cred_t *);
-void tem_copy_layered(tem_t *, struct vis_conscopy *, cred_t *);
-void tem_cursor_layered(tem_t *, struct vis_conscursor *, cred_t *);
-void tem_terminal_emulate(tem_t *, uchar_t *, int, cred_t *,
- enum called_from);
-void tem_text_display(tem_t *, uchar_t *,
- int, screen_pos_t, screen_pos_t,
- text_color_t, text_color_t,
- cred_t *, enum called_from);
-void tem_text_copy(tem_t *,
- screen_pos_t, screen_pos_t,
- screen_pos_t, screen_pos_t,
- screen_pos_t, screen_pos_t,
- cred_t *, enum called_from);
-void tem_text_cursor(tem_t *, short, cred_t *, enum called_from);
-void tem_text_cls(tem_t *,
- int count, screen_pos_t row, screen_pos_t col,
- cred_t *credp, enum called_from called_from);
-void tem_pix_display(tem_t *, uchar_t *,
- int, screen_pos_t, screen_pos_t,
- text_color_t, text_color_t,
- cred_t *, enum called_from);
-void tem_pix_copy(tem_t *,
- screen_pos_t, screen_pos_t,
- screen_pos_t, screen_pos_t,
- screen_pos_t, screen_pos_t,
- cred_t *, enum called_from);
-void tem_copy(tem_t *,
- struct vis_conscopy *,
- cred_t *, enum called_from);
-void tem_pix_cursor(tem_t *, short, cred_t *, enum called_from);
-void tem_pix_cls(tem_t *, int, screen_pos_t, screen_pos_t,
- cred_t *, enum called_from);
-void tem_pix_cls_range(tem_t *,
- screen_pos_t, int, int,
- screen_pos_t, int, int,
- boolean_t, cred_t *, enum called_from);
-
-void bit_to_pix24(tem_t *, uchar_t, text_color_t, text_color_t);
-void bit_to_pix8(tem_t *, uchar_t, text_color_t, text_color_t);
-void bit_to_pix4(tem_t *, uchar_t, text_color_t, text_color_t);
-
-text_color_t ansi_bg_to_solaris(tem_t *, int);
-text_color_t ansi_fg_to_solaris(tem_t *, int);
+void tems_display_layered(struct vis_consdisplay *, cred_t *);
+void tems_copy_layered(struct vis_conscopy *, cred_t *);
+void tems_cursor_layered(struct vis_conscursor *, cred_t *);
+void tems_safe_copy(struct vis_conscopy *, cred_t *, enum called_from);
+
+void tem_pix_align(struct tem_vt_state *, cred_t *, enum called_from);
+void tem_safe_check_first_time(struct tem_vt_state *tem, cred_t *,
+ enum called_from);
+void tem_safe_reset_display(struct tem_vt_state *, cred_t *,
+ enum called_from, boolean_t, boolean_t);
+void tem_safe_terminal_emulate(struct tem_vt_state *, uchar_t *, int,
+ cred_t *, enum called_from);
+void tem_safe_text_display(struct tem_vt_state *, uchar_t *,
+ int, screen_pos_t, screen_pos_t,
+ text_color_t, text_color_t,
+ cred_t *, enum called_from);
+void tem_safe_text_copy(struct tem_vt_state *,
+ screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t,
+ cred_t *, enum called_from);
+void tem_safe_text_cursor(struct tem_vt_state *, short, cred_t *,
+ enum called_from);
+void tem_safe_text_cls(struct tem_vt_state *,
+ int count, screen_pos_t row, screen_pos_t col,
+ cred_t *credp, enum called_from called_from);
+void tem_safe_pix_display(struct tem_vt_state *, uchar_t *,
+ int, screen_pos_t, screen_pos_t,
+ text_color_t, text_color_t,
+ cred_t *, enum called_from);
+void tem_safe_pix_copy(struct tem_vt_state *,
+ screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t,
+ cred_t *, enum called_from);
+void tem_safe_pix_cursor(struct tem_vt_state *, short, cred_t *,
+ enum called_from);
+void tem_safe_pix_bit2pix(struct tem_vt_state *, unsigned char,
+ unsigned char, unsigned char);
+void tem_safe_pix_cls(struct tem_vt_state *, int, screen_pos_t, screen_pos_t,
+ cred_t *, enum called_from);
+void tem_safe_pix_cls_range(struct tem_vt_state *,
+ screen_pos_t, int, int,
+ screen_pos_t, int, int,
+ boolean_t, cred_t *, enum called_from);
+void tem_safe_pix_clear_entire_screen(struct tem_vt_state *,
+ cred_t *, enum called_from);
+
+void tem_safe_get_color(struct tem_vt_state *, text_color_t *,
+ text_color_t *, uint8_t);
void set_font(struct font *, short *, short *, short, short);
+void tem_safe_blank_screen(struct tem_vt_state *, cred_t *,
+ enum called_from);
+void tem_safe_unblank_screen(struct tem_vt_state *, cred_t *,
+ enum called_from);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/vt.h b/usr/src/uts/common/sys/vt.h
new file mode 100644
index 0000000000..dd0c2144dc
--- /dev/null
+++ b/usr/src/uts/common/sys/vt.h
@@ -0,0 +1,112 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_VT_H
+#define _SYS_VT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/*
+ * Public IOCTLs supported by the VT, which are shared with
+ * other operating systems.
+ */
+#define VTIOC ('V'<<8)
+#define VT_OPENQRY (VTIOC|1) /* inquires if this vt already open */
+#define VT_SETMODE (VTIOC|2) /* set vt into auto or process mode */
+
+#define VT_GETMODE (VTIOC|3) /* returns mode vt is currently in */
+#define VT_RELDISP (VTIOC|4) /* tells vt when display released */
+#define VT_ACTIVATE (VTIOC|5) /* activates specified vt */
+#define VT_WAITACTIVE (VTIOC|6) /* wait for vt to be activated */
+#define VT_GETSTATE (VTIOC|100) /* returns active and open vts */
+
+/*
+ * Solaris specific public IOCTL.
+ * Inquires if the vt functionality is available.
+ */
+#define VT_ENABLED (VTIOC|101)
+
+struct vt_mode {
+ char mode; /* mode to set vt into, VT_AUTO or VT_PROCESS */
+ char waitv; /* if != 0, vt hangs on writes when not active */
+ short relsig; /* signal to use for release request */
+ short acqsig; /* signal to use for display acquired */
+ short frsig; /* signal to use for forced release */
+};
+
+/* vt switching mode */
+enum {
+ VT_AUTO = 0, /* this vt switching is automatic */
+ VT_PROCESS /* this vt switching controlled by process */
+};
+
+#define VT_ACKACQ 2 /* ack from v86 acquire routine */
+
+/*
+ * structure used by VT_GETSTATE ioctl
+ */
+
+struct vt_stat {
+ unsigned short v_active;
+ unsigned short v_signal;
+ unsigned short v_state;
+};
+
+/* project private IOCTLs */
+#define VT_CONFIG (VTIOC|102) /* config virtual console number */
+#define VT_SETDISPINFO (VTIOC|103) /* set display number */
+#define VT_SETDISPLOGIN (VTIOC|104) /* set display login */
+#define VT_GETDISPINFO (VTIOC|105) /* get display info */
+
+/*
+ * setting target console is only used by vtdaemon
+ * to set target console while vtdaemon is authenticating
+ * for it, which is returned in VT_GETSTATE. At that
+ * time, the real active console is the vtdaemon special console,
+ * but VT_GETSTATE should not be aware of it. Instead, VT_GETACTIVE
+ * is used to get the real active console for vtdaemon.
+ */
+#define VT_SET_TARGET (VTIOC|106)
+#define VT_GETACTIVE (VTIOC|107)
+
+/*
+ * structure used by VT_GETDISPINFO
+ */
+struct vt_dispinfo {
+ pid_t v_pid; /* -1 if no display info (auto mode) */
+ int v_dispnum; /* display number associated with vt */
+ int v_login; /* if the user logged in the display */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VT_H */
diff --git a/usr/src/uts/common/sys/vt_impl.h b/usr/src/uts/common/sys/vt_impl.h
new file mode 100644
index 0000000000..7bd41615f3
--- /dev/null
+++ b/usr/src/uts/common/sys/vt_impl.h
@@ -0,0 +1,137 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_VT_IMPL_H
+#define _SYS_VT_IMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/vt.h>
+#include <sys/kd.h>
+#include <sys/tem.h>
+#include <sys/tty.h>
+#include <sys/cred.h>
+#include <sys/list.h>
+#include <sys/avl.h>
+#include <sys/note.h>
+
+#define WCS_INIT 0x00000001 /* tty is init */
+#define WCS_ISOPEN 0x00000002 /* open is complete */
+#define WCS_STOPPED 0x00000004 /* output is stopped */
+#define WCS_DELAY 0x00000008 /* waiting for delay to finish */
+#define WCS_BUSY 0x00000010 /* waiting for transmission to finish */
+
+typedef struct vc_waitactive_msg {
+ list_node_t wa_list_node;
+ int wa_msg_minor; /* minor number from which msg comes */
+ int wa_wait_minor; /* which node we are waiting for */
+ mblk_t *wa_mp;
+} vc_waitactive_msg_t;
+
+/* virtual console soft state associated with each vt */
+typedef struct vc_state {
+ minor_t vc_minor;
+ avl_node_t vc_avl_node;
+ uchar_t vc_switch_mode; /* VT_AUTO or VT_PROCESS */
+ char vc_waitv;
+ int vc_relsig;
+ int vc_acqsig;
+ pid_t vc_pid;
+ minor_t vc_switchto;
+ int vc_flags;
+
+ int vc_dispnum;
+ int vc_login;
+
+ tem_vt_state_t vc_tem; /* Terminal emulator state */
+ tty_common_t vc_ttycommon; /* data common to all tty drivers */
+ bufcall_id_t vc_bufcallid; /* id returned by qbufcall */
+ timeout_id_t vc_timeoutid; /* id returned by qtimeout */
+
+ queue_t *vc_wq; /* write queue */
+
+#ifdef _HAVE_TEM_FIRMWARE
+ int vc_pendc; /* pending output character */
+#endif /* _HAVE_TEM_FIRMWARE */
+
+ /*
+ * vc_state_lock is currently only used to protect vc_flags,
+ * more precisely, the state change of vc_state_t.
+ * The existence of this lock is because wc_modechg_cb().
+ * wc_modechg_cb() is a callback function which may result in
+ * multiple threads accessing vc_flags regardless the STREAMS
+ * periemters of wc module.
+ * Since wc_modechg_cb() only conducts read access to vc_flags,
+ * we only need to hold this lock when writing to vc_flags in
+ * wc module (except wc_modechg_cb()).
+ * See locking policy in wscons.c for more info.
+ */
+ kmutex_t vc_state_lock;
+} vc_state_t;
+_NOTE(MUTEX_PROTECTS_DATA(vc_state_t::vc_state_lock, vc_state_t::vc_flags))
+
+#define VC_DEFAULT_COUNT 16
+
+/* Invalid VT minor number */
+#define VT_MINOR_INVALID ((minor_t)-1)
+/* Argument to vt_minor2vc to get the softstate of the active VT */
+#define VT_ACTIVE VT_MINOR_INVALID
+
+/*
+ * VC_INSTANCES_COUNT should be regarded as reading access to vc_avl_root
+ */
+#define VC_INSTANCES_COUNT (avl_numnodes(&vc_avl_root))
+
+void vt_ioctl(queue_t *q, mblk_t *mp);
+void vt_miocdata(queue_t *qp, mblk_t *mp);
+void vt_clean(queue_t *q, vc_state_t *pvc);
+void vt_close(queue_t *q, vc_state_t *pvc, cred_t *crp);
+int vt_open(minor_t minor, queue_t *rq, cred_t *crp);
+int vt_check_hotkeys(mblk_t *mp);
+vc_state_t *vt_minor2vc(minor_t);
+
+extern dev_info_t *wc_dip;
+extern avl_tree_t vc_avl_root;
+extern minor_t vc_active_console;
+extern kmutex_t vc_lock;
+extern minor_t vc_last_console;
+
+major_t vt_wc_attached(void);
+void vt_getactive(char *, int);
+boolean_t vt_minor_valid(minor_t minor);
+void vt_resize(uint_t);
+void vt_attach(void);
+void vt_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VT_IMPL_H */
diff --git a/usr/src/uts/common/sys/vtdaemon.h b/usr/src/uts/common/sys/vtdaemon.h
new file mode 100644
index 0000000000..95d512efda
--- /dev/null
+++ b/usr/src/uts/common/sys/vtdaemon.h
@@ -0,0 +1,51 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_VTDAEMON_H
+#define _SYS_VTDAEMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VT_DAEMON_DOOR_FILE "/var/run/vt/vtdaemon_door"
+
+#define VT_EV_X_EXIT 0 /* <vt_num> */
+#define VT_EV_HOTKEYS 1 /* <vt_num> */
+
+/*
+ * The structure of a request to vtdaemon.
+ */
+typedef struct vt_cmd_arg {
+ uchar_t vt_ev;
+ uint32_t vt_num;
+} vt_cmd_arg_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VTDAEMON_H */
diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared
index 280b7b5c07..185eb386ea 100644
--- a/usr/src/uts/intel/Makefile.intel.shared
+++ b/usr/src/uts/intel/Makefile.intel.shared
@@ -82,7 +82,7 @@ include $(UTSTREE)/common/Makefile.files
# defined before we include Makefile.uts, or else genunix's build
# won't be as parallel as we might like.
#
-NOT_YET_KMODS = $(OLDPTY_OBJS) $(PTY_OBJS) $(MOD_OBJS)
+NOT_YET_KMODS = $(OLDPTY_OBJS) $(PTY_OBJS) $(VCONS_CONF_OBJS) $(MOD_OBJS)
#
# ----- END OF TRANSITIONAL SECTION -------------------------------------------
diff --git a/usr/src/uts/intel/ia32/ml/modstubs.s b/usr/src/uts/intel/ia32/ml/modstubs.s
index bec4b20e5d..a1352a260b 100644
--- a/usr/src/uts/intel/ia32/ml/modstubs.s
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s
@@ -428,6 +428,7 @@ fcnname/**/_info: \
NO_UNLOAD_STUB(dev, devname_profile_update, nomod_minus_one);
NO_UNLOAD_STUB(dev, sdev_module_register, nomod_minus_one);
NO_UNLOAD_STUB(dev, sdev_devstate_change, nomod_minus_one);
+ NO_UNLOAD_STUB(dev, devvt_getvnodeops, nomod_minus_one);
NO_UNLOAD_STUB(dev, devpts_getvnodeops, nomod_zero);
END_MODULE(dev);
#endif
diff --git a/usr/src/uts/intel/sys/Makefile b/usr/src/uts/intel/sys/Makefile
index 8ac0deba85..2b242ba979 100644
--- a/usr/src/uts/intel/sys/Makefile
+++ b/usr/src/uts/intel/sys/Makefile
@@ -22,7 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#
include ../../../Makefile.master
@@ -48,7 +47,6 @@ HDRS = \
inline.h \
iommulib.h \
hypervisor.h \
- kd.h \
kdi_machimpl.h \
kdi_regs.h \
machlock.h \
diff --git a/usr/src/uts/intel/tem/Makefile b/usr/src/uts/intel/tem/Makefile
index ac45575c5e..9962a28f30 100644
--- a/usr/src/uts/intel/tem/Makefile
+++ b/usr/src/uts/intel/tem/Makefile
@@ -20,11 +20,9 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This makefile drives the production of the tem module
#
# intel implementation architecture dependent
@@ -42,6 +40,9 @@ MODULE = tem
OBJECTS = $(TEM_OBJS:%=$(OBJS_DIR)/%)
LINTS = $(TEM_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
+WARLOCK_OUT = $(TEM_OBJS:%.o=%.ll)
+WARLOCK_OK = $(MODULE).ok
+WLCMD_DIR = $(UTSBASE)/common/io/warlock
#
# Include common rules.
@@ -63,7 +64,6 @@ LDFLAGS += -dy -Ndacf/consconfig_dacf
# Please do not carry these forward to new Makefiles.
#
LINTTAGS += -erroff=E_STATIC_UNUSED
-LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV
#
# Default build targets.
@@ -90,3 +90,26 @@ install: $(INSTALL_DEPS)
# Include common targets.
#
include $(UTSBASE)/intel/Makefile.targ
+
+#
+# Defines for local commands
+#
+TEST = test
+WLCC = wlcc
+TOUCH = touch
+WARLOCK = warlock
+
+#
+# warlock targets
+#
+
+warlock: $(WARLOCK_OUT) warlock_ddi.files
+ $(WARLOCK) -c $(WLCMD_DIR)/tem.wlcmd $(WARLOCK_OUT) \
+ -l ../../intel/warlock/ddi_dki_impl.ll
+ $(TOUCH) $(WARLOCK_OK)
+
+%.ll: $(UTSBASE)/common/io/%.c
+ $(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+warlock_ddi.files:
+ @cd ../../intel/warlock; pwd; $(MAKE) warlock
diff --git a/usr/src/uts/intel/warlock/Makefile b/usr/src/uts/intel/warlock/Makefile
index 028c88d4a4..fbefb9b95d 100644
--- a/usr/src/uts/intel/warlock/Makefile
+++ b/usr/src/uts/intel/warlock/Makefile
@@ -52,7 +52,7 @@ include $(UTSBASE)/intel/Makefile.intel
# lock_lint rules
#
all: warlock warlock.1394 warlock.audio warlock.ecpp warlock.scsi \
- warlock.usb warlock.ib warlock.sata warlock.sdcard
+ warlock.usb warlock.ib warlock.sata warlock.sdcard warlock.wc
warlock: $(MODULE).ok
@@ -137,3 +137,6 @@ $(CLOSED_BUILD) @cd $(CLOSED)/uts/intel/marvell88sx; \
warlock.sdcard:
@cd ../sda; $(MAKE) clean; $(MAKE) warlock
@cd ../sdhost; $(MAKE) clean; $(MAKE) warlock
+
+warlock.wc:
+ @cd ../wc; $(MAKE) clean; $(MAKE) warlock
diff --git a/usr/src/uts/intel/wc/Makefile b/usr/src/uts/intel/wc/Makefile
index efdad561f7..b7461a4bed 100644
--- a/usr/src/uts/intel/wc/Makefile
+++ b/usr/src/uts/intel/wc/Makefile
@@ -23,7 +23,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
#
# This makefile drives the production of the wc driver
# kernel module.
@@ -44,6 +43,9 @@ OBJECTS = $(WC_OBJS:%=$(OBJS_DIR)/%)
LINTS = $(WC_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
CONF_SRCDIR = $(UTSBASE)/common/io
+WARLOCK_OUT = $(WC_OBJS:%.o=%.ll)
+WARLOCK_OK = $(MODULE).ok
+WLCMD_DIR = $(UTSBASE)/common/io/warlock
#
# Include common rules.
@@ -60,7 +62,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
#
# Overrides.
#
-LDFLAGS += -dy -Nmisc/tem
+LDFLAGS += -dy -Nmisc/tem -Ndacf/consconfig_dacf
#
# Default build targets.
@@ -87,3 +89,37 @@ install: $(INSTALL_DEPS)
# Include common targets.
#
include $(UTSBASE)/intel/Makefile.targ
+
+#
+# Defines for local commands
+#
+TEST = test
+WLCC = wlcc
+TOUCH = touch
+WARLOCK = warlock
+
+#
+# warlock targets
+#
+
+#
+# vcons_conf.c is compile to genunix, add it to WARLOCK_OUT
+#
+WARLOCK_OUT += vcons_conf.ll
+
+warlock: $(WARLOCK_OUT) sdev_vtops.file warlock_ddi.files
+ $(WARLOCK) -c $(WLCMD_DIR)/wc.wlcmd $(WARLOCK_OUT) \
+ -l ../../intel/warlock/ddi_dki_impl.ll
+ $(WARLOCK) -c $(WLCMD_DIR)/wc_devfs.wlcmd sdev_vtops.ll vcons_conf.ll \
+ -l ../../intel/warlock/ddi_dki_impl.ll
+ $(TOUCH) $(WARLOCK_OK)
+
+%.ll: $(UTSBASE)/common/io/%.c
+ $(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+sdev_vtops.file:
+ $(WLCC) $(CPPFLAGS) -DDEBUG -o sdev_vtops.ll -c \
+ ../../common/fs/dev/sdev_vtops.c
+
+warlock_ddi.files:
+ @cd ../../intel/warlock; pwd; $(MAKE) warlock
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 1ef0190d3f..6644b73a2b 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -95,7 +95,7 @@ include $(UTSTREE)/common/Makefile.files
# defined before we include Makefile.uts, or else genunix's build
# won't be as parallel as we might like.
#
-NOT_YET_KMODS = $(OLDPTY_OBJS) $(PTY_OBJS) $(MOD_OBJS)
+NOT_YET_KMODS = $(OLDPTY_OBJS) $(PTY_OBJS) $(VCONS_CONF_OBJS) $(MOD_OBJS)
#
# ----- END OF TRANSITIONAL SECTION -------------------------------------------
diff --git a/usr/src/uts/sparc/ml/modstubs.s b/usr/src/uts/sparc/ml/modstubs.s
index 142cd0567c..15377f736c 100644
--- a/usr/src/uts/sparc/ml/modstubs.s
+++ b/usr/src/uts/sparc/ml/modstubs.s
@@ -316,6 +316,7 @@ stubs_base:
NO_UNLOAD_STUB(dev, devname_profile_update, nomod_minus_one);
NO_UNLOAD_STUB(dev, sdev_module_register, nomod_minus_one);
NO_UNLOAD_STUB(dev, sdev_devstate_change, nomod_minus_one);
+ NO_UNLOAD_STUB(dev, devvt_getvnodeops, nomod_minus_one);
NO_UNLOAD_STUB(dev, devpts_getvnodeops, nomod_zero);
END_MODULE(dev);
#endif
diff --git a/usr/src/uts/sparc/tem/Makefile b/usr/src/uts/sparc/tem/Makefile
index 74cfc7091d..cd6a9c6d34 100644
--- a/usr/src/uts/sparc/tem/Makefile
+++ b/usr/src/uts/sparc/tem/Makefile
@@ -20,10 +20,9 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
#
# This makefile drives the production of the tem module
@@ -44,6 +43,9 @@ OBJECTS = $(TEM_OBJS:%=$(OBJS_DIR)/%)
LINTS = $(TEM_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE)
+WARLOCK_OUT = $(TEM_OBJS:%.o=%.ll)
+WARLOCK_OK = $(MODULE).ok
+WLCMD_DIR = $(UTSBASE)/common/io/warlock
#
# Include common rules.
@@ -66,7 +68,6 @@ LDFLAGS += -dy -Ndacf/consconfig_dacf
# to investigate and remove these for maximum lint coverage.
# Please do not carry these forward to new Makefiles.
#
-LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV
LINTTAGS += -erroff=E_STATIC_UNUSED
#
@@ -94,3 +95,26 @@ install: $(INSTALL_DEPS)
# Include common targets.
#
include $(UTSBASE)/sparc/Makefile.targ
+
+#
+# Defines for local commands
+#
+TEST = test
+WLCC = wlcc
+TOUCH = touch
+WARLOCK = warlock
+
+#
+# warlock targets
+#
+
+warlock: $(WARLOCK_OUT) warlock_ddi.files
+ $(WARLOCK) -c $(WLCMD_DIR)/tem.wlcmd $(WARLOCK_OUT) \
+ -l ../../sparc/warlock/ddi_dki_impl.ll
+ $(TOUCH) $(WARLOCK_OK)
+
+%.ll: $(UTSBASE)/common/io/%.c
+ $(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+warlock_ddi.files:
+ @cd ../../sparc/warlock; pwd; $(MAKE) warlock
diff --git a/usr/src/uts/sparc/warlock/Makefile b/usr/src/uts/sparc/warlock/Makefile
index 68a9256259..746c15d646 100644
--- a/usr/src/uts/sparc/warlock/Makefile
+++ b/usr/src/uts/sparc/warlock/Makefile
@@ -52,7 +52,7 @@ include $(UTSBASE)/sparc/Makefile.sparc
# lock_lint rules
#
all: warlock warlock.1394 warlock.audio warlock.ecpp warlock.scsi \
- warlock.smartcard warlock.usb warlock.ib warlock.sata
+ warlock.smartcard warlock.usb warlock.ib warlock.sata warlock.wc
warlock: $(MODULE).ok
@@ -152,3 +152,6 @@ warlock.sdcard:
@cd ../sda; $(MAKE) clean; $(MAKE) warlock
@cd ../sdhost; $(MAKE) clean; $(MAKE) warlock
@cd ../wbsd; $(MAKE) clean; $(MAKE) warlock
+
+warlock.wc:
+ @cd ../wc; $(MAKE) clean; $(MAKE) warlock
diff --git a/usr/src/uts/sparc/wc/Makefile b/usr/src/uts/sparc/wc/Makefile
index 39e210e09c..37a0e94a97 100644
--- a/usr/src/uts/sparc/wc/Makefile
+++ b/usr/src/uts/sparc/wc/Makefile
@@ -23,8 +23,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# This makefile drives the production of the wc driver
#
# sparc architecture dependent
@@ -43,6 +41,9 @@ OBJECTS = $(WC_OBJS:%=$(OBJS_DIR)/%)
LINTS = $(WC_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
CONF_SRCDIR = $(UTSBASE)/sun/io
+WARLOCK_OUT = $(WC_OBJS:%.o=%.ll)
+WARLOCK_OK = $(MODULE).ok
+WLCMD_DIR = $(UTSBASE)/common/io/warlock
#
# Include common rules.
@@ -67,7 +68,7 @@ CLEANFILES += $(MODSTUBS_O)
# lint pass one enforcement
#
CFLAGS += $(CCVERBOSE)
-LDFLAGS += -dy -Nmisc/tem
+LDFLAGS += -dy -Nmisc/tem -Ndacf/consconfig_dacf
#
# Default build targets.
@@ -94,3 +95,37 @@ install: $(INSTALL_DEPS)
# Include common targets.
#
include $(UTSBASE)/sparc/Makefile.targ
+
+#
+# Defines for local commands
+#
+TEST = test
+WLCC = wlcc
+TOUCH = touch
+WARLOCK = warlock
+
+#
+# warlock targets
+#
+
+#
+# vcons_conf.c is compiled to genunix, add it to WARLOCK_OUT
+#
+WARLOCK_OUT += vcons_conf.ll
+
+warlock: $(WARLOCK_OUT) sdev_vtops.file warlock_ddi.files
+ $(WARLOCK) -c $(WLCMD_DIR)/wc.wlcmd $(WARLOCK_OUT) \
+ -l ../../sparc/warlock/ddi_dki_impl.ll
+ $(WARLOCK) -c $(WLCMD_DIR)/wc_devfs.wlcmd sdev_vtops.ll vcons_conf.ll \
+ -l ../../sparc/warlock/ddi_dki_impl.ll
+ $(TOUCH) $(WARLOCK_OK)
+
+%.ll: $(UTSBASE)/common/io/%.c
+ $(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+sdev_vtops.file:
+ $(WLCC) $(CPPFLAGS) -DDEBUG -o sdev_vtops.ll -c \
+ ../../common/fs/dev/sdev_vtops.c
+
+warlock_ddi.files:
+ @cd ../../sparc/warlock; pwd; $(MAKE) warlock