2005-01-06 23:35:40 +00:00
|
|
|
/*-
|
2017-11-20 19:43:44 +00:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*
|
1993-06-12 14:58:17 +00:00
|
|
|
* Copyright (c) 1988 University of Utah.
|
|
|
|
* Copyright (c) 1991 The Regents of the University of California.
|
2011-12-17 15:50:45 +00:00
|
|
|
* Copyright (c) 1999 Michael Smith
|
|
|
|
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
|
|
|
*
|
1993-06-12 14:58:17 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* the Systems Programming Group of the University of Utah Computer
|
|
|
|
* Science Department.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2016-09-15 13:16:20 +00:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1993-06-12 14:58:17 +00:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1993-10-16 14:15:10 +00:00
|
|
|
* from: @(#)cons.c 7.2 (Berkeley) 5/9/91
|
1993-06-12 14:58:17 +00:00
|
|
|
*/
|
|
|
|
|
2003-06-11 00:56:59 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2001-12-11 10:21:26 +00:00
|
|
|
#include "opt_ddb.h"
|
2014-06-27 17:50:33 +00:00
|
|
|
#include "opt_syscons.h"
|
2001-12-11 10:21:26 +00:00
|
|
|
|
1994-08-13 03:50:34 +00:00
|
|
|
#include <sys/param.h>
|
1994-05-25 09:21:21 +00:00
|
|
|
#include <sys/systm.h>
|
2006-11-01 04:54:51 +00:00
|
|
|
#include <sys/lock.h>
|
|
|
|
#include <sys/mutex.h>
|
1995-01-21 14:12:15 +00:00
|
|
|
#include <sys/conf.h>
|
2000-01-24 11:48:11 +00:00
|
|
|
#include <sys/cons.h>
|
2001-10-25 00:14:16 +00:00
|
|
|
#include <sys/fcntl.h>
|
2019-12-26 15:21:34 +00:00
|
|
|
#include <sys/kbio.h>
|
2004-07-10 21:43:23 +00:00
|
|
|
#include <sys/kdb.h>
|
1995-12-08 11:19:42 +00:00
|
|
|
#include <sys/kernel.h>
|
2001-10-23 20:25:50 +00:00
|
|
|
#include <sys/malloc.h>
|
2003-06-22 02:54:33 +00:00
|
|
|
#include <sys/msgbuf.h>
|
2001-10-23 20:25:50 +00:00
|
|
|
#include <sys/namei.h>
|
2006-11-06 13:42:10 +00:00
|
|
|
#include <sys/priv.h>
|
2000-12-12 21:18:13 +00:00
|
|
|
#include <sys/proc.h>
|
2001-10-23 20:25:50 +00:00
|
|
|
#include <sys/queue.h>
|
1996-10-16 00:19:40 +00:00
|
|
|
#include <sys/reboot.h>
|
1995-12-09 20:39:47 +00:00
|
|
|
#include <sys/sysctl.h>
|
2007-12-25 21:17:34 +00:00
|
|
|
#include <sys/sbuf.h>
|
1994-08-13 03:50:34 +00:00
|
|
|
#include <sys/tty.h>
|
1998-03-28 10:33:27 +00:00
|
|
|
#include <sys/uio.h>
|
2001-10-23 20:25:50 +00:00
|
|
|
#include <sys/vnode.h>
|
1993-06-12 14:58:17 +00:00
|
|
|
|
2001-12-10 20:02:22 +00:00
|
|
|
#include <ddb/ddb.h>
|
|
|
|
|
2019-12-26 15:21:34 +00:00
|
|
|
#include <dev/kbd/kbdreg.h>
|
|
|
|
|
1995-12-09 20:39:47 +00:00
|
|
|
#include <machine/cpu.h>
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
#include <machine/clock.h>
|
1993-06-12 14:58:17 +00:00
|
|
|
|
2008-05-23 16:06:35 +00:00
|
|
|
static MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling");
|
|
|
|
|
2001-10-23 20:25:50 +00:00
|
|
|
struct cn_device {
|
|
|
|
STAILQ_ENTRY(cn_device) cnd_next;
|
|
|
|
struct consdev *cnd_cn;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define CNDEVPATHMAX 32
|
|
|
|
#define CNDEVTAB_SIZE 4
|
|
|
|
static struct cn_device cn_devtab[CNDEVTAB_SIZE];
|
|
|
|
static STAILQ_HEAD(, cn_device) cn_devlist =
|
|
|
|
STAILQ_HEAD_INITIALIZER(cn_devlist);
|
|
|
|
|
2004-02-05 01:56:43 +00:00
|
|
|
int cons_avail_mask = 0; /* Bit mask. Each registered low level console
|
|
|
|
* which is currently unavailable for inpit
|
|
|
|
* (i.e., if it is in graphics mode) will have
|
|
|
|
* this bit cleared.
|
1995-04-08 21:32:11 +00:00
|
|
|
*/
|
2020-10-05 15:54:19 +00:00
|
|
|
|
2001-10-23 20:25:50 +00:00
|
|
|
static int cn_mute;
|
2020-10-05 15:54:19 +00:00
|
|
|
SYSCTL_INT(_kern, OID_AUTO, consmute, CTLFLAG_RW, &cn_mute, 0,
|
|
|
|
"State of the console muting");
|
|
|
|
|
2003-06-22 02:54:33 +00:00
|
|
|
static char *consbuf; /* buffer used by `consmsgbuf' */
|
|
|
|
static struct callout conscallout; /* callout for outputting to constty */
|
|
|
|
struct msgbuf consmsgbuf; /* message buffer for console tty */
|
2001-12-10 20:02:22 +00:00
|
|
|
static u_char console_pausing; /* pause after each line during probe */
|
2020-02-23 03:32:16 +00:00
|
|
|
static const char console_pausestr[] =
|
2001-12-10 20:02:22 +00:00
|
|
|
"<pause; press any key to proceed to next line or '.' to end pause mode>";
|
2003-06-22 02:54:33 +00:00
|
|
|
struct tty *constty; /* pointer to console "window" tty */
|
2021-09-04 02:18:51 +00:00
|
|
|
static struct mtx constty_mtx; /* Mutex for constty assignment. */
|
|
|
|
MTX_SYSINIT(constty_mtx, &constty_mtx, "constty_mtx", MTX_DEF);
|
2006-11-01 04:54:51 +00:00
|
|
|
static struct mtx cnputs_mtx; /* Mutex for cnputs(). */
|
2021-09-04 02:18:51 +00:00
|
|
|
MTX_SYSINIT(cnputs_mtx, &cnputs_mtx, "cnputs_mtx", MTX_SPIN | MTX_NOWITNESS);
|
1995-01-21 14:12:15 +00:00
|
|
|
|
2003-06-22 02:54:33 +00:00
|
|
|
static void constty_timeout(void *arg);
|
2001-10-25 00:14:16 +00:00
|
|
|
|
2006-05-26 10:46:38 +00:00
|
|
|
static struct consdev cons_consdev;
|
|
|
|
DATA_SET(cons_set, cons_consdev);
|
2001-06-13 10:58:39 +00:00
|
|
|
SET_DECLARE(cons_set, struct consdev);
|
1999-01-07 14:14:24 +00:00
|
|
|
|
2019-12-26 15:47:19 +00:00
|
|
|
/*
|
|
|
|
* Stub for configurations that don't actually have a keyboard driver. Inclusion
|
|
|
|
* of kbd.c is contingent on any number of keyboard/console drivers being
|
|
|
|
* present in the kernel; rather than trying to catch them all, we'll just
|
|
|
|
* maintain this weak kbdinit that will be overridden by the strong version in
|
|
|
|
* kbd.c if it's present.
|
|
|
|
*/
|
|
|
|
__weak_symbol void
|
|
|
|
kbdinit(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
1993-11-25 01:38:01 +00:00
|
|
|
void
|
2001-10-23 20:25:50 +00:00
|
|
|
cninit(void)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2001-10-23 20:25:50 +00:00
|
|
|
struct consdev *best_cn, *cn, **list;
|
1995-09-10 18:57:26 +00:00
|
|
|
|
1996-10-16 00:19:40 +00:00
|
|
|
/*
|
|
|
|
* Check if we should mute the console (for security reasons perhaps)
|
|
|
|
* It can be changes dynamically using sysctl kern.consmute
|
|
|
|
* once we are up and going.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
cn_mute = ((boothowto & (RB_MUTE
|
|
|
|
|RB_SINGLE
|
|
|
|
|RB_VERBOSE
|
2004-12-01 04:59:33 +00:00
|
|
|
|RB_ASKNAME)) == RB_MUTE);
|
2001-10-23 20:25:50 +00:00
|
|
|
|
2019-12-26 15:21:34 +00:00
|
|
|
/*
|
|
|
|
* Bring up the kbd layer just in time for cnprobe. Console drivers
|
|
|
|
* have a dependency on kbd being ready, so this fits nicely between the
|
|
|
|
* machdep callers of cninit() and MI probing/initialization of consoles
|
|
|
|
* here.
|
|
|
|
*/
|
|
|
|
kbdinit();
|
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
/*
|
2001-10-23 20:25:50 +00:00
|
|
|
* Find the first console with the highest priority.
|
1993-06-12 14:58:17 +00:00
|
|
|
*/
|
2001-10-23 20:25:50 +00:00
|
|
|
best_cn = NULL;
|
|
|
|
SET_FOREACH(list, cons_set) {
|
|
|
|
cn = *list;
|
2002-08-06 18:56:41 +00:00
|
|
|
cnremove(cn);
|
Allow multiple console devices per driver without insane code duplication.
Say, a driver wants to have multiple console devices to pick from, you
would normally write down something like this:
CONSOLE_DRIVER(dev1);
CONSOLE_DRIVER(dev2);
Unfortunately, this means that you have to declare 10 cn routines,
instead of 5. It also isn't possible to initialize cn_arg on beforehand.
I noticed this restriction when I was implementing some of the console
bits for my vt(4) driver in my newcons branch. I have a single set of cn
routines (termcn_*) which are shared by all vt(4) console devices.
In order to solve this, I'm adding a separate consdev_ops structure,
which contains all the function pointers. This structure is referenced
through consdev's cn_ops field.
While there, I'm removing CONS_DRIVER() and cn_checkc, which have been
deprecated for years. They weren't used throughout the source, until the
Xen console driver showed up. CONSOLE_DRIVER() has been changed to do
the right thing. It now declares both the consdev and consdev_ops
structure and ties them together. In other words: this change doesn't
change the KPI for drivers that used the regular way of declaring
console devices.
If drivers want to use multiple console devices, they can do this as
follows:
static const struct consdev_ops mydriver_cnops = {
.cn_probe = mydriver_cnprobe,
...
};
static struct mydriver_softc cons0_softc = {
...
};
CONSOLE_DEVICE(cons0, mydriver_cnops, &cons0_softc);
static struct mydriver_softc cons1_softc = {
...
};
CONSOLE_DEVICE(cons1, mydriver_cnops, &cons1_softc);
Obtained from: //depot/user/ed/newcons/...
2009-08-24 10:53:30 +00:00
|
|
|
/* Skip cons_consdev. */
|
|
|
|
if (cn->cn_ops == NULL)
|
2001-10-23 20:25:50 +00:00
|
|
|
continue;
|
Allow multiple console devices per driver without insane code duplication.
Say, a driver wants to have multiple console devices to pick from, you
would normally write down something like this:
CONSOLE_DRIVER(dev1);
CONSOLE_DRIVER(dev2);
Unfortunately, this means that you have to declare 10 cn routines,
instead of 5. It also isn't possible to initialize cn_arg on beforehand.
I noticed this restriction when I was implementing some of the console
bits for my vt(4) driver in my newcons branch. I have a single set of cn
routines (termcn_*) which are shared by all vt(4) console devices.
In order to solve this, I'm adding a separate consdev_ops structure,
which contains all the function pointers. This structure is referenced
through consdev's cn_ops field.
While there, I'm removing CONS_DRIVER() and cn_checkc, which have been
deprecated for years. They weren't used throughout the source, until the
Xen console driver showed up. CONSOLE_DRIVER() has been changed to do
the right thing. It now declares both the consdev and consdev_ops
structure and ties them together. In other words: this change doesn't
change the KPI for drivers that used the regular way of declaring
console devices.
If drivers want to use multiple console devices, they can do this as
follows:
static const struct consdev_ops mydriver_cnops = {
.cn_probe = mydriver_cnprobe,
...
};
static struct mydriver_softc cons0_softc = {
...
};
CONSOLE_DEVICE(cons0, mydriver_cnops, &cons0_softc);
static struct mydriver_softc cons1_softc = {
...
};
CONSOLE_DEVICE(cons1, mydriver_cnops, &cons1_softc);
Obtained from: //depot/user/ed/newcons/...
2009-08-24 10:53:30 +00:00
|
|
|
cn->cn_ops->cn_probe(cn);
|
2001-10-23 20:25:50 +00:00
|
|
|
if (cn->cn_pri == CN_DEAD)
|
|
|
|
continue;
|
|
|
|
if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri)
|
|
|
|
best_cn = cn;
|
|
|
|
if (boothowto & RB_MULTIPLE) {
|
|
|
|
/*
|
|
|
|
* Initialize console, and attach to it.
|
|
|
|
*/
|
Allow multiple console devices per driver without insane code duplication.
Say, a driver wants to have multiple console devices to pick from, you
would normally write down something like this:
CONSOLE_DRIVER(dev1);
CONSOLE_DRIVER(dev2);
Unfortunately, this means that you have to declare 10 cn routines,
instead of 5. It also isn't possible to initialize cn_arg on beforehand.
I noticed this restriction when I was implementing some of the console
bits for my vt(4) driver in my newcons branch. I have a single set of cn
routines (termcn_*) which are shared by all vt(4) console devices.
In order to solve this, I'm adding a separate consdev_ops structure,
which contains all the function pointers. This structure is referenced
through consdev's cn_ops field.
While there, I'm removing CONS_DRIVER() and cn_checkc, which have been
deprecated for years. They weren't used throughout the source, until the
Xen console driver showed up. CONSOLE_DRIVER() has been changed to do
the right thing. It now declares both the consdev and consdev_ops
structure and ties them together. In other words: this change doesn't
change the KPI for drivers that used the regular way of declaring
console devices.
If drivers want to use multiple console devices, they can do this as
follows:
static const struct consdev_ops mydriver_cnops = {
.cn_probe = mydriver_cnprobe,
...
};
static struct mydriver_softc cons0_softc = {
...
};
CONSOLE_DEVICE(cons0, mydriver_cnops, &cons0_softc);
static struct mydriver_softc cons1_softc = {
...
};
CONSOLE_DEVICE(cons1, mydriver_cnops, &cons1_softc);
Obtained from: //depot/user/ed/newcons/...
2009-08-24 10:53:30 +00:00
|
|
|
cn->cn_ops->cn_init(cn);
|
2006-11-03 06:23:53 +00:00
|
|
|
cnadd(cn);
|
2001-10-23 20:25:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (best_cn == NULL)
|
1995-09-10 18:57:26 +00:00
|
|
|
return;
|
2001-10-23 20:25:50 +00:00
|
|
|
if ((boothowto & RB_MULTIPLE) == 0) {
|
Allow multiple console devices per driver without insane code duplication.
Say, a driver wants to have multiple console devices to pick from, you
would normally write down something like this:
CONSOLE_DRIVER(dev1);
CONSOLE_DRIVER(dev2);
Unfortunately, this means that you have to declare 10 cn routines,
instead of 5. It also isn't possible to initialize cn_arg on beforehand.
I noticed this restriction when I was implementing some of the console
bits for my vt(4) driver in my newcons branch. I have a single set of cn
routines (termcn_*) which are shared by all vt(4) console devices.
In order to solve this, I'm adding a separate consdev_ops structure,
which contains all the function pointers. This structure is referenced
through consdev's cn_ops field.
While there, I'm removing CONS_DRIVER() and cn_checkc, which have been
deprecated for years. They weren't used throughout the source, until the
Xen console driver showed up. CONSOLE_DRIVER() has been changed to do
the right thing. It now declares both the consdev and consdev_ops
structure and ties them together. In other words: this change doesn't
change the KPI for drivers that used the regular way of declaring
console devices.
If drivers want to use multiple console devices, they can do this as
follows:
static const struct consdev_ops mydriver_cnops = {
.cn_probe = mydriver_cnprobe,
...
};
static struct mydriver_softc cons0_softc = {
...
};
CONSOLE_DEVICE(cons0, mydriver_cnops, &cons0_softc);
static struct mydriver_softc cons1_softc = {
...
};
CONSOLE_DEVICE(cons1, mydriver_cnops, &cons1_softc);
Obtained from: //depot/user/ed/newcons/...
2009-08-24 10:53:30 +00:00
|
|
|
best_cn->cn_ops->cn_init(best_cn);
|
2006-11-03 06:23:53 +00:00
|
|
|
cnadd(best_cn);
|
1995-09-10 18:57:26 +00:00
|
|
|
}
|
2001-12-10 20:02:22 +00:00
|
|
|
if (boothowto & RB_PAUSE)
|
|
|
|
console_pausing = 1;
|
1995-09-10 18:57:26 +00:00
|
|
|
/*
|
2001-10-23 20:25:50 +00:00
|
|
|
* Make the best console the preferred console.
|
1995-09-10 18:57:26 +00:00
|
|
|
*/
|
2001-10-23 20:25:50 +00:00
|
|
|
cnselect(best_cn);
|
2014-11-19 14:23:29 +00:00
|
|
|
|
|
|
|
#ifdef EARLY_PRINTF
|
|
|
|
/*
|
|
|
|
* Release early console.
|
|
|
|
*/
|
|
|
|
early_putc = NULL;
|
|
|
|
#endif
|
2001-10-23 20:25:50 +00:00
|
|
|
}
|
|
|
|
|
2001-12-10 20:02:22 +00:00
|
|
|
void
|
|
|
|
cninit_finish()
|
|
|
|
{
|
|
|
|
console_pausing = 0;
|
|
|
|
}
|
|
|
|
|
2001-10-23 20:25:50 +00:00
|
|
|
/* add a new physical console to back the virtual console */
|
|
|
|
int
|
|
|
|
cnadd(struct consdev *cn)
|
|
|
|
{
|
|
|
|
struct cn_device *cnd;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
|
|
|
|
if (cnd->cnd_cn == cn)
|
|
|
|
return (0);
|
|
|
|
for (i = 0; i < CNDEVTAB_SIZE; i++) {
|
|
|
|
cnd = &cn_devtab[i];
|
|
|
|
if (cnd->cnd_cn == NULL)
|
|
|
|
break;
|
The second phase of syscons reorganization.
- Split syscons source code into manageable chunks and reorganize
some of complicated functions.
- Many static variables are moved to the softc structure.
- Added a new key function, PREV. When this key is pressed, the vty
immediately before the current vty will become foreground. Analogue
to PREV, which is usually assigned to the PrntScrn key.
PR: kern/10113
Submitted by: Christian Weisgerber <naddy@mips.rhein-neckar.de>
- Modified the kernel console input function sccngetc() so that it
handles function keys properly.
- Reorganized the screen update routine.
- VT switching code is reorganized. It now should be slightly more
robust than before.
- Added the DEVICE_RESUME function so that syscons no longer hooks the
APM resume event directly.
- New kernel configuration options: SC_NO_CUTPASTE, SC_NO_FONT_LOADING,
SC_NO_HISTORY and SC_NO_SYSMOUSE.
Various parts of syscons can be omitted so that the kernel size is
reduced.
SC_PIXEL_MODE
Made the VESA 800x600 mode an option, rather than a standard part of
syscons.
SC_DISABLE_DDBKEY
Disables the `debug' key combination.
SC_ALT_MOUSE_IMAGE
Inverse the character cell at the mouse cursor position in the text
console, rather than drawing an arrow on the screen.
Submitted by: Nick Hibma (n_hibma@FreeBSD.ORG)
SC_DFLT_FONT
makeoptions "SC_DFLT_FONT=_font_name_"
Include the named font as the default font of syscons. 16-line,
14-line and 8-line font data will be compiled in. This option replaces
the existing STD8X16FONT option, which loads 16-line font data only.
- The VGA driver is split into /sys/dev/fb/vga.c and /sys/isa/vga_isa.c.
- The video driver provides a set of ioctl commands to manipulate the
frame buffer.
- New kernel configuration option: VGA_WIDTH90
Enables 90 column modes: 90x25, 90x30, 90x43, 90x50, 90x60. These
modes are mot always supported by the video card.
PR: i386/7510
Submitted by: kbyanc@freedomnet.com and alexv@sui.gda.itesm.mx.
- The header file machine/console.h is reorganized; its contents is now
split into sys/fbio.h, sys/kbio.h (a new file) and sys/consio.h
(another new file). machine/console.h is still maintained for
compatibility reasons.
- Kernel console selection/installation routines are fixed and
slightly rebumped so that it should now be possible to switch between
the interanl kernel console (sc or vt) and a remote kernel console
(sio) again, as it was in 2.x, 3.0 and 3.1.
- Screen savers and splash screen decoders
Because of the header file reorganization described above, screen
savers and splash screen decoders are slightly modified. After this
update, /sys/modules/syscons/saver.h is no longer necessary and is
removed.
1999-06-22 14:14:06 +00:00
|
|
|
}
|
2001-10-23 20:25:50 +00:00
|
|
|
if (cnd->cnd_cn != NULL)
|
|
|
|
return (ENOMEM);
|
|
|
|
cnd->cnd_cn = cn;
|
2003-09-26 07:26:54 +00:00
|
|
|
if (cn->cn_name[0] == '\0') {
|
|
|
|
/* XXX: it is unclear if/where this print might output */
|
|
|
|
printf("WARNING: console at %p has no name\n", cn);
|
|
|
|
}
|
2001-10-23 20:25:50 +00:00
|
|
|
STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next);
|
2008-11-01 08:35:28 +00:00
|
|
|
if (STAILQ_FIRST(&cn_devlist) == cnd)
|
|
|
|
ttyconsdev_select(cnd->cnd_cn->cn_name);
|
2004-02-05 01:56:43 +00:00
|
|
|
|
|
|
|
/* Add device to the active mask. */
|
|
|
|
cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0);
|
|
|
|
|
2001-10-23 20:25:50 +00:00
|
|
|
return (0);
|
1995-09-10 18:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2001-10-23 20:25:50 +00:00
|
|
|
cnremove(struct consdev *cn)
|
1995-09-10 18:57:26 +00:00
|
|
|
{
|
2001-10-23 20:25:50 +00:00
|
|
|
struct cn_device *cnd;
|
2004-02-05 01:56:43 +00:00
|
|
|
int i;
|
1995-09-10 18:57:26 +00:00
|
|
|
|
2001-10-23 20:25:50 +00:00
|
|
|
STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
|
|
|
|
if (cnd->cnd_cn != cn)
|
|
|
|
continue;
|
2008-11-01 08:35:28 +00:00
|
|
|
if (STAILQ_FIRST(&cn_devlist) == cnd)
|
|
|
|
ttyconsdev_select(NULL);
|
2001-10-23 20:25:50 +00:00
|
|
|
STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
|
|
|
|
cnd->cnd_cn = NULL;
|
2004-02-05 01:56:43 +00:00
|
|
|
|
|
|
|
/* Remove this device from available mask. */
|
|
|
|
for (i = 0; i < CNDEVTAB_SIZE; i++)
|
|
|
|
if (cnd == &cn_devtab[i]) {
|
|
|
|
cons_avail_mask &= ~(1 << i);
|
|
|
|
break;
|
|
|
|
}
|
2001-10-23 20:25:50 +00:00
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* XXX
|
|
|
|
* syscons gets really confused if console resources are
|
|
|
|
* freed after the system has initialized.
|
|
|
|
*/
|
|
|
|
if (cn->cn_term != NULL)
|
Allow multiple console devices per driver without insane code duplication.
Say, a driver wants to have multiple console devices to pick from, you
would normally write down something like this:
CONSOLE_DRIVER(dev1);
CONSOLE_DRIVER(dev2);
Unfortunately, this means that you have to declare 10 cn routines,
instead of 5. It also isn't possible to initialize cn_arg on beforehand.
I noticed this restriction when I was implementing some of the console
bits for my vt(4) driver in my newcons branch. I have a single set of cn
routines (termcn_*) which are shared by all vt(4) console devices.
In order to solve this, I'm adding a separate consdev_ops structure,
which contains all the function pointers. This structure is referenced
through consdev's cn_ops field.
While there, I'm removing CONS_DRIVER() and cn_checkc, which have been
deprecated for years. They weren't used throughout the source, until the
Xen console driver showed up. CONSOLE_DRIVER() has been changed to do
the right thing. It now declares both the consdev and consdev_ops
structure and ties them together. In other words: this change doesn't
change the KPI for drivers that used the regular way of declaring
console devices.
If drivers want to use multiple console devices, they can do this as
follows:
static const struct consdev_ops mydriver_cnops = {
.cn_probe = mydriver_cnprobe,
...
};
static struct mydriver_softc cons0_softc = {
...
};
CONSOLE_DEVICE(cons0, mydriver_cnops, &cons0_softc);
static struct mydriver_softc cons1_softc = {
...
};
CONSOLE_DEVICE(cons1, mydriver_cnops, &cons1_softc);
Obtained from: //depot/user/ed/newcons/...
2009-08-24 10:53:30 +00:00
|
|
|
cn->cn_ops->cn_term(cn);
|
2001-10-23 20:25:50 +00:00
|
|
|
#endif
|
1993-06-12 14:58:17 +00:00
|
|
|
return;
|
2000-01-25 09:20:08 +00:00
|
|
|
}
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
2001-10-23 20:25:50 +00:00
|
|
|
void
|
|
|
|
cnselect(struct consdev *cn)
|
1997-08-08 20:09:50 +00:00
|
|
|
{
|
2001-10-23 20:25:50 +00:00
|
|
|
struct cn_device *cnd;
|
1997-08-08 20:09:50 +00:00
|
|
|
|
2001-10-23 20:25:50 +00:00
|
|
|
STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
|
|
|
|
if (cnd->cnd_cn != cn)
|
|
|
|
continue;
|
|
|
|
if (cnd == STAILQ_FIRST(&cn_devlist))
|
|
|
|
return;
|
|
|
|
STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
|
|
|
|
STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next);
|
2008-11-01 08:35:28 +00:00
|
|
|
ttyconsdev_select(cnd->cnd_cn->cn_name);
|
1997-08-08 20:09:50 +00:00
|
|
|
return;
|
2001-10-23 20:25:50 +00:00
|
|
|
}
|
|
|
|
}
|
1997-08-08 20:09:50 +00:00
|
|
|
|
2004-02-05 01:56:43 +00:00
|
|
|
void
|
|
|
|
cnavailable(struct consdev *cn, int available)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < CNDEVTAB_SIZE; i++) {
|
|
|
|
if (cn_devtab[i].cnd_cn == cn)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (available) {
|
|
|
|
if (i < CNDEVTAB_SIZE)
|
|
|
|
cons_avail_mask |= (1 << i);
|
|
|
|
cn->cn_flags &= ~CN_FLAG_NOAVAIL;
|
|
|
|
} else {
|
|
|
|
if (i < CNDEVTAB_SIZE)
|
|
|
|
cons_avail_mask &= ~(1 << i);
|
|
|
|
cn->cn_flags |= CN_FLAG_NOAVAIL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-02-05 17:35:28 +00:00
|
|
|
cnunavailable(void)
|
2004-02-05 01:56:43 +00:00
|
|
|
{
|
2001-10-23 20:25:50 +00:00
|
|
|
|
2004-02-05 17:35:28 +00:00
|
|
|
return (cons_avail_mask == 0);
|
2001-10-23 20:25:50 +00:00
|
|
|
}
|
|
|
|
|
2003-09-26 07:26:54 +00:00
|
|
|
/*
|
2007-12-25 21:17:34 +00:00
|
|
|
* sysctl_kern_console() provides output parseable in conscontrol(1).
|
2003-09-26 07:26:54 +00:00
|
|
|
*/
|
2001-10-23 20:25:50 +00:00
|
|
|
static int
|
|
|
|
sysctl_kern_console(SYSCTL_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
struct cn_device *cnd;
|
|
|
|
struct consdev *cp, **list;
|
2007-12-25 21:17:34 +00:00
|
|
|
char *p;
|
|
|
|
int delete, error;
|
|
|
|
struct sbuf *sb;
|
2001-10-23 20:25:50 +00:00
|
|
|
|
2015-03-15 00:36:08 +00:00
|
|
|
sb = sbuf_new(NULL, NULL, CNDEVPATHMAX * 2, SBUF_AUTOEXTEND |
|
|
|
|
SBUF_INCLUDENUL);
|
2007-12-25 21:17:34 +00:00
|
|
|
if (sb == NULL)
|
|
|
|
return (ENOMEM);
|
|
|
|
sbuf_clear(sb);
|
2001-10-23 20:25:50 +00:00
|
|
|
STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
|
2007-12-25 21:17:34 +00:00
|
|
|
sbuf_printf(sb, "%s,", cnd->cnd_cn->cn_name);
|
|
|
|
sbuf_printf(sb, "/");
|
2001-10-23 20:25:50 +00:00
|
|
|
SET_FOREACH(list, cons_set) {
|
|
|
|
cp = *list;
|
2003-09-26 07:26:54 +00:00
|
|
|
if (cp->cn_name[0] != '\0')
|
2007-12-25 21:17:34 +00:00
|
|
|
sbuf_printf(sb, "%s,", cp->cn_name);
|
2001-10-23 20:25:50 +00:00
|
|
|
}
|
2007-12-25 21:17:34 +00:00
|
|
|
sbuf_finish(sb);
|
|
|
|
error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req);
|
2001-10-23 20:25:50 +00:00
|
|
|
if (error == 0 && req->newptr != NULL) {
|
2007-12-25 21:17:34 +00:00
|
|
|
p = sbuf_data(sb);
|
2001-10-23 20:25:50 +00:00
|
|
|
error = ENXIO;
|
|
|
|
delete = 0;
|
|
|
|
if (*p == '-') {
|
|
|
|
delete = 1;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
SET_FOREACH(list, cons_set) {
|
|
|
|
cp = *list;
|
2003-09-26 07:26:54 +00:00
|
|
|
if (strcmp(p, cp->cn_name) != 0)
|
2001-10-23 20:25:50 +00:00
|
|
|
continue;
|
|
|
|
if (delete) {
|
|
|
|
cnremove(cp);
|
|
|
|
error = 0;
|
|
|
|
} else {
|
|
|
|
error = cnadd(cp);
|
|
|
|
if (error == 0)
|
|
|
|
cnselect(cp);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2000-01-25 09:20:08 +00:00
|
|
|
}
|
2007-12-25 21:17:34 +00:00
|
|
|
sbuf_delete(sb);
|
2001-10-23 20:25:50 +00:00
|
|
|
return (error);
|
1997-08-08 20:09:50 +00:00
|
|
|
}
|
|
|
|
|
2020-02-26 14:26:36 +00:00
|
|
|
SYSCTL_PROC(_kern, OID_AUTO, console,
|
|
|
|
CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 0, 0,
|
|
|
|
sysctl_kern_console, "A",
|
|
|
|
"Console device control");
|
2001-10-23 20:25:50 +00:00
|
|
|
|
2011-12-17 15:08:43 +00:00
|
|
|
void
|
|
|
|
cngrab()
|
|
|
|
{
|
|
|
|
struct cn_device *cnd;
|
|
|
|
struct consdev *cn;
|
|
|
|
|
|
|
|
STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
|
|
|
|
cn = cnd->cnd_cn;
|
|
|
|
if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG))
|
|
|
|
cn->cn_ops->cn_grab(cn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cnungrab()
|
|
|
|
{
|
|
|
|
struct cn_device *cnd;
|
|
|
|
struct consdev *cn;
|
|
|
|
|
|
|
|
STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
|
|
|
|
cn = cnd->cnd_cn;
|
|
|
|
if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG))
|
|
|
|
cn->cn_ops->cn_ungrab(cn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-29 16:16:24 +00:00
|
|
|
void
|
|
|
|
cnresume()
|
|
|
|
{
|
|
|
|
struct cn_device *cnd;
|
|
|
|
struct consdev *cn;
|
|
|
|
|
|
|
|
STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
|
|
|
|
cn = cnd->cnd_cn;
|
|
|
|
if (cn->cn_ops->cn_resume != NULL)
|
|
|
|
cn->cn_ops->cn_resume(cn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-23 20:25:50 +00:00
|
|
|
/*
|
|
|
|
* Low level console routines.
|
|
|
|
*/
|
1993-11-25 01:38:01 +00:00
|
|
|
int
|
2001-10-23 20:25:50 +00:00
|
|
|
cngetc(void)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
1994-12-18 19:35:59 +00:00
|
|
|
int c;
|
2001-10-23 20:25:50 +00:00
|
|
|
|
|
|
|
if (cn_mute)
|
1996-10-30 21:40:25 +00:00
|
|
|
return (-1);
|
2001-10-23 20:25:50 +00:00
|
|
|
while ((c = cncheckc()) == -1)
|
2012-10-06 19:50:23 +00:00
|
|
|
cpu_spinwait();
|
2001-10-23 20:25:50 +00:00
|
|
|
if (c == '\r')
|
|
|
|
c = '\n'; /* console input is always ICRNL */
|
1994-12-18 19:35:59 +00:00
|
|
|
return (c);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
1994-10-20 00:08:31 +00:00
|
|
|
int
|
2001-10-23 20:25:50 +00:00
|
|
|
cncheckc(void)
|
1994-10-20 00:08:31 +00:00
|
|
|
{
|
2001-10-23 20:25:50 +00:00
|
|
|
struct cn_device *cnd;
|
|
|
|
struct consdev *cn;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
if (cn_mute)
|
1996-09-14 04:25:32 +00:00
|
|
|
return (-1);
|
2001-10-23 20:25:50 +00:00
|
|
|
STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
|
|
|
|
cn = cnd->cnd_cn;
|
2004-07-10 21:43:23 +00:00
|
|
|
if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) {
|
Allow multiple console devices per driver without insane code duplication.
Say, a driver wants to have multiple console devices to pick from, you
would normally write down something like this:
CONSOLE_DRIVER(dev1);
CONSOLE_DRIVER(dev2);
Unfortunately, this means that you have to declare 10 cn routines,
instead of 5. It also isn't possible to initialize cn_arg on beforehand.
I noticed this restriction when I was implementing some of the console
bits for my vt(4) driver in my newcons branch. I have a single set of cn
routines (termcn_*) which are shared by all vt(4) console devices.
In order to solve this, I'm adding a separate consdev_ops structure,
which contains all the function pointers. This structure is referenced
through consdev's cn_ops field.
While there, I'm removing CONS_DRIVER() and cn_checkc, which have been
deprecated for years. They weren't used throughout the source, until the
Xen console driver showed up. CONSOLE_DRIVER() has been changed to do
the right thing. It now declares both the consdev and consdev_ops
structure and ties them together. In other words: this change doesn't
change the KPI for drivers that used the regular way of declaring
console devices.
If drivers want to use multiple console devices, they can do this as
follows:
static const struct consdev_ops mydriver_cnops = {
.cn_probe = mydriver_cnprobe,
...
};
static struct mydriver_softc cons0_softc = {
...
};
CONSOLE_DEVICE(cons0, mydriver_cnops, &cons0_softc);
static struct mydriver_softc cons1_softc = {
...
};
CONSOLE_DEVICE(cons1, mydriver_cnops, &cons1_softc);
Obtained from: //depot/user/ed/newcons/...
2009-08-24 10:53:30 +00:00
|
|
|
c = cn->cn_ops->cn_getc(cn);
|
|
|
|
if (c != -1)
|
2003-10-18 02:13:39 +00:00
|
|
|
return (c);
|
2001-10-23 20:25:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return (-1);
|
1994-10-20 00:08:31 +00:00
|
|
|
}
|
|
|
|
|
2011-12-17 15:16:54 +00:00
|
|
|
void
|
|
|
|
cngets(char *cp, size_t size, int visible)
|
|
|
|
{
|
|
|
|
char *lp, *end;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
cngrab();
|
|
|
|
|
|
|
|
lp = cp;
|
|
|
|
end = cp + size - 1;
|
|
|
|
for (;;) {
|
|
|
|
c = cngetc() & 0177;
|
|
|
|
switch (c) {
|
|
|
|
case '\n':
|
|
|
|
case '\r':
|
|
|
|
cnputc(c);
|
|
|
|
*lp = '\0';
|
|
|
|
cnungrab();
|
|
|
|
return;
|
|
|
|
case '\b':
|
|
|
|
case '\177':
|
|
|
|
if (lp > cp) {
|
2013-12-31 04:40:25 +00:00
|
|
|
if (visible)
|
|
|
|
cnputs("\b \b");
|
2011-12-17 15:16:54 +00:00
|
|
|
lp--;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
case '\0':
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
if (lp < end) {
|
|
|
|
switch (visible) {
|
|
|
|
case GETS_NOECHO:
|
|
|
|
break;
|
|
|
|
case GETS_ECHOPASS:
|
|
|
|
cnputc('*');
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cnputc(c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*lp++ = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1993-11-25 01:38:01 +00:00
|
|
|
void
|
2001-10-23 20:25:50 +00:00
|
|
|
cnputc(int c)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2001-10-23 20:25:50 +00:00
|
|
|
struct cn_device *cnd;
|
|
|
|
struct consdev *cn;
|
2020-02-23 03:32:16 +00:00
|
|
|
const char *cp;
|
2001-10-23 20:25:50 +00:00
|
|
|
|
2014-02-12 00:53:38 +00:00
|
|
|
#ifdef EARLY_PRINTF
|
|
|
|
if (early_putc != NULL) {
|
|
|
|
if (c == '\n')
|
|
|
|
early_putc('\r');
|
|
|
|
early_putc(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-10-23 20:25:50 +00:00
|
|
|
if (cn_mute || c == '\0')
|
1993-06-12 14:58:17 +00:00
|
|
|
return;
|
2001-10-23 20:25:50 +00:00
|
|
|
STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
|
|
|
|
cn = cnd->cnd_cn;
|
2004-07-10 21:43:23 +00:00
|
|
|
if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) {
|
2003-10-18 02:13:39 +00:00
|
|
|
if (c == '\n')
|
Allow multiple console devices per driver without insane code duplication.
Say, a driver wants to have multiple console devices to pick from, you
would normally write down something like this:
CONSOLE_DRIVER(dev1);
CONSOLE_DRIVER(dev2);
Unfortunately, this means that you have to declare 10 cn routines,
instead of 5. It also isn't possible to initialize cn_arg on beforehand.
I noticed this restriction when I was implementing some of the console
bits for my vt(4) driver in my newcons branch. I have a single set of cn
routines (termcn_*) which are shared by all vt(4) console devices.
In order to solve this, I'm adding a separate consdev_ops structure,
which contains all the function pointers. This structure is referenced
through consdev's cn_ops field.
While there, I'm removing CONS_DRIVER() and cn_checkc, which have been
deprecated for years. They weren't used throughout the source, until the
Xen console driver showed up. CONSOLE_DRIVER() has been changed to do
the right thing. It now declares both the consdev and consdev_ops
structure and ties them together. In other words: this change doesn't
change the KPI for drivers that used the regular way of declaring
console devices.
If drivers want to use multiple console devices, they can do this as
follows:
static const struct consdev_ops mydriver_cnops = {
.cn_probe = mydriver_cnprobe,
...
};
static struct mydriver_softc cons0_softc = {
...
};
CONSOLE_DEVICE(cons0, mydriver_cnops, &cons0_softc);
static struct mydriver_softc cons1_softc = {
...
};
CONSOLE_DEVICE(cons1, mydriver_cnops, &cons1_softc);
Obtained from: //depot/user/ed/newcons/...
2009-08-24 10:53:30 +00:00
|
|
|
cn->cn_ops->cn_putc(cn, '\r');
|
|
|
|
cn->cn_ops->cn_putc(cn, c);
|
2003-10-18 02:13:39 +00:00
|
|
|
}
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
2004-07-10 21:43:23 +00:00
|
|
|
if (console_pausing && c == '\n' && !kdb_active) {
|
2001-12-10 20:02:22 +00:00
|
|
|
for (cp = console_pausestr; *cp != '\0'; cp++)
|
|
|
|
cnputc(*cp);
|
2011-12-17 15:11:22 +00:00
|
|
|
cngrab();
|
2001-12-10 20:02:22 +00:00
|
|
|
if (cngetc() == '.')
|
|
|
|
console_pausing = 0;
|
2011-12-17 15:11:22 +00:00
|
|
|
cnungrab();
|
2001-12-10 20:02:22 +00:00
|
|
|
cnputc('\r');
|
|
|
|
for (cp = console_pausestr; *cp != '\0'; cp++)
|
|
|
|
cnputc(' ');
|
|
|
|
cnputc('\r');
|
|
|
|
}
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
2006-11-01 04:54:51 +00:00
|
|
|
void
|
2018-10-20 18:31:36 +00:00
|
|
|
cnputsn(const char *p, size_t n)
|
2006-11-01 04:54:51 +00:00
|
|
|
{
|
2018-10-20 18:31:36 +00:00
|
|
|
size_t i;
|
2006-11-01 04:54:51 +00:00
|
|
|
int unlock_reqd = 0;
|
|
|
|
|
2021-09-04 02:18:51 +00:00
|
|
|
if (mtx_initialized(&cnputs_mtx)) {
|
|
|
|
/*
|
2015-01-03 17:21:19 +00:00
|
|
|
* NOTE: Debug prints and/or witness printouts in
|
|
|
|
* console driver clients can cause the "cnputs_mtx"
|
|
|
|
* mutex to recurse. Simply return if that happens.
|
|
|
|
*/
|
|
|
|
if (mtx_owned(&cnputs_mtx))
|
|
|
|
return;
|
2006-11-01 04:54:51 +00:00
|
|
|
mtx_lock_spin(&cnputs_mtx);
|
|
|
|
unlock_reqd = 1;
|
|
|
|
}
|
|
|
|
|
2018-10-20 18:31:36 +00:00
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
cnputc(p[i]);
|
2006-11-01 04:54:51 +00:00
|
|
|
|
|
|
|
if (unlock_reqd)
|
|
|
|
mtx_unlock_spin(&cnputs_mtx);
|
|
|
|
}
|
|
|
|
|
2018-10-20 18:31:36 +00:00
|
|
|
void
|
2020-02-23 03:32:16 +00:00
|
|
|
cnputs(const char *p)
|
2018-10-20 18:31:36 +00:00
|
|
|
{
|
|
|
|
cnputsn(p, strlen(p));
|
|
|
|
}
|
|
|
|
|
2021-09-04 02:18:51 +00:00
|
|
|
static unsigned int consmsgbuf_size = 65536;
|
|
|
|
SYSCTL_UINT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RWTUN, &consmsgbuf_size,
|
|
|
|
0, "Console tty buffer size");
|
2003-06-22 02:54:33 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Redirect console output to a tty.
|
|
|
|
*/
|
2021-09-04 02:18:51 +00:00
|
|
|
int
|
2003-06-22 02:54:33 +00:00
|
|
|
constty_set(struct tty *tp)
|
|
|
|
{
|
2021-09-04 02:18:51 +00:00
|
|
|
int size = consmsgbuf_size;
|
|
|
|
void *buf = NULL;
|
|
|
|
|
|
|
|
tty_assert_locked(tp);
|
|
|
|
if (constty == tp)
|
|
|
|
return (0);
|
|
|
|
if (constty != NULL)
|
|
|
|
return (EBUSY);
|
2003-06-22 02:54:33 +00:00
|
|
|
|
|
|
|
if (consbuf == NULL) {
|
2021-09-04 02:18:51 +00:00
|
|
|
tty_unlock(tp);
|
|
|
|
buf = malloc(size, M_TTYCONS, M_WAITOK);
|
|
|
|
tty_lock(tp);
|
2003-06-22 02:54:33 +00:00
|
|
|
}
|
2021-09-04 02:18:51 +00:00
|
|
|
mtx_lock(&constty_mtx);
|
|
|
|
if (constty != NULL) {
|
|
|
|
mtx_unlock(&constty_mtx);
|
|
|
|
free(buf, M_TTYCONS);
|
|
|
|
return (EBUSY);
|
|
|
|
}
|
|
|
|
if (consbuf == NULL) {
|
|
|
|
consbuf = buf;
|
|
|
|
msgbuf_init(&consmsgbuf, buf, size);
|
|
|
|
} else
|
|
|
|
free(buf, M_TTYCONS);
|
2003-06-22 02:54:33 +00:00
|
|
|
constty = tp;
|
2021-09-04 02:18:51 +00:00
|
|
|
mtx_unlock(&constty_mtx);
|
|
|
|
|
|
|
|
callout_init_mtx(&conscallout, tty_getlock(tp), 0);
|
|
|
|
constty_timeout(tp);
|
|
|
|
return (0);
|
2003-06-22 02:54:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Disable console redirection to a tty.
|
|
|
|
*/
|
2021-09-04 02:18:51 +00:00
|
|
|
int
|
|
|
|
constty_clear(struct tty *tp)
|
2003-06-22 02:54:33 +00:00
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
2021-09-04 02:18:51 +00:00
|
|
|
tty_assert_locked(tp);
|
|
|
|
if (constty != tp)
|
|
|
|
return (ENXIO);
|
2003-06-22 02:54:33 +00:00
|
|
|
callout_stop(&conscallout);
|
2021-09-04 02:18:51 +00:00
|
|
|
mtx_lock(&constty_mtx);
|
|
|
|
constty = NULL;
|
|
|
|
mtx_unlock(&constty_mtx);
|
2003-06-22 02:54:33 +00:00
|
|
|
while ((c = msgbuf_getchar(&consmsgbuf)) != -1)
|
|
|
|
cnputc(c);
|
2021-09-04 02:18:51 +00:00
|
|
|
/* We never free consbuf because it can still be in use. */
|
|
|
|
return (0);
|
2003-06-22 02:54:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Times per second to check for pending console tty messages. */
|
2021-09-04 02:18:51 +00:00
|
|
|
static int constty_wakeups_per_second = 15;
|
2003-06-22 02:54:33 +00:00
|
|
|
SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW,
|
2010-08-09 14:48:31 +00:00
|
|
|
&constty_wakeups_per_second, 0,
|
|
|
|
"Times per second to check for pending console tty messages");
|
2003-06-22 02:54:33 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
constty_timeout(void *arg)
|
|
|
|
{
|
2021-09-04 02:18:51 +00:00
|
|
|
struct tty *tp = arg;
|
2003-06-22 02:54:33 +00:00
|
|
|
int c;
|
|
|
|
|
2021-09-04 02:18:51 +00:00
|
|
|
tty_assert_locked(tp);
|
|
|
|
while ((c = msgbuf_getchar(&consmsgbuf)) != -1) {
|
|
|
|
if (tty_putchar(tp, c) < 0) {
|
|
|
|
constty_clear(tp);
|
|
|
|
return;
|
Integrate the new MPSAFE TTY layer to the FreeBSD operating system.
The last half year I've been working on a replacement TTY layer for the
FreeBSD kernel. The new TTY layer was designed to improve the following:
- Improved driver model:
The old TTY layer has a driver model that is not abstract enough to
make it friendly to use. A good example is the output path, where the
device drivers directly access the output buffers. This means that an
in-kernel PPP implementation must always convert network buffers into
TTY buffers.
If a PPP implementation would be built on top of the new TTY layer
(still needs a hooks layer, though), it would allow the PPP
implementation to directly hand the data to the TTY driver.
- Improved hotplugging:
With the old TTY layer, it isn't entirely safe to destroy TTY's from
the system. This implementation has a two-step destructing design,
where the driver first abandons the TTY. After all threads have left
the TTY, the TTY layer calls a routine in the driver, which can be
used to free resources (unit numbers, etc).
The pts(4) driver also implements this feature, which means
posix_openpt() will now return PTY's that are created on the fly.
- Improved performance:
One of the major improvements is the per-TTY mutex, which is expected
to improve scalability when compared to the old Giant locking.
Another change is the unbuffered copying to userspace, which is both
used on TTY device nodes and PTY masters.
Upgrading should be quite straightforward. Unlike previous versions,
existing kernel configuration files do not need to be changed, except
when they reference device drivers that are listed in UPDATING.
Obtained from: //depot/projects/mpsafetty/...
Approved by: philip (ex-mentor)
Discussed: on the lists, at BSDCan, at the DevSummit
Sponsored by: Snow B.V., the Netherlands
dcons(4) fixed by: kan
2008-08-20 08:31:58 +00:00
|
|
|
}
|
2003-06-22 02:54:33 +00:00
|
|
|
}
|
2021-09-04 02:18:51 +00:00
|
|
|
callout_reset_sbt(&conscallout, SBT_1S / constty_wakeups_per_second,
|
|
|
|
0, constty_timeout, tp, C_PREL(1));
|
2003-06-22 02:54:33 +00:00
|
|
|
}
|
|
|
|
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
/*
|
|
|
|
* Sysbeep(), if we have hardware for it
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAS_TIMER_SPKR
|
|
|
|
|
|
|
|
static int beeping;
|
2014-09-22 14:27:26 +00:00
|
|
|
static struct callout beeping_timer;
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
sysbeepstop(void *chan)
|
|
|
|
{
|
|
|
|
|
|
|
|
timer_spkr_release();
|
|
|
|
beeping = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sysbeep(int pitch, int period)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (timer_spkr_acquire()) {
|
|
|
|
if (!beeping) {
|
|
|
|
/* Something else owns it. */
|
|
|
|
return (EBUSY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
timer_spkr_setfreq(pitch);
|
|
|
|
if (!beeping) {
|
|
|
|
beeping = period;
|
2014-09-22 14:27:26 +00:00
|
|
|
callout_reset(&beeping_timer, period, sysbeepstop, NULL);
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2014-09-22 14:27:26 +00:00
|
|
|
static void
|
|
|
|
sysbeep_init(void *unused)
|
|
|
|
{
|
|
|
|
|
2015-05-22 17:05:21 +00:00
|
|
|
callout_init(&beeping_timer, 1);
|
2014-09-22 14:27:26 +00:00
|
|
|
}
|
|
|
|
SYSINIT(sysbeep, SI_SUB_SOFTINTR, SI_ORDER_ANY, sysbeep_init, NULL);
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No hardware, no sound
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
sysbeep(int pitch __unused, int period __unused)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (ENODEV);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2014-06-27 17:50:33 +00:00
|
|
|
/*
|
|
|
|
* Temporary support for sc(4) to vt(4) transition.
|
|
|
|
*/
|
2014-07-02 13:24:21 +00:00
|
|
|
static unsigned vty_prefer;
|
2014-06-28 03:56:17 +00:00
|
|
|
static char vty_name[16];
|
|
|
|
SYSCTL_STRING(_kern, OID_AUTO, vty, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, vty_name,
|
|
|
|
0, "Console vty driver");
|
2014-06-27 17:50:33 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
vty_enabled(unsigned vty)
|
|
|
|
{
|
|
|
|
static unsigned vty_selected = 0;
|
|
|
|
|
|
|
|
if (vty_selected == 0) {
|
|
|
|
TUNABLE_STR_FETCH("kern.vty", vty_name, sizeof(vty_name));
|
|
|
|
do {
|
|
|
|
#if defined(DEV_SC)
|
|
|
|
if (strcmp(vty_name, "sc") == 0) {
|
|
|
|
vty_selected = VTY_SC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(DEV_VT)
|
|
|
|
if (strcmp(vty_name, "vt") == 0) {
|
|
|
|
vty_selected = VTY_VT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2014-07-02 13:24:21 +00:00
|
|
|
if (vty_prefer != 0) {
|
|
|
|
vty_selected = vty_prefer;
|
|
|
|
break;
|
|
|
|
}
|
2014-11-04 10:18:03 +00:00
|
|
|
#if defined(DEV_VT)
|
2014-06-27 17:50:33 +00:00
|
|
|
vty_selected = VTY_VT;
|
2014-11-04 10:18:03 +00:00
|
|
|
#elif defined(DEV_SC)
|
|
|
|
vty_selected = VTY_SC;
|
2014-06-27 17:50:33 +00:00
|
|
|
#endif
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
if (vty_selected == VTY_VT)
|
|
|
|
strcpy(vty_name, "vt");
|
|
|
|
else if (vty_selected == VTY_SC)
|
|
|
|
strcpy(vty_name, "sc");
|
|
|
|
}
|
|
|
|
return ((vty_selected & vty) != 0);
|
|
|
|
}
|
|
|
|
|
2014-07-02 13:24:21 +00:00
|
|
|
void
|
|
|
|
vty_set_preferred(unsigned vty)
|
|
|
|
{
|
|
|
|
|
|
|
|
vty_prefer = vty;
|
|
|
|
#if !defined(DEV_SC)
|
2014-07-02 14:47:48 +00:00
|
|
|
vty_prefer &= ~VTY_SC;
|
2014-07-02 13:24:21 +00:00
|
|
|
#endif
|
|
|
|
#if !defined(DEV_VT)
|
2014-07-02 14:47:48 +00:00
|
|
|
vty_prefer &= ~VTY_VT;
|
2014-07-02 13:24:21 +00:00
|
|
|
#endif
|
|
|
|
}
|