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: releng/10.3/sys/kern/subr_terminal.c 274860 2014-11-22 16:55:55Z dumbbell $");
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;
88262861Sjhbstatic 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,
95262861Sjhb	.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 = {
122268037Smarius	.ta_fgcolor	= TCHAR_FGCOLOR(TERMINAL_KERN_ATTR),
123268037Smarius	.ta_bgcolor	= TCHAR_BGCOLOR(TERMINAL_KERN_ATTR),
124268037Smarius	.ta_format	= TCHAR_FORMAT(TERMINAL_KERN_ATTR)
125219888Sed};
126219888Sed
127219888Sedstatic const teken_attr_t default_message = {
128268037Smarius	.ta_fgcolor	= TCHAR_FGCOLOR(TERMINAL_NORM_ATTR),
129268037Smarius	.ta_bgcolor	= TCHAR_BGCOLOR(TERMINAL_NORM_ATTR),
130268037Smarius	.ta_format	= TCHAR_FORMAT(TERMINAL_NORM_ATTR)
131219888Sed};
132219888Sed
133268037Smarius#define	TCHAR_CREATE(c, a)	((c) | TFORMAT((a)->ta_format) |	\
134268037Smarius	TCOLOR_FG(teken_256to8((a)->ta_fgcolor)) |			\
135268037Smarius	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
193274860Sdumbbellterminal_set_cursor(struct terminal *tm, const term_pos_t *pos)
194274860Sdumbbell{
195274860Sdumbbell
196274860Sdumbbell	teken_set_cursor(&tm->tm_emulator, pos);
197274860Sdumbbell}
198274860Sdumbbell
199274860Sdumbbellvoid
200256897Srayterminal_set_winsize_blank(struct terminal *tm, const struct winsize *size,
201268037Smarius    int blank, const term_attr_t *attr)
202219888Sed{
203219888Sed	term_rect_t r;
204219888Sed
205219888Sed	tm->tm_winsize = *size;
206219888Sed
207219888Sed	r.tr_begin.tp_row = r.tr_begin.tp_col = 0;
208219888Sed	r.tr_end.tp_row = size->ws_row;
209219888Sed	r.tr_end.tp_col = size->ws_col;
210219888Sed
211219888Sed	TERMINAL_LOCK(tm);
212257252Sray	if (blank == 0)
213257431Sray		teken_set_winsize_noreset(&tm->tm_emulator, &r.tr_end);
214257252Sray	else
215257252Sray		teken_set_winsize(&tm->tm_emulator, &r.tr_end);
216219888Sed	TERMINAL_UNLOCK(tm);
217219888Sed
218264455Sray	if ((blank != 0) && !(tm->tm_flags & TF_MUTE))
219268037Smarius		tm->tm_class->tc_fill(tm, &r,
220268037Smarius		    TCHAR_CREATE((teken_char_t)' ', attr));
221256897Sray
222219888Sed	terminal_sync_ttysize(tm);
223219888Sed}
224219888Sed
225256897Srayvoid
226256897Srayterminal_set_winsize(struct terminal *tm, const struct winsize *size)
227256897Sray{
228256897Sray
229268037Smarius	terminal_set_winsize_blank(tm, size, 1,
230268037Smarius	    (const term_attr_t *)&default_message);
231256897Sray}
232256897Sray
233219888Sed/*
234219888Sed * XXX: This function is a kludge.  Drivers like vt(4) need to
235219888Sed * temporarily stop input when resizing, etc.  This should ideally be
236219888Sed * handled within the driver.
237219888Sed */
238219888Sed
239219888Sedvoid
240219888Sedterminal_mute(struct terminal *tm, int yes)
241219888Sed{
242219888Sed
243219888Sed	TERMINAL_LOCK(tm);
244219888Sed	if (yes)
245219888Sed		tm->tm_flags |= TF_MUTE;
246219888Sed	else
247219888Sed		tm->tm_flags &= ~TF_MUTE;
248219888Sed	TERMINAL_UNLOCK(tm);
249219888Sed}
250219888Sed
251219888Sedvoid
252219888Sedterminal_input_char(struct terminal *tm, term_char_t c)
253219888Sed{
254219888Sed	struct tty *tp;
255219888Sed
256219888Sed	tp = tm->tm_tty;
257219888Sed	if (tp == NULL)
258219888Sed		return;
259219888Sed
260262861Sjhb	/*
261262861Sjhb	 * Strip off any attributes. Also ignore input of second part of
262262861Sjhb	 * CJK fullwidth characters, as we don't want to return these
263262861Sjhb	 * characters twice.
264262861Sjhb	 */
265262861Sjhb	if (TCHAR_FORMAT(c) & TF_CJK_RIGHT)
266262861Sjhb		return;
267219888Sed	c = TCHAR_CHARACTER(c);
268219888Sed
269219888Sed	tty_lock(tp);
270219888Sed	/*
271219888Sed	 * Conversion to UTF-8.
272219888Sed	 */
273219888Sed	if (c < 0x80) {
274219888Sed		ttydisc_rint(tp, c, 0);
275219888Sed	} else if (c < 0x800) {
276219888Sed		char str[2] = {
277219888Sed			0xc0 | (c >> 6),
278219888Sed			0x80 | (c & 0x3f)
279219888Sed		};
280219888Sed
281219888Sed		ttydisc_rint_simple(tp, str, sizeof str);
282219888Sed	} else if (c < 0x10000) {
283219888Sed		char str[3] = {
284219888Sed			0xe0 | (c >> 12),
285219888Sed			0x80 | ((c >> 6) & 0x3f),
286219888Sed			0x80 | (c & 0x3f)
287219888Sed		};
288219888Sed
289219888Sed		ttydisc_rint_simple(tp, str, sizeof str);
290219888Sed	} else {
291219888Sed		char str[4] = {
292219888Sed			0xf0 | (c >> 18),
293219888Sed			0x80 | ((c >> 12) & 0x3f),
294219888Sed			0x80 | ((c >> 6) & 0x3f),
295219888Sed			0x80 | (c & 0x3f)
296219888Sed		};
297219888Sed
298219888Sed		ttydisc_rint_simple(tp, str, sizeof str);
299219888Sed	}
300219888Sed	ttydisc_rint_done(tp);
301219888Sed	tty_unlock(tp);
302219888Sed}
303219888Sed
304219888Sedvoid
305219888Sedterminal_input_raw(struct terminal *tm, char c)
306219888Sed{
307219888Sed	struct tty *tp;
308219888Sed
309219888Sed	tp = tm->tm_tty;
310219888Sed	if (tp == NULL)
311219888Sed		return;
312219888Sed
313219888Sed	tty_lock(tp);
314219888Sed	ttydisc_rint(tp, c, 0);
315219888Sed	ttydisc_rint_done(tp);
316219888Sed	tty_unlock(tp);
317219888Sed}
318219888Sed
319219888Sedvoid
320219888Sedterminal_input_special(struct terminal *tm, unsigned int k)
321219888Sed{
322219888Sed	struct tty *tp;
323219888Sed	const char *str;
324219888Sed
325219888Sed	tp = tm->tm_tty;
326219888Sed	if (tp == NULL)
327219888Sed		return;
328219888Sed
329219888Sed	str = teken_get_sequence(&tm->tm_emulator, k);
330219888Sed	if (str == NULL)
331219888Sed		return;
332219888Sed
333219888Sed	tty_lock(tp);
334219888Sed	ttydisc_rint_simple(tp, str, strlen(str));
335219888Sed	ttydisc_rint_done(tp);
336219888Sed	tty_unlock(tp);
337219888Sed}
338219888Sed
339219888Sed/*
340219888Sed * Binding with the TTY layer.
341219888Sed */
342219888Sed
343219888Sedstatic int
344219888Sedtermtty_open(struct tty *tp)
345219888Sed{
346219888Sed	struct terminal *tm = tty_softc(tp);
347219888Sed
348219888Sed	tm->tm_class->tc_opened(tm, 1);
349219888Sed	return (0);
350219888Sed}
351219888Sed
352219888Sedstatic void
353219888Sedtermtty_close(struct tty *tp)
354219888Sed{
355219888Sed	struct terminal *tm = tty_softc(tp);
356219888Sed
357219888Sed	tm->tm_class->tc_opened(tm, 0);
358219888Sed}
359219888Sed
360219888Sedstatic void
361219888Sedtermtty_outwakeup(struct tty *tp)
362219888Sed{
363219888Sed	struct terminal *tm = tty_softc(tp);
364219888Sed	char obuf[128];
365219888Sed	size_t olen;
366219888Sed	unsigned int flags = 0;
367219888Sed
368219888Sed	while ((olen = ttydisc_getc(tp, obuf, sizeof obuf)) > 0) {
369219888Sed		TERMINAL_LOCK_TTY(tm);
370219888Sed		if (!(tm->tm_flags & TF_MUTE)) {
371219888Sed			tm->tm_flags &= ~TF_BELL;
372219888Sed			teken_input(&tm->tm_emulator, obuf, olen);
373219888Sed			flags |= tm->tm_flags;
374219888Sed		}
375219888Sed		TERMINAL_UNLOCK_TTY(tm);
376219888Sed	}
377219888Sed
378219888Sed	tm->tm_class->tc_done(tm);
379219888Sed	if (flags & TF_BELL)
380219888Sed		tm->tm_class->tc_bell(tm);
381219888Sed}
382219888Sed
383219888Sedstatic int
384219888Sedtermtty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
385219888Sed{
386219888Sed	struct terminal *tm = tty_softc(tp);
387219888Sed	int error;
388219888Sed
389219888Sed	switch (cmd) {
390219888Sed	case CONS_GETINFO: {
391219888Sed		vid_info_t *vi = (vid_info_t *)data;
392219888Sed		const teken_pos_t *p;
393219888Sed		int fg, bg;
394219888Sed
395219888Sed		if (vi->size != sizeof(vid_info_t))
396219888Sed			return (EINVAL);
397219888Sed
398219888Sed		/* Already help the console driver by filling in some data. */
399219888Sed		p = teken_get_cursor(&tm->tm_emulator);
400219888Sed		vi->mv_row = p->tp_row;
401219888Sed		vi->mv_col = p->tp_col;
402219888Sed
403219888Sed		p = teken_get_winsize(&tm->tm_emulator);
404219888Sed		vi->mv_rsz = p->tp_row;
405219888Sed		vi->mv_csz = p->tp_col;
406219888Sed
407219888Sed		teken_get_defattr_cons25(&tm->tm_emulator, &fg, &bg);
408219888Sed		vi->mv_norm.fore = fg;
409219888Sed		vi->mv_norm.back = bg;
410219888Sed		/* XXX: keep vidcontrol happy; bold backgrounds. */
411219888Sed		vi->mv_rev.fore = bg;
412219888Sed		vi->mv_rev.back = fg & 0x7;
413219888Sed		break;
414219888Sed	}
415219888Sed	}
416219888Sed
417219888Sed	/*
418219888Sed	 * Unlike various other drivers, this driver will never
419219888Sed	 * deallocate TTYs.  This means it's safe to temporarily unlock
420219888Sed	 * the TTY when handling ioctls.
421219888Sed	 */
422219888Sed	tty_unlock(tp);
423219888Sed	error = tm->tm_class->tc_ioctl(tm, cmd, data, td);
424219888Sed	tty_lock(tp);
425219888Sed	return (error);
426219888Sed}
427219888Sed
428262861Sjhbstatic int
429262861Sjhbtermtty_mmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t * paddr,
430262861Sjhb    int nprot, vm_memattr_t *memattr)
431262861Sjhb{
432262861Sjhb	struct terminal *tm = tty_softc(tp);
433262861Sjhb
434262861Sjhb	return (tm->tm_class->tc_mmap(tm, offset, paddr, nprot, memattr));
435262861Sjhb}
436262861Sjhb
437219888Sed/*
438219888Sed * Binding with the kernel and debug console.
439219888Sed */
440219888Sed
441256143Sraystatic cn_probe_t	termcn_cnprobe;
442256143Sraystatic cn_init_t	termcn_cninit;
443256143Sraystatic cn_term_t	termcn_cnterm;
444256143Sraystatic cn_getc_t	termcn_cngetc;
445256143Sraystatic cn_putc_t	termcn_cnputc;
446256143Sraystatic cn_grab_t	termcn_cngrab;
447256143Sraystatic cn_ungrab_t	termcn_cnungrab;
448219888Sed
449256143Srayconst struct consdev_ops termcn_cnops = {
450256143Sray	.cn_probe	= termcn_cnprobe,
451256143Sray	.cn_init	= termcn_cninit,
452256143Sray	.cn_term	= termcn_cnterm,
453256143Sray	.cn_getc	= termcn_cngetc,
454256143Sray	.cn_putc	= termcn_cnputc,
455256143Sray	.cn_grab	= termcn_cngrab,
456256143Sray	.cn_ungrab	= termcn_cnungrab,
457219888Sed};
458219888Sed
459256143Srayvoid
460256143Sraytermcn_cnregister(struct terminal *tm)
461256143Sray{
462256143Sray	struct consdev *cp;
463256143Sray
464256143Sray	cp = tm->consdev;
465256143Sray	if (cp == NULL) {
466256143Sray		cp = malloc(sizeof(struct consdev), M_TERMINAL,
467256143Sray		    M_WAITOK|M_ZERO);
468256143Sray		cp->cn_ops = &termcn_cnops;
469256143Sray		cp->cn_arg = tm;
470256143Sray		cp->cn_pri = CN_INTERNAL;
471256143Sray		sprintf(cp->cn_name, "ttyv0");
472256143Sray
473256143Sray		tm->tm_flags = TF_CONS;
474256143Sray		tm->consdev = cp;
475256143Sray
476256143Sray		terminal_init(tm);
477256143Sray	}
478256143Sray
479256143Sray	/* Attach terminal as console. */
480256143Sray	cnadd(cp);
481256143Sray}
482256143Sray
483219888Sedstatic void
484256143Sraytermcn_cngrab(struct consdev *cp)
485219888Sed{
486271769Sdumbbell	struct terminal *tm = cp->cn_arg;
487256143Sray
488271769Sdumbbell	tm->tm_class->tc_cngrab(tm);
489256143Sray}
490256143Sray
491256143Sraystatic void
492256143Sraytermcn_cnungrab(struct consdev *cp)
493256143Sray{
494271769Sdumbbell	struct terminal *tm = cp->cn_arg;
495256143Sray
496271769Sdumbbell	tm->tm_class->tc_cnungrab(tm);
497256143Sray}
498256143Sray
499256143Sraystatic void
500256143Sraytermcn_cnprobe(struct consdev *cp)
501256143Sray{
502219888Sed	struct terminal *tm = cp->cn_arg;
503219888Sed
504256143Sray	if (tm == NULL) {
505256143Sray		cp->cn_pri = CN_DEAD;
506256143Sray		return;
507256143Sray	}
508256143Sray
509256143Sray	tm->consdev = cp;
510219888Sed	terminal_init(tm);
511219888Sed
512219888Sed	tm->tm_class->tc_cnprobe(tm, cp);
513219888Sed}
514219888Sed
515219888Sedstatic void
516256143Sraytermcn_cninit(struct consdev *cp)
517219888Sed{
518256143Sray
519219888Sed}
520219888Sed
521219888Sedstatic void
522256143Sraytermcn_cnterm(struct consdev *cp)
523219888Sed{
524256143Sray
525219888Sed}
526219888Sed
527219888Sedstatic int
528256143Sraytermcn_cngetc(struct consdev *cp)
529219888Sed{
530219888Sed	struct terminal *tm = cp->cn_arg;
531219888Sed
532219888Sed	return (tm->tm_class->tc_cngetc(tm));
533219888Sed}
534219888Sed
535219888Sedstatic void
536256143Sraytermcn_cnputc(struct consdev *cp, int c)
537219888Sed{
538219888Sed	struct terminal *tm = cp->cn_arg;
539219888Sed	teken_attr_t backup;
540219888Sed	char cv = c;
541219888Sed
542219888Sed	TERMINAL_LOCK_CONS(tm);
543219888Sed	if (!(tm->tm_flags & TF_MUTE)) {
544219888Sed		backup = *teken_get_curattr(&tm->tm_emulator);
545219888Sed		teken_set_curattr(&tm->tm_emulator, &kernel_message);
546219888Sed		teken_input(&tm->tm_emulator, &cv, 1);
547219888Sed		teken_set_curattr(&tm->tm_emulator, &backup);
548219888Sed	}
549219888Sed	TERMINAL_UNLOCK_CONS(tm);
550219888Sed
551219888Sed	tm->tm_class->tc_done(tm);
552219888Sed}
553219888Sed
554219888Sed/*
555219888Sed * Binding with the terminal emulator.
556219888Sed */
557219888Sed
558219888Sedstatic void
559219888Sedtermteken_bell(void *softc)
560219888Sed{
561219888Sed	struct terminal *tm = softc;
562219888Sed
563219888Sed	tm->tm_flags |= TF_BELL;
564219888Sed}
565219888Sed
566219888Sedstatic void
567219888Sedtermteken_cursor(void *softc, const teken_pos_t *p)
568219888Sed{
569219888Sed	struct terminal *tm = softc;
570219888Sed
571219888Sed	tm->tm_class->tc_cursor(tm, p);
572219888Sed}
573219888Sed
574219888Sedstatic void
575219888Sedtermteken_putchar(void *softc, const teken_pos_t *p, teken_char_t c,
576219888Sed    const teken_attr_t *a)
577219888Sed{
578219888Sed	struct terminal *tm = softc;
579219888Sed
580219888Sed	tm->tm_class->tc_putchar(tm, p, TCHAR_CREATE(c, a));
581219888Sed}
582219888Sed
583219888Sedstatic void
584219888Sedtermteken_fill(void *softc, const teken_rect_t *r, teken_char_t c,
585219888Sed    const teken_attr_t *a)
586219888Sed{
587219888Sed	struct terminal *tm = softc;
588219888Sed
589219888Sed	tm->tm_class->tc_fill(tm, r, TCHAR_CREATE(c, a));
590219888Sed}
591219888Sed
592219888Sedstatic void
593219888Sedtermteken_copy(void *softc, const teken_rect_t *r, const teken_pos_t *p)
594219888Sed{
595219888Sed	struct terminal *tm = softc;
596219888Sed
597219888Sed	tm->tm_class->tc_copy(tm, r, p);
598219888Sed}
599219888Sed
600219888Sedstatic void
601219888Sedtermteken_param(void *softc, int cmd, unsigned int arg)
602219888Sed{
603219888Sed	struct terminal *tm = softc;
604219888Sed
605219888Sed	tm->tm_class->tc_param(tm, cmd, arg);
606219888Sed}
607219888Sed
608219888Sedstatic void
609219888Sedtermteken_respond(void *softc, const void *buf, size_t len)
610219888Sed{
611219888Sed#if 0
612219888Sed	struct terminal *tm = softc;
613219888Sed	struct tty *tp;
614219888Sed
615219888Sed	/*
616219888Sed	 * Only inject a response into the TTY if the data actually
617219888Sed	 * originated from the TTY.
618219888Sed	 *
619219888Sed	 * XXX: This cannot be done right now.  The TTY could pick up
620219888Sed	 * other locks.  It could also in theory cause loops, when the
621219888Sed	 * TTY performs echoing of a command that generates even more
622219888Sed	 * input.
623219888Sed	 */
624219888Sed	tp = tm->tm_tty;
625219888Sed	if (tp == NULL)
626219888Sed		return;
627219888Sed
628219888Sed	ttydisc_rint_simple(tp, buf, len);
629219888Sed	ttydisc_rint_done(tp);
630219888Sed#endif
631219888Sed}
632