subr_terminal.c revision 263817
1319780Sdim/*-
2319780Sdim * Copyright (c) 2009 The FreeBSD Foundation
3319780Sdim * All rights reserved.
4319780Sdim *
5319780Sdim * This software was developed by Ed Schouten under sponsorship from the
6319780Sdim * FreeBSD Foundation.
7319780Sdim *
8319780Sdim * Redistribution and use in source and binary forms, with or without
9319780Sdim * modification, are permitted provided that the following conditions
10319780Sdim * are met:
11319780Sdim * 1. Redistributions of source code must retain the above copyright
12319780Sdim *    notice, this list of conditions and the following disclaimer.
13319780Sdim * 2. Redistributions in binary form must reproduce the above copyright
14319780Sdim *    notice, this list of conditions and the following disclaimer in the
15319780Sdim *    documentation and/or other materials provided with the distribution.
16319780Sdim *
17320397Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18319780Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19320397Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20319780Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21319780Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22319780Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23319780Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24319780Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25319780Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26319780Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27319780Sdim * SUCH DAMAGE.
28319780Sdim */
29319780Sdim
30319780Sdim#include <sys/cdefs.h>
31319780Sdim__FBSDID("$FreeBSD: stable/9/sys/kern/subr_terminal.c 263817 2014-03-27 15:58:18Z ray $");
32319780Sdim
33319780Sdim#include <sys/param.h>
34319780Sdim#include <sys/cons.h>
35319780Sdim#include <sys/consio.h>
36319780Sdim#include <sys/kernel.h>
37319780Sdim#include <sys/lock.h>
38319780Sdim#include <sys/malloc.h>
39320041Sdim#include <sys/mutex.h>
40319780Sdim#include <sys/systm.h>
41319780Sdim#include <sys/terminal.h>
42319780Sdim#include <sys/tty.h>
43319780Sdim
44319780Sdim#include <machine/stdarg.h>
45319780Sdim
46319780Sdimstatic MALLOC_DEFINE(M_TERMINAL, "terminal", "terminal device");
47319780Sdim
48319780Sdim/*
49319780Sdim * Locking.
50319780Sdim *
51319780Sdim * Normally we don't need to lock down the terminal emulator, because
52319780Sdim * the TTY lock is already held when calling teken_input().
53319780Sdim * Unfortunately this is not the case when the terminal acts as a
54319780Sdim * console device, because cnputc() can be called at the same time.
55319780Sdim * This means terminals may need to be locked down using a spin lock.
56319780Sdim */
57319780Sdim#define	TERMINAL_LOCK(tm)	do {					\
58319780Sdim	if ((tm)->tm_flags & TF_CONS)					\
59319780Sdim		mtx_lock_spin(&(tm)->tm_mtx);				\
60319780Sdim	else if ((tm)->tm_tty != NULL)					\
61319780Sdim		tty_lock((tm)->tm_tty);					\
62319780Sdim} while (0)
63319780Sdim#define	TERMINAL_UNLOCK(tm)	do {					\
64319780Sdim	if ((tm)->tm_flags & TF_CONS)					\
65319780Sdim		mtx_unlock_spin(&(tm)->tm_mtx);				\
66319780Sdim	else if ((tm)->tm_tty != NULL)					\
67319780Sdim		tty_unlock((tm)->tm_tty);				\
68319780Sdim} while (0)
69319780Sdim#define	TERMINAL_LOCK_TTY(tm)	do {					\
70319780Sdim	if ((tm)->tm_flags & TF_CONS)					\
71319780Sdim		mtx_lock_spin(&(tm)->tm_mtx);				\
72319780Sdim} while (0)
73319780Sdim#define	TERMINAL_UNLOCK_TTY(tm)	do {					\
74319780Sdim	if ((tm)->tm_flags & TF_CONS)					\
75319780Sdim		mtx_unlock_spin(&(tm)->tm_mtx);				\
76319780Sdim} while (0)
77319780Sdim#define	TERMINAL_LOCK_CONS(tm)		mtx_lock_spin(&(tm)->tm_mtx)
78319780Sdim#define	TERMINAL_UNLOCK_CONS(tm)	mtx_unlock_spin(&(tm)->tm_mtx)
79319780Sdim
80319780Sdim/*
81319780Sdim * TTY routines.
82319780Sdim */
83319780Sdim
84319780Sdimstatic tsw_open_t	termtty_open;
85319780Sdimstatic tsw_close_t	termtty_close;
86319780Sdimstatic tsw_outwakeup_t	termtty_outwakeup;
87319780Sdimstatic tsw_ioctl_t	termtty_ioctl;
88319780Sdimstatic tsw_mmap_t	termtty_mmap;
89319780Sdim
90320397Sdimstatic struct ttydevsw terminal_tty_class = {
91320397Sdim	.tsw_open	= termtty_open,
92320397Sdim	.tsw_close	= termtty_close,
93319780Sdim	.tsw_outwakeup	= termtty_outwakeup,
94319780Sdim	.tsw_ioctl	= termtty_ioctl,
95319780Sdim	.tsw_mmap	= termtty_mmap,
96319780Sdim};
97319780Sdim
98319780Sdim/*
99319780Sdim * Terminal emulator routines.
100319780Sdim */
101319780Sdim
102319780Sdimstatic tf_bell_t	termteken_bell;
103319780Sdimstatic tf_cursor_t	termteken_cursor;
104319780Sdimstatic tf_putchar_t	termteken_putchar;
105319780Sdimstatic tf_fill_t	termteken_fill;
106319780Sdimstatic tf_copy_t	termteken_copy;
107319780Sdimstatic tf_param_t	termteken_param;
108319780Sdimstatic tf_respond_t	termteken_respond;
109319780Sdim
110319780Sdimstatic teken_funcs_t terminal_drawmethods = {
111319780Sdim	.tf_bell	= termteken_bell,
112319780Sdim	.tf_cursor	= termteken_cursor,
113319780Sdim	.tf_putchar	= termteken_putchar,
114319780Sdim	.tf_fill	= termteken_fill,
115319780Sdim	.tf_copy	= termteken_copy,
116319780Sdim	.tf_param	= termteken_param,
117320397Sdim	.tf_respond	= termteken_respond,
118320397Sdim};
119320397Sdim
120320397Sdim/* Kernel message formatting. */
121320397Sdimstatic const teken_attr_t kernel_message = {
122320397Sdim	.ta_fgcolor	= TC_WHITE,
123320397Sdim	.ta_bgcolor	= TC_BLACK,
124320397Sdim	.ta_format	= TF_BOLD,
125320397Sdim};
126320397Sdim
127320397Sdimstatic const teken_attr_t default_message = {
128320397Sdim	.ta_fgcolor	= TC_WHITE,
129320397Sdim	.ta_bgcolor	= TC_BLACK,
130320397Sdim};
131320397Sdim
132320397Sdim#define	TCHAR_CREATE(c, a)	((c) | \
133320397Sdim	(a)->ta_format << 21 | \
134320397Sdim	teken_256to8((a)->ta_fgcolor) << 26 | \
135320397Sdim	teken_256to8((a)->ta_bgcolor) << 29)
136320397Sdim
137320397Sdimstatic void
138320397Sdimterminal_init(struct terminal *tm)
139320397Sdim{
140320397Sdim
141320397Sdim	if (tm->tm_flags & TF_CONS)
142319780Sdim		mtx_init(&tm->tm_mtx, "trmlck", NULL, MTX_SPIN);
143319780Sdim	teken_init(&tm->tm_emulator, &terminal_drawmethods, tm);
144319780Sdim	teken_set_defattr(&tm->tm_emulator, &default_message);
145319780Sdim}
146319780Sdim
147319780Sdimstruct terminal *
148319780Sdimterminal_alloc(const struct terminal_class *tc, void *softc)
149319780Sdim{
150319780Sdim	struct terminal *tm;
151319780Sdim
152319780Sdim	tm = malloc(sizeof(struct terminal), M_TERMINAL, M_WAITOK|M_ZERO);
153319780Sdim	terminal_init(tm);
154319780Sdim
155319780Sdim	tm->tm_class = tc;
156319780Sdim	tm->tm_softc = softc;
157319780Sdim
158319780Sdim	return (tm);
159319780Sdim}
160319780Sdim
161319780Sdimstatic void
162319780Sdimterminal_sync_ttysize(struct terminal *tm)
163319780Sdim{
164319780Sdim	struct tty *tp;
165319780Sdim
166319780Sdim	tp = tm->tm_tty;
167319780Sdim	if (tp == NULL)
168319780Sdim		return;
169319780Sdim
170319780Sdim	tty_lock(tp);
171319780Sdim	tty_set_winsize(tp, &tm->tm_winsize);
172319780Sdim	tty_unlock(tp);
173319780Sdim}
174319780Sdim
175319780Sdimvoid
176319780Sdimterminal_maketty(struct terminal *tm, const char *fmt, ...)
177319780Sdim{
178319780Sdim	struct tty *tp;
179319780Sdim	char name[8];
180319780Sdim	va_list ap;
181319780Sdim
182319780Sdim	va_start(ap, fmt);
183319780Sdim	vsnrprintf(name, sizeof name, 32, fmt, ap);
184319780Sdim	va_end(ap);
185319780Sdim
186319780Sdim	tp = tty_alloc(&terminal_tty_class, tm);
187319780Sdim	tty_makedev(tp, NULL, "%s", name);
188319780Sdim	tm->tm_tty = tp;
189319780Sdim	terminal_sync_ttysize(tm);
190319780Sdim}
191319780Sdim
192319780Sdimvoid
193319780Sdimterminal_set_winsize_blank(struct terminal *tm, const struct winsize *size,
194319780Sdim    int blank)
195319780Sdim{
196319780Sdim	term_rect_t r;
197319780Sdim
198319780Sdim	tm->tm_winsize = *size;
199319780Sdim
200319780Sdim	r.tr_begin.tp_row = r.tr_begin.tp_col = 0;
201319780Sdim	r.tr_end.tp_row = size->ws_row;
202319780Sdim	r.tr_end.tp_col = size->ws_col;
203319780Sdim
204319780Sdim	TERMINAL_LOCK(tm);
205319780Sdim	if (blank == 0)
206319780Sdim		teken_set_winsize_noreset(&tm->tm_emulator, &r.tr_end);
207319780Sdim	else
208319780Sdim		teken_set_winsize(&tm->tm_emulator, &r.tr_end);
209319780Sdim	TERMINAL_UNLOCK(tm);
210319780Sdim
211319780Sdim	if (blank != 0)
212319780Sdim		tm->tm_class->tc_fill(tm, &r, TCHAR_CREATE((teken_char_t)' ',
213319780Sdim		    &default_message));
214319780Sdim
215319780Sdim	terminal_sync_ttysize(tm);
216319780Sdim}
217319780Sdim
218319780Sdimvoid
219319780Sdimterminal_set_winsize(struct terminal *tm, const struct winsize *size)
220319780Sdim{
221319780Sdim
222319780Sdim	terminal_set_winsize_blank(tm, size, 1);
223319780Sdim}
224319780Sdim
225319780Sdim/*
226319780Sdim * XXX: This function is a kludge.  Drivers like vt(4) need to
227319780Sdim * temporarily stop input when resizing, etc.  This should ideally be
228319780Sdim * handled within the driver.
229319780Sdim */
230319780Sdim
231319780Sdimvoid
232319780Sdimterminal_mute(struct terminal *tm, int yes)
233319780Sdim{
234319780Sdim
235319780Sdim	TERMINAL_LOCK(tm);
236319780Sdim	if (yes)
237319780Sdim		tm->tm_flags |= TF_MUTE;
238319780Sdim	else
239319780Sdim		tm->tm_flags &= ~TF_MUTE;
240319780Sdim	TERMINAL_UNLOCK(tm);
241319780Sdim}
242319780Sdim
243319780Sdimvoid
244319780Sdimterminal_input_char(struct terminal *tm, term_char_t c)
245319780Sdim{
246319780Sdim	struct tty *tp;
247319780Sdim
248319780Sdim	tp = tm->tm_tty;
249319780Sdim	if (tp == NULL)
250319780Sdim		return;
251319780Sdim
252319780Sdim	/*
253319780Sdim	 * Strip off any attributes. Also ignore input of second part of
254319780Sdim	 * CJK fullwidth characters, as we don't want to return these
255319780Sdim	 * characters twice.
256319780Sdim	 */
257319780Sdim	if (TCHAR_FORMAT(c) & TF_CJK_RIGHT)
258319780Sdim		return;
259319780Sdim	c = TCHAR_CHARACTER(c);
260319780Sdim
261319780Sdim	tty_lock(tp);
262319780Sdim	/*
263319780Sdim	 * Conversion to UTF-8.
264319780Sdim	 */
265319780Sdim	if (c < 0x80) {
266319780Sdim		ttydisc_rint(tp, c, 0);
267319780Sdim	} else if (c < 0x800) {
268319780Sdim		char str[2] = {
269319780Sdim			0xc0 | (c >> 6),
270319780Sdim			0x80 | (c & 0x3f)
271319780Sdim		};
272319780Sdim
273319780Sdim		ttydisc_rint_simple(tp, str, sizeof str);
274319780Sdim	} else if (c < 0x10000) {
275319780Sdim		char str[3] = {
276319780Sdim			0xe0 | (c >> 12),
277319780Sdim			0x80 | ((c >> 6) & 0x3f),
278319780Sdim			0x80 | (c & 0x3f)
279319780Sdim		};
280319780Sdim
281319780Sdim		ttydisc_rint_simple(tp, str, sizeof str);
282319780Sdim	} else {
283319780Sdim		char str[4] = {
284319780Sdim			0xf0 | (c >> 18),
285319780Sdim			0x80 | ((c >> 12) & 0x3f),
286319780Sdim			0x80 | ((c >> 6) & 0x3f),
287320970Sdim			0x80 | (c & 0x3f)
288320970Sdim		};
289320970Sdim
290320970Sdim		ttydisc_rint_simple(tp, str, sizeof str);
291320970Sdim	}
292320970Sdim	ttydisc_rint_done(tp);
293320970Sdim	tty_unlock(tp);
294320970Sdim}
295320970Sdim
296320970Sdimvoid
297320970Sdimterminal_input_raw(struct terminal *tm, char c)
298320970Sdim{
299320970Sdim	struct tty *tp;
300320970Sdim
301320970Sdim	tp = tm->tm_tty;
302320970Sdim	if (tp == NULL)
303320970Sdim		return;
304320970Sdim
305320970Sdim	tty_lock(tp);
306320970Sdim	ttydisc_rint(tp, c, 0);
307320970Sdim	ttydisc_rint_done(tp);
308320970Sdim	tty_unlock(tp);
309320970Sdim}
310320970Sdim
311320970Sdimvoid
312320970Sdimterminal_input_special(struct terminal *tm, unsigned int k)
313319780Sdim{
314319780Sdim	struct tty *tp;
315320041Sdim	const char *str;
316320041Sdim
317320397Sdim	tp = tm->tm_tty;
318320397Sdim	if (tp == NULL)
319320397Sdim		return;
320320397Sdim
321320397Sdim	str = teken_get_sequence(&tm->tm_emulator, k);
322320397Sdim	if (str == NULL)
323319780Sdim		return;
324320397Sdim
325320397Sdim	tty_lock(tp);
326320397Sdim	ttydisc_rint_simple(tp, str, strlen(str));
327320397Sdim	ttydisc_rint_done(tp);
328320397Sdim	tty_unlock(tp);
329320397Sdim}
330320397Sdim
331320397Sdim/*
332320397Sdim * Binding with the TTY layer.
333320397Sdim */
334320397Sdim
335320397Sdimstatic int
336320397Sdimtermtty_open(struct tty *tp)
337320397Sdim{
338320397Sdim	struct terminal *tm = tty_softc(tp);
339320397Sdim
340320397Sdim	tm->tm_class->tc_opened(tm, 1);
341320397Sdim	return (0);
342320397Sdim}
343320397Sdim
344320397Sdimstatic void
345320397Sdimtermtty_close(struct tty *tp)
346320397Sdim{
347320397Sdim	struct terminal *tm = tty_softc(tp);
348320397Sdim
349320397Sdim	tm->tm_class->tc_opened(tm, 0);
350320397Sdim}
351320397Sdim
352320397Sdimstatic void
353320397Sdimtermtty_outwakeup(struct tty *tp)
354320397Sdim{
355320397Sdim	struct terminal *tm = tty_softc(tp);
356320397Sdim	char obuf[128];
357320397Sdim	size_t olen;
358320397Sdim	unsigned int flags = 0;
359320397Sdim
360320397Sdim	while ((olen = ttydisc_getc(tp, obuf, sizeof obuf)) > 0) {
361320397Sdim		TERMINAL_LOCK_TTY(tm);
362320397Sdim		if (!(tm->tm_flags & TF_MUTE)) {
363320397Sdim			tm->tm_flags &= ~TF_BELL;
364320397Sdim			teken_input(&tm->tm_emulator, obuf, olen);
365320397Sdim			flags |= tm->tm_flags;
366320397Sdim		}
367320397Sdim		TERMINAL_UNLOCK_TTY(tm);
368320397Sdim	}
369320397Sdim
370320397Sdim	tm->tm_class->tc_done(tm);
371320397Sdim	if (flags & TF_BELL)
372320397Sdim		tm->tm_class->tc_bell(tm);
373320397Sdim}
374320397Sdim
375320397Sdimstatic int
376320397Sdimtermtty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
377320397Sdim{
378320397Sdim	struct terminal *tm = tty_softc(tp);
379320397Sdim	int error;
380320397Sdim
381320397Sdim	switch (cmd) {
382320397Sdim	case CONS_GETINFO: {
383320397Sdim		vid_info_t *vi = (vid_info_t *)data;
384320397Sdim		const teken_pos_t *p;
385320397Sdim		int fg, bg;
386320397Sdim
387320397Sdim		if (vi->size != sizeof(vid_info_t))
388320397Sdim			return (EINVAL);
389320397Sdim
390320397Sdim		/* Already help the console driver by filling in some data. */
391320397Sdim		p = teken_get_cursor(&tm->tm_emulator);
392320397Sdim		vi->mv_row = p->tp_row;
393320397Sdim		vi->mv_col = p->tp_col;
394320397Sdim
395319780Sdim		p = teken_get_winsize(&tm->tm_emulator);
396319780Sdim		vi->mv_rsz = p->tp_row;
397319780Sdim		vi->mv_csz = p->tp_col;
398319780Sdim
399319780Sdim		teken_get_defattr_cons25(&tm->tm_emulator, &fg, &bg);
400319780Sdim		vi->mv_norm.fore = fg;
401320041Sdim		vi->mv_norm.back = bg;
402320397Sdim		/* XXX: keep vidcontrol happy; bold backgrounds. */
403320041Sdim		vi->mv_rev.fore = bg;
404320041Sdim		vi->mv_rev.back = fg & 0x7;
405320397Sdim		break;
406320397Sdim	}
407320397Sdim	}
408320397Sdim
409320397Sdim	/*
410319780Sdim	 * Unlike various other drivers, this driver will never
411319780Sdim	 * deallocate TTYs.  This means it's safe to temporarily unlock
412320041Sdim	 * the TTY when handling ioctls.
413320041Sdim	 */
414320397Sdim	tty_unlock(tp);
415320041Sdim	error = tm->tm_class->tc_ioctl(tm, cmd, data, td);
416320041Sdim	tty_lock(tp);
417319780Sdim	return (error);
418320397Sdim}
419320041Sdim
420320041Sdimstatic int
421320041Sdimtermtty_mmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t * paddr,
422320397Sdim    int nprot, vm_memattr_t *memattr)
423320041Sdim{
424320397Sdim	struct terminal *tm = tty_softc(tp);
425320970Sdim
426320397Sdim	return (tm->tm_class->tc_mmap(tm, offset, paddr, nprot, memattr));
427320397Sdim}
428320397Sdim
429320041Sdim/*
430320041Sdim * Binding with the kernel and debug console.
431320397Sdim */
432319780Sdim
433320041Sdimstatic cn_probe_t	termcn_cnprobe;
434320041Sdimstatic cn_init_t	termcn_cninit;
435320397Sdimstatic cn_term_t	termcn_cnterm;
436319780Sdimstatic cn_getc_t	termcn_cngetc;
437320041Sdimstatic cn_putc_t	termcn_cnputc;
438320041Sdimstatic cn_grab_t	termcn_cngrab;
439320397Sdimstatic cn_ungrab_t	termcn_cnungrab;
440320397Sdim
441320970Sdimconst struct consdev_ops termcn_cnops = {
442320397Sdim	.cn_probe	= termcn_cnprobe,
443320397Sdim	.cn_init	= termcn_cninit,
444320041Sdim	.cn_term	= termcn_cnterm,
445320572Sdim	.cn_getc	= termcn_cngetc,
446320572Sdim	.cn_putc	= termcn_cnputc,
447320572Sdim	.cn_grab	= termcn_cngrab,
448320572Sdim	.cn_ungrab	= termcn_cnungrab,
449320572Sdim};
450320572Sdim
451320572Sdimvoid
452319780Sdimtermcn_cnregister(struct terminal *tm)
453319780Sdim{
454320397Sdim	struct consdev *cp;
455320041Sdim
456320397Sdim	cp = tm->consdev;
457320041Sdim	if (cp == NULL) {
458319780Sdim		cp = malloc(sizeof(struct consdev), M_TERMINAL,
459320041Sdim		    M_WAITOK|M_ZERO);
460319780Sdim		cp->cn_ops = &termcn_cnops;
461320397Sdim		cp->cn_arg = tm;
462319780Sdim		cp->cn_pri = CN_INTERNAL;
463320041Sdim		sprintf(cp->cn_name, "ttyv0");
464320041Sdim
465320397Sdim		tm->tm_flags = TF_CONS;
466320041Sdim		tm->consdev = cp;
467320041Sdim
468320041Sdim		terminal_init(tm);
469320397Sdim	}
470320041Sdim
471320041Sdim	/* Attach terminal as console. */
472320041Sdim	cnadd(cp);
473320397Sdim}
474320041Sdim
475320041Sdimstatic void
476320041Sdimtermcn_cngrab(struct consdev *cp)
477320397Sdim{
478320041Sdim
479320041Sdim}
480320041Sdim
481320041Sdimstatic void
482320397Sdimtermcn_cnungrab(struct consdev *cp)
483320041Sdim{
484320041Sdim
485320041Sdim}
486320041Sdim
487320397Sdimstatic void
488320041Sdimtermcn_cnprobe(struct consdev *cp)
489319780Sdim{
490319780Sdim	struct terminal *tm = cp->cn_arg;
491320397Sdim
492319780Sdim	if (tm == NULL) {
493319780Sdim		cp->cn_pri = CN_DEAD;
494319780Sdim		return;
495320397Sdim	}
496320397Sdim
497319780Sdim	tm->consdev = cp;
498320397Sdim	terminal_init(tm);
499319780Sdim
500319780Sdim	tm->tm_class->tc_cnprobe(tm, cp);
501320397Sdim}
502319780Sdim
503319780Sdimstatic void
504319780Sdimtermcn_cninit(struct consdev *cp)
505320397Sdim{
506319780Sdim
507319780Sdim}
508319780Sdim
509319780Sdimstatic void
510319780Sdimtermcn_cnterm(struct consdev *cp)
511319780Sdim{
512319780Sdim
513319780Sdim}
514319780Sdim
515319780Sdimstatic int
516319780Sdimtermcn_cngetc(struct consdev *cp)
517319780Sdim{
518319780Sdim	struct terminal *tm = cp->cn_arg;
519319780Sdim
520319780Sdim	return (tm->tm_class->tc_cngetc(tm));
521319780Sdim}
522319780Sdim
523319780Sdimstatic void
524319780Sdimtermcn_cnputc(struct consdev *cp, int c)
525319780Sdim{
526319780Sdim	struct terminal *tm = cp->cn_arg;
527319780Sdim	teken_attr_t backup;
528319780Sdim	char cv = c;
529319780Sdim
530319780Sdim	TERMINAL_LOCK_CONS(tm);
531319780Sdim	if (!(tm->tm_flags & TF_MUTE)) {
532319780Sdim		backup = *teken_get_curattr(&tm->tm_emulator);
533319780Sdim		teken_set_curattr(&tm->tm_emulator, &kernel_message);
534319780Sdim		teken_input(&tm->tm_emulator, &cv, 1);
535319780Sdim		teken_set_curattr(&tm->tm_emulator, &backup);
536319780Sdim	}
537319780Sdim	TERMINAL_UNLOCK_CONS(tm);
538319780Sdim
539319780Sdim	tm->tm_class->tc_done(tm);
540319780Sdim}
541319780Sdim
542319780Sdim/*
543319780Sdim * Binding with the terminal emulator.
544319780Sdim */
545319780Sdim
546319780Sdimstatic void
547319780Sdimtermteken_bell(void *softc)
548319780Sdim{
549319780Sdim	struct terminal *tm = softc;
550319780Sdim
551319780Sdim	tm->tm_flags |= TF_BELL;
552319780Sdim}
553319780Sdim
554319780Sdimstatic void
555319780Sdimtermteken_cursor(void *softc, const teken_pos_t *p)
556319780Sdim{
557319780Sdim	struct terminal *tm = softc;
558320041Sdim
559319780Sdim	tm->tm_class->tc_cursor(tm, p);
560320041Sdim}
561319780Sdim
562319780Sdimstatic void
563319780Sdimtermteken_putchar(void *softc, const teken_pos_t *p, teken_char_t c,
564320397Sdim    const teken_attr_t *a)
565320041Sdim{
566319780Sdim	struct terminal *tm = softc;
567320041Sdim
568319780Sdim	tm->tm_class->tc_putchar(tm, p, TCHAR_CREATE(c, a));
569319780Sdim}
570320041Sdim
571320041Sdimstatic void
572320041Sdimtermteken_fill(void *softc, const teken_rect_t *r, teken_char_t c,
573320041Sdim    const teken_attr_t *a)
574320041Sdim{
575319780Sdim	struct terminal *tm = softc;
576319780Sdim
577319780Sdim	tm->tm_class->tc_fill(tm, r, TCHAR_CREATE(c, a));
578319780Sdim}
579319780Sdim
580319780Sdimstatic void
581319780Sdimtermteken_copy(void *softc, const teken_rect_t *r, const teken_pos_t *p)
582319780Sdim{
583319780Sdim	struct terminal *tm = softc;
584319780Sdim
585319780Sdim	tm->tm_class->tc_copy(tm, r, p);
586319780Sdim}
587319780Sdim
588319780Sdimstatic void
589319780Sdimtermteken_param(void *softc, int cmd, unsigned int arg)
590319780Sdim{
591319780Sdim	struct terminal *tm = softc;
592319780Sdim
593319780Sdim	tm->tm_class->tc_param(tm, cmd, arg);
594319780Sdim}
595319780Sdim
596319780Sdimstatic void
597319780Sdimtermteken_respond(void *softc, const void *buf, size_t len)
598319780Sdim{
599319780Sdim#if 0
600319780Sdim	struct terminal *tm = softc;
601319780Sdim	struct tty *tp;
602319780Sdim
603319780Sdim	/*
604319780Sdim	 * Only inject a response into the TTY if the data actually
605319780Sdim	 * originated from the TTY.
606319780Sdim	 *
607319780Sdim	 * XXX: This cannot be done right now.  The TTY could pick up
608319780Sdim	 * other locks.  It could also in theory cause loops, when the
609319780Sdim	 * TTY performs echoing of a command that generates even more
610319780Sdim	 * input.
611319780Sdim	 */
612319780Sdim	tp = tm->tm_tty;
613319780Sdim	if (tp == NULL)
614319780Sdim		return;
615319780Sdim
616319780Sdim	ttydisc_rint_simple(tp, buf, len);
617319780Sdim	ttydisc_rint_done(tp);
618319780Sdim#endif
619319780Sdim}
620319780Sdim