xref: /freebsd/sys/kern/subr_terminal.c (revision 27cf7d04ef5416dc7fcbf43bc8147463b0d87848)
1*27cf7d04SAleksandr Rybalko /*-
2*27cf7d04SAleksandr Rybalko  * Copyright (c) 2009 The FreeBSD Foundation
3*27cf7d04SAleksandr Rybalko  * All rights reserved.
4*27cf7d04SAleksandr Rybalko  *
5*27cf7d04SAleksandr Rybalko  * This software was developed by Ed Schouten under sponsorship from the
6*27cf7d04SAleksandr Rybalko  * FreeBSD Foundation.
7*27cf7d04SAleksandr Rybalko  *
8*27cf7d04SAleksandr Rybalko  * Redistribution and use in source and binary forms, with or without
9*27cf7d04SAleksandr Rybalko  * modification, are permitted provided that the following conditions
10*27cf7d04SAleksandr Rybalko  * are met:
11*27cf7d04SAleksandr Rybalko  * 1. Redistributions of source code must retain the above copyright
12*27cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer.
13*27cf7d04SAleksandr Rybalko  * 2. Redistributions in binary form must reproduce the above copyright
14*27cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer in the
15*27cf7d04SAleksandr Rybalko  *    documentation and/or other materials provided with the distribution.
16*27cf7d04SAleksandr Rybalko  *
17*27cf7d04SAleksandr Rybalko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*27cf7d04SAleksandr Rybalko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*27cf7d04SAleksandr Rybalko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*27cf7d04SAleksandr Rybalko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*27cf7d04SAleksandr Rybalko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*27cf7d04SAleksandr Rybalko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*27cf7d04SAleksandr Rybalko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*27cf7d04SAleksandr Rybalko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*27cf7d04SAleksandr Rybalko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*27cf7d04SAleksandr Rybalko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*27cf7d04SAleksandr Rybalko  * SUCH DAMAGE.
28*27cf7d04SAleksandr Rybalko  */
29*27cf7d04SAleksandr Rybalko 
30*27cf7d04SAleksandr Rybalko #include <sys/cdefs.h>
31*27cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$");
32*27cf7d04SAleksandr Rybalko 
33*27cf7d04SAleksandr Rybalko #include <sys/param.h>
34*27cf7d04SAleksandr Rybalko #include <sys/cons.h>
35*27cf7d04SAleksandr Rybalko #include <sys/consio.h>
36*27cf7d04SAleksandr Rybalko #include <sys/kernel.h>
37*27cf7d04SAleksandr Rybalko #include <sys/lock.h>
38*27cf7d04SAleksandr Rybalko #include <sys/malloc.h>
39*27cf7d04SAleksandr Rybalko #include <sys/mutex.h>
40*27cf7d04SAleksandr Rybalko #include <sys/systm.h>
41*27cf7d04SAleksandr Rybalko #include <sys/terminal.h>
42*27cf7d04SAleksandr Rybalko #include <sys/tty.h>
43*27cf7d04SAleksandr Rybalko 
44*27cf7d04SAleksandr Rybalko #include <machine/stdarg.h>
45*27cf7d04SAleksandr Rybalko 
46*27cf7d04SAleksandr Rybalko static MALLOC_DEFINE(M_TERMINAL, "terminal", "terminal device");
47*27cf7d04SAleksandr Rybalko 
48*27cf7d04SAleksandr Rybalko /*
49*27cf7d04SAleksandr Rybalko  * Locking.
50*27cf7d04SAleksandr Rybalko  *
51*27cf7d04SAleksandr Rybalko  * Normally we don't need to lock down the terminal emulator, because
52*27cf7d04SAleksandr Rybalko  * the TTY lock is already held when calling teken_input().
53*27cf7d04SAleksandr Rybalko  * Unfortunately this is not the case when the terminal acts as a
54*27cf7d04SAleksandr Rybalko  * console device, because cnputc() can be called at the same time.
55*27cf7d04SAleksandr Rybalko  * This means terminals may need to be locked down using a spin lock.
56*27cf7d04SAleksandr Rybalko  */
57*27cf7d04SAleksandr Rybalko #define	TERMINAL_LOCK(tm)	do {					\
58*27cf7d04SAleksandr Rybalko 	if ((tm)->tm_flags & TF_CONS)					\
59*27cf7d04SAleksandr Rybalko 		mtx_lock_spin(&(tm)->tm_mtx);				\
60*27cf7d04SAleksandr Rybalko 	else if ((tm)->tm_tty != NULL)					\
61*27cf7d04SAleksandr Rybalko 		tty_lock((tm)->tm_tty);					\
62*27cf7d04SAleksandr Rybalko } while (0)
63*27cf7d04SAleksandr Rybalko #define	TERMINAL_UNLOCK(tm)	do {					\
64*27cf7d04SAleksandr Rybalko 	if ((tm)->tm_flags & TF_CONS)					\
65*27cf7d04SAleksandr Rybalko 		mtx_unlock_spin(&(tm)->tm_mtx);				\
66*27cf7d04SAleksandr Rybalko 	else if ((tm)->tm_tty != NULL)					\
67*27cf7d04SAleksandr Rybalko 		tty_unlock((tm)->tm_tty);				\
68*27cf7d04SAleksandr Rybalko } while (0)
69*27cf7d04SAleksandr Rybalko #define	TERMINAL_LOCK_TTY(tm)	do {					\
70*27cf7d04SAleksandr Rybalko 	if ((tm)->tm_flags & TF_CONS)					\
71*27cf7d04SAleksandr Rybalko 		mtx_lock_spin(&(tm)->tm_mtx);				\
72*27cf7d04SAleksandr Rybalko } while (0)
73*27cf7d04SAleksandr Rybalko #define	TERMINAL_UNLOCK_TTY(tm)	do {					\
74*27cf7d04SAleksandr Rybalko 	if ((tm)->tm_flags & TF_CONS)					\
75*27cf7d04SAleksandr Rybalko 		mtx_unlock_spin(&(tm)->tm_mtx);				\
76*27cf7d04SAleksandr Rybalko } while (0)
77*27cf7d04SAleksandr Rybalko #define	TERMINAL_LOCK_CONS(tm)		mtx_lock_spin(&(tm)->tm_mtx)
78*27cf7d04SAleksandr Rybalko #define	TERMINAL_UNLOCK_CONS(tm)	mtx_unlock_spin(&(tm)->tm_mtx)
79*27cf7d04SAleksandr Rybalko 
80*27cf7d04SAleksandr Rybalko /*
81*27cf7d04SAleksandr Rybalko  * TTY routines.
82*27cf7d04SAleksandr Rybalko  */
83*27cf7d04SAleksandr Rybalko 
84*27cf7d04SAleksandr Rybalko static tsw_open_t	termtty_open;
85*27cf7d04SAleksandr Rybalko static tsw_close_t	termtty_close;
86*27cf7d04SAleksandr Rybalko static tsw_outwakeup_t	termtty_outwakeup;
87*27cf7d04SAleksandr Rybalko static tsw_ioctl_t	termtty_ioctl;
88*27cf7d04SAleksandr Rybalko 
89*27cf7d04SAleksandr Rybalko static struct ttydevsw terminal_tty_class = {
90*27cf7d04SAleksandr Rybalko 	.tsw_open	= termtty_open,
91*27cf7d04SAleksandr Rybalko 	.tsw_close	= termtty_close,
92*27cf7d04SAleksandr Rybalko 	.tsw_outwakeup	= termtty_outwakeup,
93*27cf7d04SAleksandr Rybalko 	.tsw_ioctl	= termtty_ioctl,
94*27cf7d04SAleksandr Rybalko };
95*27cf7d04SAleksandr Rybalko 
96*27cf7d04SAleksandr Rybalko /*
97*27cf7d04SAleksandr Rybalko  * Terminal emulator routines.
98*27cf7d04SAleksandr Rybalko  */
99*27cf7d04SAleksandr Rybalko 
100*27cf7d04SAleksandr Rybalko static tf_bell_t	termteken_bell;
101*27cf7d04SAleksandr Rybalko static tf_cursor_t	termteken_cursor;
102*27cf7d04SAleksandr Rybalko static tf_putchar_t	termteken_putchar;
103*27cf7d04SAleksandr Rybalko static tf_fill_t	termteken_fill;
104*27cf7d04SAleksandr Rybalko static tf_copy_t	termteken_copy;
105*27cf7d04SAleksandr Rybalko static tf_param_t	termteken_param;
106*27cf7d04SAleksandr Rybalko static tf_respond_t	termteken_respond;
107*27cf7d04SAleksandr Rybalko 
108*27cf7d04SAleksandr Rybalko static teken_funcs_t terminal_drawmethods = {
109*27cf7d04SAleksandr Rybalko 	.tf_bell	= termteken_bell,
110*27cf7d04SAleksandr Rybalko 	.tf_cursor	= termteken_cursor,
111*27cf7d04SAleksandr Rybalko 	.tf_putchar	= termteken_putchar,
112*27cf7d04SAleksandr Rybalko 	.tf_fill	= termteken_fill,
113*27cf7d04SAleksandr Rybalko 	.tf_copy	= termteken_copy,
114*27cf7d04SAleksandr Rybalko 	.tf_param	= termteken_param,
115*27cf7d04SAleksandr Rybalko 	.tf_respond	= termteken_respond,
116*27cf7d04SAleksandr Rybalko };
117*27cf7d04SAleksandr Rybalko 
118*27cf7d04SAleksandr Rybalko /* Kernel message formatting. */
119*27cf7d04SAleksandr Rybalko static const teken_attr_t kernel_message = {
120*27cf7d04SAleksandr Rybalko 	.ta_fgcolor	= TC_WHITE,
121*27cf7d04SAleksandr Rybalko 	.ta_bgcolor	= TC_BLACK,
122*27cf7d04SAleksandr Rybalko 	.ta_format	= TF_BOLD,
123*27cf7d04SAleksandr Rybalko };
124*27cf7d04SAleksandr Rybalko 
125*27cf7d04SAleksandr Rybalko static const teken_attr_t default_message = {
126*27cf7d04SAleksandr Rybalko 	.ta_fgcolor	= TC_WHITE,
127*27cf7d04SAleksandr Rybalko 	.ta_bgcolor	= TC_BLACK,
128*27cf7d04SAleksandr Rybalko };
129*27cf7d04SAleksandr Rybalko 
130*27cf7d04SAleksandr Rybalko #define	TCHAR_CREATE(c, a)	((c) | \
131*27cf7d04SAleksandr Rybalko 	(a)->ta_format << 22 | \
132*27cf7d04SAleksandr Rybalko 	teken_256to8((a)->ta_fgcolor) << 26 | \
133*27cf7d04SAleksandr Rybalko 	teken_256to8((a)->ta_bgcolor) << 29)
134*27cf7d04SAleksandr Rybalko 
135*27cf7d04SAleksandr Rybalko static void
136*27cf7d04SAleksandr Rybalko terminal_init(struct terminal *tm)
137*27cf7d04SAleksandr Rybalko {
138*27cf7d04SAleksandr Rybalko 
139*27cf7d04SAleksandr Rybalko 	if (tm->tm_flags & TF_CONS)
140*27cf7d04SAleksandr Rybalko 		mtx_init(&tm->tm_mtx, "trmlck", NULL, MTX_SPIN);
141*27cf7d04SAleksandr Rybalko 	teken_init(&tm->tm_emulator, &terminal_drawmethods, tm);
142*27cf7d04SAleksandr Rybalko 	teken_set_defattr(&tm->tm_emulator, &default_message);
143*27cf7d04SAleksandr Rybalko }
144*27cf7d04SAleksandr Rybalko 
145*27cf7d04SAleksandr Rybalko struct terminal *
146*27cf7d04SAleksandr Rybalko terminal_alloc(const struct terminal_class *tc, void *softc)
147*27cf7d04SAleksandr Rybalko {
148*27cf7d04SAleksandr Rybalko 	struct terminal *tm;
149*27cf7d04SAleksandr Rybalko 
150*27cf7d04SAleksandr Rybalko 	tm = malloc(sizeof(struct terminal), M_TERMINAL, M_WAITOK|M_ZERO);
151*27cf7d04SAleksandr Rybalko 	terminal_init(tm);
152*27cf7d04SAleksandr Rybalko 
153*27cf7d04SAleksandr Rybalko 	tm->tm_class = tc;
154*27cf7d04SAleksandr Rybalko 	tm->tm_softc = softc;
155*27cf7d04SAleksandr Rybalko 
156*27cf7d04SAleksandr Rybalko 	return (tm);
157*27cf7d04SAleksandr Rybalko }
158*27cf7d04SAleksandr Rybalko 
159*27cf7d04SAleksandr Rybalko static void
160*27cf7d04SAleksandr Rybalko terminal_sync_ttysize(struct terminal *tm)
161*27cf7d04SAleksandr Rybalko {
162*27cf7d04SAleksandr Rybalko 	struct tty *tp;
163*27cf7d04SAleksandr Rybalko 
164*27cf7d04SAleksandr Rybalko 	tp = tm->tm_tty;
165*27cf7d04SAleksandr Rybalko 	if (tp == NULL)
166*27cf7d04SAleksandr Rybalko 		return;
167*27cf7d04SAleksandr Rybalko 
168*27cf7d04SAleksandr Rybalko 	tty_lock(tp);
169*27cf7d04SAleksandr Rybalko 	tty_set_winsize(tp, &tm->tm_winsize);
170*27cf7d04SAleksandr Rybalko 	tty_unlock(tp);
171*27cf7d04SAleksandr Rybalko }
172*27cf7d04SAleksandr Rybalko 
173*27cf7d04SAleksandr Rybalko void
174*27cf7d04SAleksandr Rybalko terminal_maketty(struct terminal *tm, const char *fmt, ...)
175*27cf7d04SAleksandr Rybalko {
176*27cf7d04SAleksandr Rybalko 	struct tty *tp;
177*27cf7d04SAleksandr Rybalko 	char name[8];
178*27cf7d04SAleksandr Rybalko 	va_list ap;
179*27cf7d04SAleksandr Rybalko 
180*27cf7d04SAleksandr Rybalko 	va_start(ap, fmt);
181*27cf7d04SAleksandr Rybalko 	vsnrprintf(name, sizeof name, 32, fmt, ap);
182*27cf7d04SAleksandr Rybalko 	va_end(ap);
183*27cf7d04SAleksandr Rybalko 
184*27cf7d04SAleksandr Rybalko 	tp = tty_alloc(&terminal_tty_class, tm);
185*27cf7d04SAleksandr Rybalko 	tty_makedev(tp, NULL, "%s", name);
186*27cf7d04SAleksandr Rybalko 	tm->tm_tty = tp;
187*27cf7d04SAleksandr Rybalko 	terminal_sync_ttysize(tm);
188*27cf7d04SAleksandr Rybalko }
189*27cf7d04SAleksandr Rybalko 
190*27cf7d04SAleksandr Rybalko void
191*27cf7d04SAleksandr Rybalko terminal_set_winsize_blank(struct terminal *tm, const struct winsize *size,
192*27cf7d04SAleksandr Rybalko     int blank)
193*27cf7d04SAleksandr Rybalko {
194*27cf7d04SAleksandr Rybalko 	term_rect_t r;
195*27cf7d04SAleksandr Rybalko 
196*27cf7d04SAleksandr Rybalko 	tm->tm_winsize = *size;
197*27cf7d04SAleksandr Rybalko 
198*27cf7d04SAleksandr Rybalko 	r.tr_begin.tp_row = r.tr_begin.tp_col = 0;
199*27cf7d04SAleksandr Rybalko 	r.tr_end.tp_row = size->ws_row;
200*27cf7d04SAleksandr Rybalko 	r.tr_end.tp_col = size->ws_col;
201*27cf7d04SAleksandr Rybalko 
202*27cf7d04SAleksandr Rybalko 	TERMINAL_LOCK(tm);
203*27cf7d04SAleksandr Rybalko 	if (blank == 0)
204*27cf7d04SAleksandr Rybalko 		teken_set_winsize_noreset(&tm->tm_emulator, &r.tr_end);
205*27cf7d04SAleksandr Rybalko 	else
206*27cf7d04SAleksandr Rybalko 		teken_set_winsize(&tm->tm_emulator, &r.tr_end);
207*27cf7d04SAleksandr Rybalko 	TERMINAL_UNLOCK(tm);
208*27cf7d04SAleksandr Rybalko 
209*27cf7d04SAleksandr Rybalko 	if (blank != 0)
210*27cf7d04SAleksandr Rybalko 		tm->tm_class->tc_fill(tm, &r, TCHAR_CREATE((teken_char_t)' ',
211*27cf7d04SAleksandr Rybalko 		    &default_message));
212*27cf7d04SAleksandr Rybalko 
213*27cf7d04SAleksandr Rybalko 	terminal_sync_ttysize(tm);
214*27cf7d04SAleksandr Rybalko }
215*27cf7d04SAleksandr Rybalko 
216*27cf7d04SAleksandr Rybalko void
217*27cf7d04SAleksandr Rybalko terminal_set_winsize(struct terminal *tm, const struct winsize *size)
218*27cf7d04SAleksandr Rybalko {
219*27cf7d04SAleksandr Rybalko 
220*27cf7d04SAleksandr Rybalko 	terminal_set_winsize_blank(tm, size, 1);
221*27cf7d04SAleksandr Rybalko }
222*27cf7d04SAleksandr Rybalko 
223*27cf7d04SAleksandr Rybalko /*
224*27cf7d04SAleksandr Rybalko  * XXX: This function is a kludge.  Drivers like vt(4) need to
225*27cf7d04SAleksandr Rybalko  * temporarily stop input when resizing, etc.  This should ideally be
226*27cf7d04SAleksandr Rybalko  * handled within the driver.
227*27cf7d04SAleksandr Rybalko  */
228*27cf7d04SAleksandr Rybalko 
229*27cf7d04SAleksandr Rybalko void
230*27cf7d04SAleksandr Rybalko terminal_mute(struct terminal *tm, int yes)
231*27cf7d04SAleksandr Rybalko {
232*27cf7d04SAleksandr Rybalko 
233*27cf7d04SAleksandr Rybalko 	TERMINAL_LOCK(tm);
234*27cf7d04SAleksandr Rybalko 	if (yes)
235*27cf7d04SAleksandr Rybalko 		tm->tm_flags |= TF_MUTE;
236*27cf7d04SAleksandr Rybalko 	else
237*27cf7d04SAleksandr Rybalko 		tm->tm_flags &= ~TF_MUTE;
238*27cf7d04SAleksandr Rybalko 	TERMINAL_UNLOCK(tm);
239*27cf7d04SAleksandr Rybalko }
240*27cf7d04SAleksandr Rybalko 
241*27cf7d04SAleksandr Rybalko void
242*27cf7d04SAleksandr Rybalko terminal_input_char(struct terminal *tm, term_char_t c)
243*27cf7d04SAleksandr Rybalko {
244*27cf7d04SAleksandr Rybalko 	struct tty *tp;
245*27cf7d04SAleksandr Rybalko 
246*27cf7d04SAleksandr Rybalko 	tp = tm->tm_tty;
247*27cf7d04SAleksandr Rybalko 	if (tp == NULL)
248*27cf7d04SAleksandr Rybalko 		return;
249*27cf7d04SAleksandr Rybalko 
250*27cf7d04SAleksandr Rybalko 	/* Strip off any attributes. */
251*27cf7d04SAleksandr Rybalko 	c = TCHAR_CHARACTER(c);
252*27cf7d04SAleksandr Rybalko 
253*27cf7d04SAleksandr Rybalko 	tty_lock(tp);
254*27cf7d04SAleksandr Rybalko 	/*
255*27cf7d04SAleksandr Rybalko 	 * Conversion to UTF-8.
256*27cf7d04SAleksandr Rybalko 	 */
257*27cf7d04SAleksandr Rybalko 	if (c < 0x80) {
258*27cf7d04SAleksandr Rybalko 		ttydisc_rint(tp, c, 0);
259*27cf7d04SAleksandr Rybalko 	} else if (c < 0x800) {
260*27cf7d04SAleksandr Rybalko 		char str[2] = {
261*27cf7d04SAleksandr Rybalko 			0xc0 | (c >> 6),
262*27cf7d04SAleksandr Rybalko 			0x80 | (c & 0x3f)
263*27cf7d04SAleksandr Rybalko 		};
264*27cf7d04SAleksandr Rybalko 
265*27cf7d04SAleksandr Rybalko 		ttydisc_rint_simple(tp, str, sizeof str);
266*27cf7d04SAleksandr Rybalko 	} else if (c < 0x10000) {
267*27cf7d04SAleksandr Rybalko 		char str[3] = {
268*27cf7d04SAleksandr Rybalko 			0xe0 | (c >> 12),
269*27cf7d04SAleksandr Rybalko 			0x80 | ((c >> 6) & 0x3f),
270*27cf7d04SAleksandr Rybalko 			0x80 | (c & 0x3f)
271*27cf7d04SAleksandr Rybalko 		};
272*27cf7d04SAleksandr Rybalko 
273*27cf7d04SAleksandr Rybalko 		ttydisc_rint_simple(tp, str, sizeof str);
274*27cf7d04SAleksandr Rybalko 	} else {
275*27cf7d04SAleksandr Rybalko 		char str[4] = {
276*27cf7d04SAleksandr Rybalko 			0xf0 | (c >> 18),
277*27cf7d04SAleksandr Rybalko 			0x80 | ((c >> 12) & 0x3f),
278*27cf7d04SAleksandr Rybalko 			0x80 | ((c >> 6) & 0x3f),
279*27cf7d04SAleksandr Rybalko 			0x80 | (c & 0x3f)
280*27cf7d04SAleksandr Rybalko 		};
281*27cf7d04SAleksandr Rybalko 
282*27cf7d04SAleksandr Rybalko 		ttydisc_rint_simple(tp, str, sizeof str);
283*27cf7d04SAleksandr Rybalko 	}
284*27cf7d04SAleksandr Rybalko 	ttydisc_rint_done(tp);
285*27cf7d04SAleksandr Rybalko 	tty_unlock(tp);
286*27cf7d04SAleksandr Rybalko }
287*27cf7d04SAleksandr Rybalko 
288*27cf7d04SAleksandr Rybalko void
289*27cf7d04SAleksandr Rybalko terminal_input_raw(struct terminal *tm, char c)
290*27cf7d04SAleksandr Rybalko {
291*27cf7d04SAleksandr Rybalko 	struct tty *tp;
292*27cf7d04SAleksandr Rybalko 
293*27cf7d04SAleksandr Rybalko 	tp = tm->tm_tty;
294*27cf7d04SAleksandr Rybalko 	if (tp == NULL)
295*27cf7d04SAleksandr Rybalko 		return;
296*27cf7d04SAleksandr Rybalko 
297*27cf7d04SAleksandr Rybalko 	tty_lock(tp);
298*27cf7d04SAleksandr Rybalko 	ttydisc_rint(tp, c, 0);
299*27cf7d04SAleksandr Rybalko 	ttydisc_rint_done(tp);
300*27cf7d04SAleksandr Rybalko 	tty_unlock(tp);
301*27cf7d04SAleksandr Rybalko }
302*27cf7d04SAleksandr Rybalko 
303*27cf7d04SAleksandr Rybalko void
304*27cf7d04SAleksandr Rybalko terminal_input_special(struct terminal *tm, unsigned int k)
305*27cf7d04SAleksandr Rybalko {
306*27cf7d04SAleksandr Rybalko 	struct tty *tp;
307*27cf7d04SAleksandr Rybalko 	const char *str;
308*27cf7d04SAleksandr Rybalko 
309*27cf7d04SAleksandr Rybalko 	tp = tm->tm_tty;
310*27cf7d04SAleksandr Rybalko 	if (tp == NULL)
311*27cf7d04SAleksandr Rybalko 		return;
312*27cf7d04SAleksandr Rybalko 
313*27cf7d04SAleksandr Rybalko 	str = teken_get_sequence(&tm->tm_emulator, k);
314*27cf7d04SAleksandr Rybalko 	if (str == NULL)
315*27cf7d04SAleksandr Rybalko 		return;
316*27cf7d04SAleksandr Rybalko 
317*27cf7d04SAleksandr Rybalko 	tty_lock(tp);
318*27cf7d04SAleksandr Rybalko 	ttydisc_rint_simple(tp, str, strlen(str));
319*27cf7d04SAleksandr Rybalko 	ttydisc_rint_done(tp);
320*27cf7d04SAleksandr Rybalko 	tty_unlock(tp);
321*27cf7d04SAleksandr Rybalko }
322*27cf7d04SAleksandr Rybalko 
323*27cf7d04SAleksandr Rybalko /*
324*27cf7d04SAleksandr Rybalko  * Binding with the TTY layer.
325*27cf7d04SAleksandr Rybalko  */
326*27cf7d04SAleksandr Rybalko 
327*27cf7d04SAleksandr Rybalko static int
328*27cf7d04SAleksandr Rybalko termtty_open(struct tty *tp)
329*27cf7d04SAleksandr Rybalko {
330*27cf7d04SAleksandr Rybalko 	struct terminal *tm = tty_softc(tp);
331*27cf7d04SAleksandr Rybalko 
332*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_opened(tm, 1);
333*27cf7d04SAleksandr Rybalko 	return (0);
334*27cf7d04SAleksandr Rybalko }
335*27cf7d04SAleksandr Rybalko 
336*27cf7d04SAleksandr Rybalko static void
337*27cf7d04SAleksandr Rybalko termtty_close(struct tty *tp)
338*27cf7d04SAleksandr Rybalko {
339*27cf7d04SAleksandr Rybalko 	struct terminal *tm = tty_softc(tp);
340*27cf7d04SAleksandr Rybalko 
341*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_opened(tm, 0);
342*27cf7d04SAleksandr Rybalko }
343*27cf7d04SAleksandr Rybalko 
344*27cf7d04SAleksandr Rybalko static void
345*27cf7d04SAleksandr Rybalko termtty_outwakeup(struct tty *tp)
346*27cf7d04SAleksandr Rybalko {
347*27cf7d04SAleksandr Rybalko 	struct terminal *tm = tty_softc(tp);
348*27cf7d04SAleksandr Rybalko 	char obuf[128];
349*27cf7d04SAleksandr Rybalko 	size_t olen;
350*27cf7d04SAleksandr Rybalko 	unsigned int flags = 0;
351*27cf7d04SAleksandr Rybalko 
352*27cf7d04SAleksandr Rybalko 	while ((olen = ttydisc_getc(tp, obuf, sizeof obuf)) > 0) {
353*27cf7d04SAleksandr Rybalko 		TERMINAL_LOCK_TTY(tm);
354*27cf7d04SAleksandr Rybalko 		if (!(tm->tm_flags & TF_MUTE)) {
355*27cf7d04SAleksandr Rybalko 			tm->tm_flags &= ~TF_BELL;
356*27cf7d04SAleksandr Rybalko 			teken_input(&tm->tm_emulator, obuf, olen);
357*27cf7d04SAleksandr Rybalko 			flags |= tm->tm_flags;
358*27cf7d04SAleksandr Rybalko 		}
359*27cf7d04SAleksandr Rybalko 		TERMINAL_UNLOCK_TTY(tm);
360*27cf7d04SAleksandr Rybalko 	}
361*27cf7d04SAleksandr Rybalko 
362*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_done(tm);
363*27cf7d04SAleksandr Rybalko 	if (flags & TF_BELL)
364*27cf7d04SAleksandr Rybalko 		tm->tm_class->tc_bell(tm);
365*27cf7d04SAleksandr Rybalko }
366*27cf7d04SAleksandr Rybalko 
367*27cf7d04SAleksandr Rybalko static int
368*27cf7d04SAleksandr Rybalko termtty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
369*27cf7d04SAleksandr Rybalko {
370*27cf7d04SAleksandr Rybalko 	struct terminal *tm = tty_softc(tp);
371*27cf7d04SAleksandr Rybalko 	int error;
372*27cf7d04SAleksandr Rybalko 
373*27cf7d04SAleksandr Rybalko 	switch (cmd) {
374*27cf7d04SAleksandr Rybalko 	case CONS_GETINFO: {
375*27cf7d04SAleksandr Rybalko 		vid_info_t *vi = (vid_info_t *)data;
376*27cf7d04SAleksandr Rybalko 		const teken_pos_t *p;
377*27cf7d04SAleksandr Rybalko 		int fg, bg;
378*27cf7d04SAleksandr Rybalko 
379*27cf7d04SAleksandr Rybalko 		if (vi->size != sizeof(vid_info_t))
380*27cf7d04SAleksandr Rybalko 			return (EINVAL);
381*27cf7d04SAleksandr Rybalko 
382*27cf7d04SAleksandr Rybalko 		/* Already help the console driver by filling in some data. */
383*27cf7d04SAleksandr Rybalko 		p = teken_get_cursor(&tm->tm_emulator);
384*27cf7d04SAleksandr Rybalko 		vi->mv_row = p->tp_row;
385*27cf7d04SAleksandr Rybalko 		vi->mv_col = p->tp_col;
386*27cf7d04SAleksandr Rybalko 
387*27cf7d04SAleksandr Rybalko 		p = teken_get_winsize(&tm->tm_emulator);
388*27cf7d04SAleksandr Rybalko 		vi->mv_rsz = p->tp_row;
389*27cf7d04SAleksandr Rybalko 		vi->mv_csz = p->tp_col;
390*27cf7d04SAleksandr Rybalko 
391*27cf7d04SAleksandr Rybalko 		teken_get_defattr_cons25(&tm->tm_emulator, &fg, &bg);
392*27cf7d04SAleksandr Rybalko 		vi->mv_norm.fore = fg;
393*27cf7d04SAleksandr Rybalko 		vi->mv_norm.back = bg;
394*27cf7d04SAleksandr Rybalko 		/* XXX: keep vidcontrol happy; bold backgrounds. */
395*27cf7d04SAleksandr Rybalko 		vi->mv_rev.fore = bg;
396*27cf7d04SAleksandr Rybalko 		vi->mv_rev.back = fg & 0x7;
397*27cf7d04SAleksandr Rybalko 		break;
398*27cf7d04SAleksandr Rybalko 	}
399*27cf7d04SAleksandr Rybalko 	}
400*27cf7d04SAleksandr Rybalko 
401*27cf7d04SAleksandr Rybalko 	/*
402*27cf7d04SAleksandr Rybalko 	 * Unlike various other drivers, this driver will never
403*27cf7d04SAleksandr Rybalko 	 * deallocate TTYs.  This means it's safe to temporarily unlock
404*27cf7d04SAleksandr Rybalko 	 * the TTY when handling ioctls.
405*27cf7d04SAleksandr Rybalko 	 */
406*27cf7d04SAleksandr Rybalko 	tty_unlock(tp);
407*27cf7d04SAleksandr Rybalko 	error = tm->tm_class->tc_ioctl(tm, cmd, data, td);
408*27cf7d04SAleksandr Rybalko 	tty_lock(tp);
409*27cf7d04SAleksandr Rybalko 	return (error);
410*27cf7d04SAleksandr Rybalko }
411*27cf7d04SAleksandr Rybalko 
412*27cf7d04SAleksandr Rybalko /*
413*27cf7d04SAleksandr Rybalko  * Binding with the kernel and debug console.
414*27cf7d04SAleksandr Rybalko  */
415*27cf7d04SAleksandr Rybalko 
416*27cf7d04SAleksandr Rybalko static cn_probe_t	termcn_cnprobe;
417*27cf7d04SAleksandr Rybalko static cn_init_t	termcn_cninit;
418*27cf7d04SAleksandr Rybalko static cn_term_t	termcn_cnterm;
419*27cf7d04SAleksandr Rybalko static cn_getc_t	termcn_cngetc;
420*27cf7d04SAleksandr Rybalko static cn_putc_t	termcn_cnputc;
421*27cf7d04SAleksandr Rybalko static cn_grab_t	termcn_cngrab;
422*27cf7d04SAleksandr Rybalko static cn_ungrab_t	termcn_cnungrab;
423*27cf7d04SAleksandr Rybalko 
424*27cf7d04SAleksandr Rybalko const struct consdev_ops termcn_cnops = {
425*27cf7d04SAleksandr Rybalko 	.cn_probe	= termcn_cnprobe,
426*27cf7d04SAleksandr Rybalko 	.cn_init	= termcn_cninit,
427*27cf7d04SAleksandr Rybalko 	.cn_term	= termcn_cnterm,
428*27cf7d04SAleksandr Rybalko 	.cn_getc	= termcn_cngetc,
429*27cf7d04SAleksandr Rybalko 	.cn_putc	= termcn_cnputc,
430*27cf7d04SAleksandr Rybalko 	.cn_grab	= termcn_cngrab,
431*27cf7d04SAleksandr Rybalko 	.cn_ungrab	= termcn_cnungrab,
432*27cf7d04SAleksandr Rybalko };
433*27cf7d04SAleksandr Rybalko 
434*27cf7d04SAleksandr Rybalko void
435*27cf7d04SAleksandr Rybalko termcn_cnregister(struct terminal *tm)
436*27cf7d04SAleksandr Rybalko {
437*27cf7d04SAleksandr Rybalko 	struct consdev *cp;
438*27cf7d04SAleksandr Rybalko 
439*27cf7d04SAleksandr Rybalko 	cp = tm->consdev;
440*27cf7d04SAleksandr Rybalko 	if (cp == NULL) {
441*27cf7d04SAleksandr Rybalko 		cp = malloc(sizeof(struct consdev), M_TERMINAL,
442*27cf7d04SAleksandr Rybalko 		    M_WAITOK|M_ZERO);
443*27cf7d04SAleksandr Rybalko 		cp->cn_ops = &termcn_cnops;
444*27cf7d04SAleksandr Rybalko 		cp->cn_arg = tm;
445*27cf7d04SAleksandr Rybalko 		cp->cn_pri = CN_INTERNAL;
446*27cf7d04SAleksandr Rybalko 		sprintf(cp->cn_name, "ttyv0");
447*27cf7d04SAleksandr Rybalko 
448*27cf7d04SAleksandr Rybalko 		tm->tm_flags = TF_CONS;
449*27cf7d04SAleksandr Rybalko 		tm->consdev = cp;
450*27cf7d04SAleksandr Rybalko 
451*27cf7d04SAleksandr Rybalko 		terminal_init(tm);
452*27cf7d04SAleksandr Rybalko 	}
453*27cf7d04SAleksandr Rybalko 
454*27cf7d04SAleksandr Rybalko 	/* Attach terminal as console. */
455*27cf7d04SAleksandr Rybalko 	cnadd(cp);
456*27cf7d04SAleksandr Rybalko }
457*27cf7d04SAleksandr Rybalko 
458*27cf7d04SAleksandr Rybalko static void
459*27cf7d04SAleksandr Rybalko termcn_cngrab(struct consdev *cp)
460*27cf7d04SAleksandr Rybalko {
461*27cf7d04SAleksandr Rybalko 
462*27cf7d04SAleksandr Rybalko }
463*27cf7d04SAleksandr Rybalko 
464*27cf7d04SAleksandr Rybalko static void
465*27cf7d04SAleksandr Rybalko termcn_cnungrab(struct consdev *cp)
466*27cf7d04SAleksandr Rybalko {
467*27cf7d04SAleksandr Rybalko 
468*27cf7d04SAleksandr Rybalko }
469*27cf7d04SAleksandr Rybalko 
470*27cf7d04SAleksandr Rybalko static void
471*27cf7d04SAleksandr Rybalko termcn_cnprobe(struct consdev *cp)
472*27cf7d04SAleksandr Rybalko {
473*27cf7d04SAleksandr Rybalko 	struct terminal *tm = cp->cn_arg;
474*27cf7d04SAleksandr Rybalko 
475*27cf7d04SAleksandr Rybalko 	if (tm == NULL) {
476*27cf7d04SAleksandr Rybalko 		cp->cn_pri = CN_DEAD;
477*27cf7d04SAleksandr Rybalko 		return;
478*27cf7d04SAleksandr Rybalko 	}
479*27cf7d04SAleksandr Rybalko 
480*27cf7d04SAleksandr Rybalko 	tm->consdev = cp;
481*27cf7d04SAleksandr Rybalko 	terminal_init(tm);
482*27cf7d04SAleksandr Rybalko 
483*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_cnprobe(tm, cp);
484*27cf7d04SAleksandr Rybalko }
485*27cf7d04SAleksandr Rybalko 
486*27cf7d04SAleksandr Rybalko static void
487*27cf7d04SAleksandr Rybalko termcn_cninit(struct consdev *cp)
488*27cf7d04SAleksandr Rybalko {
489*27cf7d04SAleksandr Rybalko 
490*27cf7d04SAleksandr Rybalko }
491*27cf7d04SAleksandr Rybalko 
492*27cf7d04SAleksandr Rybalko static void
493*27cf7d04SAleksandr Rybalko termcn_cnterm(struct consdev *cp)
494*27cf7d04SAleksandr Rybalko {
495*27cf7d04SAleksandr Rybalko 
496*27cf7d04SAleksandr Rybalko }
497*27cf7d04SAleksandr Rybalko 
498*27cf7d04SAleksandr Rybalko static int
499*27cf7d04SAleksandr Rybalko termcn_cngetc(struct consdev *cp)
500*27cf7d04SAleksandr Rybalko {
501*27cf7d04SAleksandr Rybalko 	struct terminal *tm = cp->cn_arg;
502*27cf7d04SAleksandr Rybalko 
503*27cf7d04SAleksandr Rybalko 	return (tm->tm_class->tc_cngetc(tm));
504*27cf7d04SAleksandr Rybalko }
505*27cf7d04SAleksandr Rybalko 
506*27cf7d04SAleksandr Rybalko static void
507*27cf7d04SAleksandr Rybalko termcn_cnputc(struct consdev *cp, int c)
508*27cf7d04SAleksandr Rybalko {
509*27cf7d04SAleksandr Rybalko 	struct terminal *tm = cp->cn_arg;
510*27cf7d04SAleksandr Rybalko 	teken_attr_t backup;
511*27cf7d04SAleksandr Rybalko 	char cv = c;
512*27cf7d04SAleksandr Rybalko 
513*27cf7d04SAleksandr Rybalko 	TERMINAL_LOCK_CONS(tm);
514*27cf7d04SAleksandr Rybalko 	if (!(tm->tm_flags & TF_MUTE)) {
515*27cf7d04SAleksandr Rybalko 		backup = *teken_get_curattr(&tm->tm_emulator);
516*27cf7d04SAleksandr Rybalko 		teken_set_curattr(&tm->tm_emulator, &kernel_message);
517*27cf7d04SAleksandr Rybalko 		teken_input(&tm->tm_emulator, &cv, 1);
518*27cf7d04SAleksandr Rybalko 		teken_set_curattr(&tm->tm_emulator, &backup);
519*27cf7d04SAleksandr Rybalko 	}
520*27cf7d04SAleksandr Rybalko 	TERMINAL_UNLOCK_CONS(tm);
521*27cf7d04SAleksandr Rybalko 
522*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_done(tm);
523*27cf7d04SAleksandr Rybalko }
524*27cf7d04SAleksandr Rybalko 
525*27cf7d04SAleksandr Rybalko /*
526*27cf7d04SAleksandr Rybalko  * Binding with the terminal emulator.
527*27cf7d04SAleksandr Rybalko  */
528*27cf7d04SAleksandr Rybalko 
529*27cf7d04SAleksandr Rybalko static void
530*27cf7d04SAleksandr Rybalko termteken_bell(void *softc)
531*27cf7d04SAleksandr Rybalko {
532*27cf7d04SAleksandr Rybalko 	struct terminal *tm = softc;
533*27cf7d04SAleksandr Rybalko 
534*27cf7d04SAleksandr Rybalko 	tm->tm_flags |= TF_BELL;
535*27cf7d04SAleksandr Rybalko }
536*27cf7d04SAleksandr Rybalko 
537*27cf7d04SAleksandr Rybalko static void
538*27cf7d04SAleksandr Rybalko termteken_cursor(void *softc, const teken_pos_t *p)
539*27cf7d04SAleksandr Rybalko {
540*27cf7d04SAleksandr Rybalko 	struct terminal *tm = softc;
541*27cf7d04SAleksandr Rybalko 
542*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_cursor(tm, p);
543*27cf7d04SAleksandr Rybalko }
544*27cf7d04SAleksandr Rybalko 
545*27cf7d04SAleksandr Rybalko static void
546*27cf7d04SAleksandr Rybalko termteken_putchar(void *softc, const teken_pos_t *p, teken_char_t c,
547*27cf7d04SAleksandr Rybalko     const teken_attr_t *a)
548*27cf7d04SAleksandr Rybalko {
549*27cf7d04SAleksandr Rybalko 	struct terminal *tm = softc;
550*27cf7d04SAleksandr Rybalko 
551*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_putchar(tm, p, TCHAR_CREATE(c, a));
552*27cf7d04SAleksandr Rybalko }
553*27cf7d04SAleksandr Rybalko 
554*27cf7d04SAleksandr Rybalko static void
555*27cf7d04SAleksandr Rybalko termteken_fill(void *softc, const teken_rect_t *r, teken_char_t c,
556*27cf7d04SAleksandr Rybalko     const teken_attr_t *a)
557*27cf7d04SAleksandr Rybalko {
558*27cf7d04SAleksandr Rybalko 	struct terminal *tm = softc;
559*27cf7d04SAleksandr Rybalko 
560*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_fill(tm, r, TCHAR_CREATE(c, a));
561*27cf7d04SAleksandr Rybalko }
562*27cf7d04SAleksandr Rybalko 
563*27cf7d04SAleksandr Rybalko static void
564*27cf7d04SAleksandr Rybalko termteken_copy(void *softc, const teken_rect_t *r, const teken_pos_t *p)
565*27cf7d04SAleksandr Rybalko {
566*27cf7d04SAleksandr Rybalko 	struct terminal *tm = softc;
567*27cf7d04SAleksandr Rybalko 
568*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_copy(tm, r, p);
569*27cf7d04SAleksandr Rybalko }
570*27cf7d04SAleksandr Rybalko 
571*27cf7d04SAleksandr Rybalko static void
572*27cf7d04SAleksandr Rybalko termteken_param(void *softc, int cmd, unsigned int arg)
573*27cf7d04SAleksandr Rybalko {
574*27cf7d04SAleksandr Rybalko 	struct terminal *tm = softc;
575*27cf7d04SAleksandr Rybalko 
576*27cf7d04SAleksandr Rybalko 	tm->tm_class->tc_param(tm, cmd, arg);
577*27cf7d04SAleksandr Rybalko }
578*27cf7d04SAleksandr Rybalko 
579*27cf7d04SAleksandr Rybalko static void
580*27cf7d04SAleksandr Rybalko termteken_respond(void *softc, const void *buf, size_t len)
581*27cf7d04SAleksandr Rybalko {
582*27cf7d04SAleksandr Rybalko #if 0
583*27cf7d04SAleksandr Rybalko 	struct terminal *tm = softc;
584*27cf7d04SAleksandr Rybalko 	struct tty *tp;
585*27cf7d04SAleksandr Rybalko 
586*27cf7d04SAleksandr Rybalko 	/*
587*27cf7d04SAleksandr Rybalko 	 * Only inject a response into the TTY if the data actually
588*27cf7d04SAleksandr Rybalko 	 * originated from the TTY.
589*27cf7d04SAleksandr Rybalko 	 *
590*27cf7d04SAleksandr Rybalko 	 * XXX: This cannot be done right now.  The TTY could pick up
591*27cf7d04SAleksandr Rybalko 	 * other locks.  It could also in theory cause loops, when the
592*27cf7d04SAleksandr Rybalko 	 * TTY performs echoing of a command that generates even more
593*27cf7d04SAleksandr Rybalko 	 * input.
594*27cf7d04SAleksandr Rybalko 	 */
595*27cf7d04SAleksandr Rybalko 	tp = tm->tm_tty;
596*27cf7d04SAleksandr Rybalko 	if (tp == NULL)
597*27cf7d04SAleksandr Rybalko 		return;
598*27cf7d04SAleksandr Rybalko 
599*27cf7d04SAleksandr Rybalko 	ttydisc_rint_simple(tp, buf, len);
600*27cf7d04SAleksandr Rybalko 	ttydisc_rint_done(tp);
601*27cf7d04SAleksandr Rybalko #endif
602*27cf7d04SAleksandr Rybalko }
603