subr_terminal.c revision 267978
1219888Sed/*-
2219888Sed * Copyright (c) 2009 The FreeBSD Foundation
3219888Sed * All rights reserved.
4219888Sed *
5219888Sed * This software was developed by Ed Schouten under sponsorship from the
6219888Sed * FreeBSD Foundation.
7219888Sed *
8219888Sed * Redistribution and use in source and binary forms, with or without
9219888Sed * modification, are permitted provided that the following conditions
10219888Sed * are met:
11219888Sed * 1. Redistributions of source code must retain the above copyright
12219888Sed *    notice, this list of conditions and the following disclaimer.
13219888Sed * 2. Redistributions in binary form must reproduce the above copyright
14219888Sed *    notice, this list of conditions and the following disclaimer in the
15219888Sed *    documentation and/or other materials provided with the distribution.
16219888Sed *
17219888Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20219888Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27219888Sed * SUCH DAMAGE.
28219888Sed */
29219888Sed
30219888Sed#include <sys/cdefs.h>
31219888Sed__FBSDID("$FreeBSD: head/sys/kern/subr_terminal.c 267978 2014-06-27 19:57:57Z marius $");
32219888Sed
33219888Sed#include <sys/param.h>
34219888Sed#include <sys/cons.h>
35219888Sed#include <sys/consio.h>
36219888Sed#include <sys/kernel.h>
37219888Sed#include <sys/lock.h>
38219888Sed#include <sys/malloc.h>
39219888Sed#include <sys/mutex.h>
40219888Sed#include <sys/systm.h>
41219888Sed#include <sys/terminal.h>
42219888Sed#include <sys/tty.h>
43219888Sed
44219888Sed#include <machine/stdarg.h>
45219888Sed
46219888Sedstatic MALLOC_DEFINE(M_TERMINAL, "terminal", "terminal device");
47219888Sed
48219888Sed/*
49219888Sed * Locking.
50219888Sed *
51219888Sed * Normally we don't need to lock down the terminal emulator, because
52219888Sed * the TTY lock is already held when calling teken_input().
53219888Sed * Unfortunately this is not the case when the terminal acts as a
54219888Sed * console device, because cnputc() can be called at the same time.
55219888Sed * This means terminals may need to be locked down using a spin lock.
56219888Sed */
57219888Sed#define	TERMINAL_LOCK(tm)	do {					\
58219888Sed	if ((tm)->tm_flags & TF_CONS)					\
59219888Sed		mtx_lock_spin(&(tm)->tm_mtx);				\
60219888Sed	else if ((tm)->tm_tty != NULL)					\
61219888Sed		tty_lock((tm)->tm_tty);					\
62219888Sed} while (0)
63219888Sed#define	TERMINAL_UNLOCK(tm)	do {					\
64219888Sed	if ((tm)->tm_flags & TF_CONS)					\
65219888Sed		mtx_unlock_spin(&(tm)->tm_mtx);				\
66219888Sed	else if ((tm)->tm_tty != NULL)					\
67219888Sed		tty_unlock((tm)->tm_tty);				\
68219888Sed} while (0)
69219888Sed#define	TERMINAL_LOCK_TTY(tm)	do {					\
70219888Sed	if ((tm)->tm_flags & TF_CONS)					\
71219888Sed		mtx_lock_spin(&(tm)->tm_mtx);				\
72219888Sed} while (0)
73219888Sed#define	TERMINAL_UNLOCK_TTY(tm)	do {					\
74219888Sed	if ((tm)->tm_flags & TF_CONS)					\
75219888Sed		mtx_unlock_spin(&(tm)->tm_mtx);				\
76219888Sed} while (0)
77219888Sed#define	TERMINAL_LOCK_CONS(tm)		mtx_lock_spin(&(tm)->tm_mtx)
78219888Sed#define	TERMINAL_UNLOCK_CONS(tm)	mtx_unlock_spin(&(tm)->tm_mtx)
79219888Sed
80219888Sed/*
81219888Sed * TTY routines.
82219888Sed */
83219888Sed
84219888Sedstatic tsw_open_t	termtty_open;
85219888Sedstatic tsw_close_t	termtty_close;
86219888Sedstatic tsw_outwakeup_t	termtty_outwakeup;
87219888Sedstatic tsw_ioctl_t	termtty_ioctl;
88259777Sraystatic tsw_mmap_t	termtty_mmap;
89219888Sed
90219888Sedstatic struct ttydevsw terminal_tty_class = {
91219888Sed	.tsw_open	= termtty_open,
92219888Sed	.tsw_close	= termtty_close,
93219888Sed	.tsw_outwakeup	= termtty_outwakeup,
94219888Sed	.tsw_ioctl	= termtty_ioctl,
95259777Sray	.tsw_mmap	= termtty_mmap,
96219888Sed};
97219888Sed
98219888Sed/*
99219888Sed * Terminal emulator routines.
100219888Sed */
101219888Sed
102219888Sedstatic tf_bell_t	termteken_bell;
103219888Sedstatic tf_cursor_t	termteken_cursor;
104219888Sedstatic tf_putchar_t	termteken_putchar;
105219888Sedstatic tf_fill_t	termteken_fill;
106219888Sedstatic tf_copy_t	termteken_copy;
107219888Sedstatic tf_param_t	termteken_param;
108219888Sedstatic tf_respond_t	termteken_respond;
109219888Sed
110219888Sedstatic teken_funcs_t terminal_drawmethods = {
111219888Sed	.tf_bell	= termteken_bell,
112219888Sed	.tf_cursor	= termteken_cursor,
113219888Sed	.tf_putchar	= termteken_putchar,
114219888Sed	.tf_fill	= termteken_fill,
115219888Sed	.tf_copy	= termteken_copy,
116219888Sed	.tf_param	= termteken_param,
117219888Sed	.tf_respond	= termteken_respond,
118219888Sed};
119219888Sed
120219888Sed/* Kernel message formatting. */
121219888Sedstatic const teken_attr_t kernel_message = {
122267978Smarius	.ta_fgcolor	= TCHAR_FGCOLOR(TERMINAL_KERN_ATTR),
123267978Smarius	.ta_bgcolor	= TCHAR_BGCOLOR(TERMINAL_KERN_ATTR),
124267978Smarius	.ta_format	= TCHAR_FORMAT(TERMINAL_KERN_ATTR)
125219888Sed};
126219888Sed
127219888Sedstatic const teken_attr_t default_message = {
128267978Smarius	.ta_fgcolor	= TCHAR_FGCOLOR(TERMINAL_NORM_ATTR),
129267978Smarius	.ta_bgcolor	= TCHAR_BGCOLOR(TERMINAL_NORM_ATTR),
130267978Smarius	.ta_format	= TCHAR_FORMAT(TERMINAL_NORM_ATTR)
131219888Sed};
132219888Sed
133267978Smarius#define	TCHAR_CREATE(c, a)	((c) | TFORMAT((a)->ta_format) |	\
134267978Smarius	TCOLOR_FG(teken_256to8((a)->ta_fgcolor)) |			\
135267978Smarius	TCOLOR_BG(teken_256to8((a)->ta_bgcolor)))
136219888Sed
137219888Sedstatic void
138219888Sedterminal_init(struct terminal *tm)
139219888Sed{
140219888Sed
141219888Sed	if (tm->tm_flags & TF_CONS)
142219888Sed		mtx_init(&tm->tm_mtx, "trmlck", NULL, MTX_SPIN);
143219888Sed	teken_init(&tm->tm_emulator, &terminal_drawmethods, tm);
144219888Sed	teken_set_defattr(&tm->tm_emulator, &default_message);
145219888Sed}
146219888Sed
147219888Sedstruct terminal *
148219888Sedterminal_alloc(const struct terminal_class *tc, void *softc)
149219888Sed{
150219888Sed	struct terminal *tm;
151219888Sed
152219888Sed	tm = malloc(sizeof(struct terminal), M_TERMINAL, M_WAITOK|M_ZERO);
153219888Sed	terminal_init(tm);
154219888Sed
155219888Sed	tm->tm_class = tc;
156219888Sed	tm->tm_softc = softc;
157219888Sed
158219888Sed	return (tm);
159219888Sed}
160219888Sed
161219888Sedstatic void
162219888Sedterminal_sync_ttysize(struct terminal *tm)
163219888Sed{
164219888Sed	struct tty *tp;
165219888Sed
166219888Sed	tp = tm->tm_tty;
167219888Sed	if (tp == NULL)
168219888Sed		return;
169219888Sed
170219888Sed	tty_lock(tp);
171219888Sed	tty_set_winsize(tp, &tm->tm_winsize);
172219888Sed	tty_unlock(tp);
173219888Sed}
174219888Sed
175219888Sedvoid
176219888Sedterminal_maketty(struct terminal *tm, const char *fmt, ...)
177219888Sed{
178219888Sed	struct tty *tp;
179219888Sed	char name[8];
180219888Sed	va_list ap;
181219888Sed
182219888Sed	va_start(ap, fmt);
183219888Sed	vsnrprintf(name, sizeof name, 32, fmt, ap);
184219888Sed	va_end(ap);
185219888Sed
186219888Sed	tp = tty_alloc(&terminal_tty_class, tm);
187243802Snwhitehorn	tty_makedev(tp, NULL, "%s", name);
188219888Sed	tm->tm_tty = tp;
189219888Sed	terminal_sync_ttysize(tm);
190219888Sed}
191219888Sed
192219888Sedvoid
193256897Srayterminal_set_winsize_blank(struct terminal *tm, const struct winsize *size,
194267978Smarius    int blank, const term_attr_t *attr)
195219888Sed{
196219888Sed	term_rect_t r;
197219888Sed
198219888Sed	tm->tm_winsize = *size;
199219888Sed
200219888Sed	r.tr_begin.tp_row = r.tr_begin.tp_col = 0;
201219888Sed	r.tr_end.tp_row = size->ws_row;
202219888Sed	r.tr_end.tp_col = size->ws_col;
203219888Sed
204219888Sed	TERMINAL_LOCK(tm);
205257252Sray	if (blank == 0)
206257431Sray		teken_set_winsize_noreset(&tm->tm_emulator, &r.tr_end);
207257252Sray	else
208257252Sray		teken_set_winsize(&tm->tm_emulator, &r.tr_end);
209219888Sed	TERMINAL_UNLOCK(tm);
210219888Sed
211264242Sray	if ((blank != 0) && !(tm->tm_flags & TF_MUTE))
212267978Smarius		tm->tm_class->tc_fill(tm, &r,
213267978Smarius		    TCHAR_CREATE((teken_char_t)' ', attr));
214256897Sray
215219888Sed	terminal_sync_ttysize(tm);
216219888Sed}
217219888Sed
218256897Srayvoid
219256897Srayterminal_set_winsize(struct terminal *tm, const struct winsize *size)
220256897Sray{
221256897Sray
222267978Smarius	terminal_set_winsize_blank(tm, size, 1,
223267978Smarius	    (const term_attr_t *)&default_message);
224256897Sray}
225256897Sray
226219888Sed/*
227219888Sed * XXX: This function is a kludge.  Drivers like vt(4) need to
228219888Sed * temporarily stop input when resizing, etc.  This should ideally be
229219888Sed * handled within the driver.
230219888Sed */
231219888Sed
232219888Sedvoid
233219888Sedterminal_mute(struct terminal *tm, int yes)
234219888Sed{
235219888Sed
236219888Sed	TERMINAL_LOCK(tm);
237219888Sed	if (yes)
238219888Sed		tm->tm_flags |= TF_MUTE;
239219888Sed	else
240219888Sed		tm->tm_flags &= ~TF_MUTE;
241219888Sed	TERMINAL_UNLOCK(tm);
242219888Sed}
243219888Sed
244219888Sedvoid
245219888Sedterminal_input_char(struct terminal *tm, term_char_t c)
246219888Sed{
247219888Sed	struct tty *tp;
248219888Sed
249219888Sed	tp = tm->tm_tty;
250219888Sed	if (tp == NULL)
251219888Sed		return;
252219888Sed
253259830Sed	/*
254259830Sed	 * Strip off any attributes. Also ignore input of second part of
255259830Sed	 * CJK fullwidth characters, as we don't want to return these
256259830Sed	 * characters twice.
257259830Sed	 */
258259830Sed	if (TCHAR_FORMAT(c) & TF_CJK_RIGHT)
259259830Sed		return;
260219888Sed	c = TCHAR_CHARACTER(c);
261219888Sed
262219888Sed	tty_lock(tp);
263219888Sed	/*
264219888Sed	 * Conversion to UTF-8.
265219888Sed	 */
266219888Sed	if (c < 0x80) {
267219888Sed		ttydisc_rint(tp, c, 0);
268219888Sed	} else if (c < 0x800) {
269219888Sed		char str[2] = {
270219888Sed			0xc0 | (c >> 6),
271219888Sed			0x80 | (c & 0x3f)
272219888Sed		};
273219888Sed
274219888Sed		ttydisc_rint_simple(tp, str, sizeof str);
275219888Sed	} else if (c < 0x10000) {
276219888Sed		char str[3] = {
277219888Sed			0xe0 | (c >> 12),
278219888Sed			0x80 | ((c >> 6) & 0x3f),
279219888Sed			0x80 | (c & 0x3f)
280219888Sed		};
281219888Sed
282219888Sed		ttydisc_rint_simple(tp, str, sizeof str);
283219888Sed	} else {
284219888Sed		char str[4] = {
285219888Sed			0xf0 | (c >> 18),
286219888Sed			0x80 | ((c >> 12) & 0x3f),
287219888Sed			0x80 | ((c >> 6) & 0x3f),
288219888Sed			0x80 | (c & 0x3f)
289219888Sed		};
290219888Sed
291219888Sed		ttydisc_rint_simple(tp, str, sizeof str);
292219888Sed	}
293219888Sed	ttydisc_rint_done(tp);
294219888Sed	tty_unlock(tp);
295219888Sed}
296219888Sed
297219888Sedvoid
298219888Sedterminal_input_raw(struct terminal *tm, char c)
299219888Sed{
300219888Sed	struct tty *tp;
301219888Sed
302219888Sed	tp = tm->tm_tty;
303219888Sed	if (tp == NULL)
304219888Sed		return;
305219888Sed
306219888Sed	tty_lock(tp);
307219888Sed	ttydisc_rint(tp, c, 0);
308219888Sed	ttydisc_rint_done(tp);
309219888Sed	tty_unlock(tp);
310219888Sed}
311219888Sed
312219888Sedvoid
313219888Sedterminal_input_special(struct terminal *tm, unsigned int k)
314219888Sed{
315219888Sed	struct tty *tp;
316219888Sed	const char *str;
317219888Sed
318219888Sed	tp = tm->tm_tty;
319219888Sed	if (tp == NULL)
320219888Sed		return;
321219888Sed
322219888Sed	str = teken_get_sequence(&tm->tm_emulator, k);
323219888Sed	if (str == NULL)
324219888Sed		return;
325219888Sed
326219888Sed	tty_lock(tp);
327219888Sed	ttydisc_rint_simple(tp, str, strlen(str));
328219888Sed	ttydisc_rint_done(tp);
329219888Sed	tty_unlock(tp);
330219888Sed}
331219888Sed
332219888Sed/*
333219888Sed * Binding with the TTY layer.
334219888Sed */
335219888Sed
336219888Sedstatic int
337219888Sedtermtty_open(struct tty *tp)
338219888Sed{
339219888Sed	struct terminal *tm = tty_softc(tp);
340219888Sed
341219888Sed	tm->tm_class->tc_opened(tm, 1);
342219888Sed	return (0);
343219888Sed}
344219888Sed
345219888Sedstatic void
346219888Sedtermtty_close(struct tty *tp)
347219888Sed{
348219888Sed	struct terminal *tm = tty_softc(tp);
349219888Sed
350219888Sed	tm->tm_class->tc_opened(tm, 0);
351219888Sed}
352219888Sed
353219888Sedstatic void
354219888Sedtermtty_outwakeup(struct tty *tp)
355219888Sed{
356219888Sed	struct terminal *tm = tty_softc(tp);
357219888Sed	char obuf[128];
358219888Sed	size_t olen;
359219888Sed	unsigned int flags = 0;
360219888Sed
361219888Sed	while ((olen = ttydisc_getc(tp, obuf, sizeof obuf)) > 0) {
362219888Sed		TERMINAL_LOCK_TTY(tm);
363219888Sed		if (!(tm->tm_flags & TF_MUTE)) {
364219888Sed			tm->tm_flags &= ~TF_BELL;
365219888Sed			teken_input(&tm->tm_emulator, obuf, olen);
366219888Sed			flags |= tm->tm_flags;
367219888Sed		}
368219888Sed		TERMINAL_UNLOCK_TTY(tm);
369219888Sed	}
370219888Sed
371219888Sed	tm->tm_class->tc_done(tm);
372219888Sed	if (flags & TF_BELL)
373219888Sed		tm->tm_class->tc_bell(tm);
374219888Sed}
375219888Sed
376219888Sedstatic int
377219888Sedtermtty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
378219888Sed{
379219888Sed	struct terminal *tm = tty_softc(tp);
380219888Sed	int error;
381219888Sed
382219888Sed	switch (cmd) {
383219888Sed	case CONS_GETINFO: {
384219888Sed		vid_info_t *vi = (vid_info_t *)data;
385219888Sed		const teken_pos_t *p;
386219888Sed		int fg, bg;
387219888Sed
388219888Sed		if (vi->size != sizeof(vid_info_t))
389219888Sed			return (EINVAL);
390219888Sed
391219888Sed		/* Already help the console driver by filling in some data. */
392219888Sed		p = teken_get_cursor(&tm->tm_emulator);
393219888Sed		vi->mv_row = p->tp_row;
394219888Sed		vi->mv_col = p->tp_col;
395219888Sed
396219888Sed		p = teken_get_winsize(&tm->tm_emulator);
397219888Sed		vi->mv_rsz = p->tp_row;
398219888Sed		vi->mv_csz = p->tp_col;
399219888Sed
400219888Sed		teken_get_defattr_cons25(&tm->tm_emulator, &fg, &bg);
401219888Sed		vi->mv_norm.fore = fg;
402219888Sed		vi->mv_norm.back = bg;
403219888Sed		/* XXX: keep vidcontrol happy; bold backgrounds. */
404219888Sed		vi->mv_rev.fore = bg;
405219888Sed		vi->mv_rev.back = fg & 0x7;
406219888Sed		break;
407219888Sed	}
408219888Sed	}
409219888Sed
410219888Sed	/*
411219888Sed	 * Unlike various other drivers, this driver will never
412219888Sed	 * deallocate TTYs.  This means it's safe to temporarily unlock
413219888Sed	 * the TTY when handling ioctls.
414219888Sed	 */
415219888Sed	tty_unlock(tp);
416219888Sed	error = tm->tm_class->tc_ioctl(tm, cmd, data, td);
417219888Sed	tty_lock(tp);
418219888Sed	return (error);
419219888Sed}
420219888Sed
421259777Sraystatic int
422259777Sraytermtty_mmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t * paddr,
423259777Sray    int nprot, vm_memattr_t *memattr)
424259777Sray{
425259777Sray	struct terminal *tm = tty_softc(tp);
426259777Sray
427259777Sray	return (tm->tm_class->tc_mmap(tm, offset, paddr, nprot, memattr));
428259777Sray}
429259777Sray
430219888Sed/*
431219888Sed * Binding with the kernel and debug console.
432219888Sed */
433219888Sed
434256143Sraystatic cn_probe_t	termcn_cnprobe;
435256143Sraystatic cn_init_t	termcn_cninit;
436256143Sraystatic cn_term_t	termcn_cnterm;
437256143Sraystatic cn_getc_t	termcn_cngetc;
438256143Sraystatic cn_putc_t	termcn_cnputc;
439256143Sraystatic cn_grab_t	termcn_cngrab;
440256143Sraystatic cn_ungrab_t	termcn_cnungrab;
441219888Sed
442256143Srayconst struct consdev_ops termcn_cnops = {
443256143Sray	.cn_probe	= termcn_cnprobe,
444256143Sray	.cn_init	= termcn_cninit,
445256143Sray	.cn_term	= termcn_cnterm,
446256143Sray	.cn_getc	= termcn_cngetc,
447256143Sray	.cn_putc	= termcn_cnputc,
448256143Sray	.cn_grab	= termcn_cngrab,
449256143Sray	.cn_ungrab	= termcn_cnungrab,
450219888Sed};
451219888Sed
452256143Srayvoid
453256143Sraytermcn_cnregister(struct terminal *tm)
454256143Sray{
455256143Sray	struct consdev *cp;
456256143Sray
457256143Sray	cp = tm->consdev;
458256143Sray	if (cp == NULL) {
459256143Sray		cp = malloc(sizeof(struct consdev), M_TERMINAL,
460256143Sray		    M_WAITOK|M_ZERO);
461256143Sray		cp->cn_ops = &termcn_cnops;
462256143Sray		cp->cn_arg = tm;
463256143Sray		cp->cn_pri = CN_INTERNAL;
464256143Sray		sprintf(cp->cn_name, "ttyv0");
465256143Sray
466256143Sray		tm->tm_flags = TF_CONS;
467256143Sray		tm->consdev = cp;
468256143Sray
469256143Sray		terminal_init(tm);
470256143Sray	}
471256143Sray
472256143Sray	/* Attach terminal as console. */
473256143Sray	cnadd(cp);
474256143Sray}
475256143Sray
476219888Sedstatic void
477256143Sraytermcn_cngrab(struct consdev *cp)
478219888Sed{
479256143Sray
480256143Sray}
481256143Sray
482256143Sraystatic void
483256143Sraytermcn_cnungrab(struct consdev *cp)
484256143Sray{
485256143Sray
486256143Sray}
487256143Sray
488256143Sraystatic void
489256143Sraytermcn_cnprobe(struct consdev *cp)
490256143Sray{
491219888Sed	struct terminal *tm = cp->cn_arg;
492219888Sed
493256143Sray	if (tm == NULL) {
494256143Sray		cp->cn_pri = CN_DEAD;
495256143Sray		return;
496256143Sray	}
497256143Sray
498256143Sray	tm->consdev = cp;
499219888Sed	terminal_init(tm);
500219888Sed
501219888Sed	tm->tm_class->tc_cnprobe(tm, cp);
502219888Sed}
503219888Sed
504219888Sedstatic void
505256143Sraytermcn_cninit(struct consdev *cp)
506219888Sed{
507256143Sray
508219888Sed}
509219888Sed
510219888Sedstatic void
511256143Sraytermcn_cnterm(struct consdev *cp)
512219888Sed{
513256143Sray
514219888Sed}
515219888Sed
516219888Sedstatic int
517256143Sraytermcn_cngetc(struct consdev *cp)
518219888Sed{
519219888Sed	struct terminal *tm = cp->cn_arg;
520219888Sed
521219888Sed	return (tm->tm_class->tc_cngetc(tm));
522219888Sed}
523219888Sed
524219888Sedstatic void
525256143Sraytermcn_cnputc(struct consdev *cp, int c)
526219888Sed{
527219888Sed	struct terminal *tm = cp->cn_arg;
528219888Sed	teken_attr_t backup;
529219888Sed	char cv = c;
530219888Sed
531219888Sed	TERMINAL_LOCK_CONS(tm);
532219888Sed	if (!(tm->tm_flags & TF_MUTE)) {
533219888Sed		backup = *teken_get_curattr(&tm->tm_emulator);
534219888Sed		teken_set_curattr(&tm->tm_emulator, &kernel_message);
535219888Sed		teken_input(&tm->tm_emulator, &cv, 1);
536219888Sed		teken_set_curattr(&tm->tm_emulator, &backup);
537219888Sed	}
538219888Sed	TERMINAL_UNLOCK_CONS(tm);
539219888Sed
540219888Sed	tm->tm_class->tc_done(tm);
541219888Sed}
542219888Sed
543219888Sed/*
544219888Sed * Binding with the terminal emulator.
545219888Sed */
546219888Sed
547219888Sedstatic void
548219888Sedtermteken_bell(void *softc)
549219888Sed{
550219888Sed	struct terminal *tm = softc;
551219888Sed
552219888Sed	tm->tm_flags |= TF_BELL;
553219888Sed}
554219888Sed
555219888Sedstatic void
556219888Sedtermteken_cursor(void *softc, const teken_pos_t *p)
557219888Sed{
558219888Sed	struct terminal *tm = softc;
559219888Sed
560219888Sed	tm->tm_class->tc_cursor(tm, p);
561219888Sed}
562219888Sed
563219888Sedstatic void
564219888Sedtermteken_putchar(void *softc, const teken_pos_t *p, teken_char_t c,
565219888Sed    const teken_attr_t *a)
566219888Sed{
567219888Sed	struct terminal *tm = softc;
568219888Sed
569219888Sed	tm->tm_class->tc_putchar(tm, p, TCHAR_CREATE(c, a));
570219888Sed}
571219888Sed
572219888Sedstatic void
573219888Sedtermteken_fill(void *softc, const teken_rect_t *r, teken_char_t c,
574219888Sed    const teken_attr_t *a)
575219888Sed{
576219888Sed	struct terminal *tm = softc;
577219888Sed
578219888Sed	tm->tm_class->tc_fill(tm, r, TCHAR_CREATE(c, a));
579219888Sed}
580219888Sed
581219888Sedstatic void
582219888Sedtermteken_copy(void *softc, const teken_rect_t *r, const teken_pos_t *p)
583219888Sed{
584219888Sed	struct terminal *tm = softc;
585219888Sed
586219888Sed	tm->tm_class->tc_copy(tm, r, p);
587219888Sed}
588219888Sed
589219888Sedstatic void
590219888Sedtermteken_param(void *softc, int cmd, unsigned int arg)
591219888Sed{
592219888Sed	struct terminal *tm = softc;
593219888Sed
594219888Sed	tm->tm_class->tc_param(tm, cmd, arg);
595219888Sed}
596219888Sed
597219888Sedstatic void
598219888Sedtermteken_respond(void *softc, const void *buf, size_t len)
599219888Sed{
600219888Sed#if 0
601219888Sed	struct terminal *tm = softc;
602219888Sed	struct tty *tp;
603219888Sed
604219888Sed	/*
605219888Sed	 * Only inject a response into the TTY if the data actually
606219888Sed	 * originated from the TTY.
607219888Sed	 *
608219888Sed	 * XXX: This cannot be done right now.  The TTY could pick up
609219888Sed	 * other locks.  It could also in theory cause loops, when the
610219888Sed	 * TTY performs echoing of a command that generates even more
611219888Sed	 * input.
612219888Sed	 */
613219888Sed	tp = tm->tm_tty;
614219888Sed	if (tp == NULL)
615219888Sed		return;
616219888Sed
617219888Sed	ttydisc_rint_simple(tp, buf, len);
618219888Sed	ttydisc_rint_done(tp);
619219888Sed#endif
620219888Sed}
621