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: stable/11/sys/kern/subr_terminal.c 332831 2018-04-20 15:55:09Z jtl $");
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
133330916Seadler/* Fudge fg brightness as TF_BOLD (shifted). */
134330916Seadler#define	TCOLOR_FG_FUDGED(color) __extension__ ({			\
135330916Seadler	teken_color_t _c;						\
136330916Seadler									\
137330916Seadler	_c = (color);							\
138330916Seadler	TCOLOR_FG(_c & 7) | ((_c & 8) << 18);				\
139330916Seadler})
140330916Seadler
141330916Seadler/* Fudge bg brightness as TF_BLINK (shifted). */
142330916Seadler#define	TCOLOR_BG_FUDGED(color) __extension__ ({			\
143330916Seadler	teken_color_t _c;						\
144330916Seadler									\
145330916Seadler	_c = (color);							\
146330916Seadler	TCOLOR_BG(_c & 7) | ((_c & 8) << 20);				\
147330916Seadler})
148330916Seadler
149330916Seadler#define	TCOLOR_256TO16(color) __extension__ ({				\
150330916Seadler	teken_color_t _c;						\
151330916Seadler									\
152330916Seadler	_c = (color);							\
153330916Seadler	if (_c >= 16)							\
154330916Seadler		_c = teken_256to16(_c);					\
155330916Seadler	_c;								\
156330916Seadler})
157330916Seadler
158267978Smarius#define	TCHAR_CREATE(c, a)	((c) | TFORMAT((a)->ta_format) |	\
159330916Seadler	TCOLOR_FG_FUDGED(TCOLOR_256TO16((a)->ta_fgcolor)) |		\
160330916Seadler	TCOLOR_BG_FUDGED(TCOLOR_256TO16((a)->ta_bgcolor)))
161219888Sed
162219888Sedstatic void
163219888Sedterminal_init(struct terminal *tm)
164219888Sed{
165219888Sed
166219888Sed	if (tm->tm_flags & TF_CONS)
167219888Sed		mtx_init(&tm->tm_mtx, "trmlck", NULL, MTX_SPIN);
168219888Sed	teken_init(&tm->tm_emulator, &terminal_drawmethods, tm);
169219888Sed	teken_set_defattr(&tm->tm_emulator, &default_message);
170219888Sed}
171219888Sed
172219888Sedstruct terminal *
173219888Sedterminal_alloc(const struct terminal_class *tc, void *softc)
174219888Sed{
175219888Sed	struct terminal *tm;
176219888Sed
177219888Sed	tm = malloc(sizeof(struct terminal), M_TERMINAL, M_WAITOK|M_ZERO);
178219888Sed	terminal_init(tm);
179219888Sed
180219888Sed	tm->tm_class = tc;
181219888Sed	tm->tm_softc = softc;
182219888Sed
183219888Sed	return (tm);
184219888Sed}
185219888Sed
186219888Sedstatic void
187219888Sedterminal_sync_ttysize(struct terminal *tm)
188219888Sed{
189219888Sed	struct tty *tp;
190219888Sed
191219888Sed	tp = tm->tm_tty;
192219888Sed	if (tp == NULL)
193219888Sed		return;
194219888Sed
195219888Sed	tty_lock(tp);
196219888Sed	tty_set_winsize(tp, &tm->tm_winsize);
197219888Sed	tty_unlock(tp);
198219888Sed}
199219888Sed
200219888Sedvoid
201219888Sedterminal_maketty(struct terminal *tm, const char *fmt, ...)
202219888Sed{
203219888Sed	struct tty *tp;
204219888Sed	char name[8];
205219888Sed	va_list ap;
206219888Sed
207219888Sed	va_start(ap, fmt);
208219888Sed	vsnrprintf(name, sizeof name, 32, fmt, ap);
209219888Sed	va_end(ap);
210219888Sed
211219888Sed	tp = tty_alloc(&terminal_tty_class, tm);
212243802Snwhitehorn	tty_makedev(tp, NULL, "%s", name);
213219888Sed	tm->tm_tty = tp;
214219888Sed	terminal_sync_ttysize(tm);
215219888Sed}
216219888Sed
217219888Sedvoid
218273932Sdumbbellterminal_set_cursor(struct terminal *tm, const term_pos_t *pos)
219273932Sdumbbell{
220273932Sdumbbell
221273932Sdumbbell	teken_set_cursor(&tm->tm_emulator, pos);
222273932Sdumbbell}
223273932Sdumbbell
224273932Sdumbbellvoid
225256897Srayterminal_set_winsize_blank(struct terminal *tm, const struct winsize *size,
226267978Smarius    int blank, const term_attr_t *attr)
227219888Sed{
228219888Sed	term_rect_t r;
229219888Sed
230219888Sed	tm->tm_winsize = *size;
231219888Sed
232219888Sed	r.tr_begin.tp_row = r.tr_begin.tp_col = 0;
233219888Sed	r.tr_end.tp_row = size->ws_row;
234219888Sed	r.tr_end.tp_col = size->ws_col;
235219888Sed
236219888Sed	TERMINAL_LOCK(tm);
237257252Sray	if (blank == 0)
238257431Sray		teken_set_winsize_noreset(&tm->tm_emulator, &r.tr_end);
239257252Sray	else
240257252Sray		teken_set_winsize(&tm->tm_emulator, &r.tr_end);
241219888Sed	TERMINAL_UNLOCK(tm);
242219888Sed
243264242Sray	if ((blank != 0) && !(tm->tm_flags & TF_MUTE))
244267978Smarius		tm->tm_class->tc_fill(tm, &r,
245267978Smarius		    TCHAR_CREATE((teken_char_t)' ', attr));
246256897Sray
247219888Sed	terminal_sync_ttysize(tm);
248219888Sed}
249219888Sed
250256897Srayvoid
251256897Srayterminal_set_winsize(struct terminal *tm, const struct winsize *size)
252256897Sray{
253256897Sray
254267978Smarius	terminal_set_winsize_blank(tm, size, 1,
255267978Smarius	    (const term_attr_t *)&default_message);
256256897Sray}
257256897Sray
258219888Sed/*
259219888Sed * XXX: This function is a kludge.  Drivers like vt(4) need to
260219888Sed * temporarily stop input when resizing, etc.  This should ideally be
261219888Sed * handled within the driver.
262219888Sed */
263219888Sed
264219888Sedvoid
265219888Sedterminal_mute(struct terminal *tm, int yes)
266219888Sed{
267219888Sed
268219888Sed	TERMINAL_LOCK(tm);
269219888Sed	if (yes)
270219888Sed		tm->tm_flags |= TF_MUTE;
271219888Sed	else
272219888Sed		tm->tm_flags &= ~TF_MUTE;
273219888Sed	TERMINAL_UNLOCK(tm);
274219888Sed}
275219888Sed
276219888Sedvoid
277219888Sedterminal_input_char(struct terminal *tm, term_char_t c)
278219888Sed{
279219888Sed	struct tty *tp;
280219888Sed
281219888Sed	tp = tm->tm_tty;
282219888Sed	if (tp == NULL)
283219888Sed		return;
284219888Sed
285259830Sed	/*
286259830Sed	 * Strip off any attributes. Also ignore input of second part of
287259830Sed	 * CJK fullwidth characters, as we don't want to return these
288259830Sed	 * characters twice.
289259830Sed	 */
290259830Sed	if (TCHAR_FORMAT(c) & TF_CJK_RIGHT)
291259830Sed		return;
292219888Sed	c = TCHAR_CHARACTER(c);
293219888Sed
294219888Sed	tty_lock(tp);
295219888Sed	/*
296219888Sed	 * Conversion to UTF-8.
297219888Sed	 */
298219888Sed	if (c < 0x80) {
299219888Sed		ttydisc_rint(tp, c, 0);
300219888Sed	} else if (c < 0x800) {
301219888Sed		char str[2] = {
302219888Sed			0xc0 | (c >> 6),
303219888Sed			0x80 | (c & 0x3f)
304219888Sed		};
305219888Sed
306219888Sed		ttydisc_rint_simple(tp, str, sizeof str);
307219888Sed	} else if (c < 0x10000) {
308219888Sed		char str[3] = {
309219888Sed			0xe0 | (c >> 12),
310219888Sed			0x80 | ((c >> 6) & 0x3f),
311219888Sed			0x80 | (c & 0x3f)
312219888Sed		};
313219888Sed
314219888Sed		ttydisc_rint_simple(tp, str, sizeof str);
315219888Sed	} else {
316219888Sed		char str[4] = {
317219888Sed			0xf0 | (c >> 18),
318219888Sed			0x80 | ((c >> 12) & 0x3f),
319219888Sed			0x80 | ((c >> 6) & 0x3f),
320219888Sed			0x80 | (c & 0x3f)
321219888Sed		};
322219888Sed
323219888Sed		ttydisc_rint_simple(tp, str, sizeof str);
324219888Sed	}
325219888Sed	ttydisc_rint_done(tp);
326219888Sed	tty_unlock(tp);
327219888Sed}
328219888Sed
329219888Sedvoid
330219888Sedterminal_input_raw(struct terminal *tm, char c)
331219888Sed{
332219888Sed	struct tty *tp;
333219888Sed
334219888Sed	tp = tm->tm_tty;
335219888Sed	if (tp == NULL)
336219888Sed		return;
337219888Sed
338219888Sed	tty_lock(tp);
339219888Sed	ttydisc_rint(tp, c, 0);
340219888Sed	ttydisc_rint_done(tp);
341219888Sed	tty_unlock(tp);
342219888Sed}
343219888Sed
344219888Sedvoid
345219888Sedterminal_input_special(struct terminal *tm, unsigned int k)
346219888Sed{
347219888Sed	struct tty *tp;
348219888Sed	const char *str;
349219888Sed
350219888Sed	tp = tm->tm_tty;
351219888Sed	if (tp == NULL)
352219888Sed		return;
353219888Sed
354219888Sed	str = teken_get_sequence(&tm->tm_emulator, k);
355219888Sed	if (str == NULL)
356219888Sed		return;
357219888Sed
358219888Sed	tty_lock(tp);
359219888Sed	ttydisc_rint_simple(tp, str, strlen(str));
360219888Sed	ttydisc_rint_done(tp);
361219888Sed	tty_unlock(tp);
362219888Sed}
363219888Sed
364219888Sed/*
365219888Sed * Binding with the TTY layer.
366219888Sed */
367219888Sed
368219888Sedstatic int
369219888Sedtermtty_open(struct tty *tp)
370219888Sed{
371219888Sed	struct terminal *tm = tty_softc(tp);
372219888Sed
373219888Sed	tm->tm_class->tc_opened(tm, 1);
374219888Sed	return (0);
375219888Sed}
376219888Sed
377219888Sedstatic void
378219888Sedtermtty_close(struct tty *tp)
379219888Sed{
380219888Sed	struct terminal *tm = tty_softc(tp);
381219888Sed
382219888Sed	tm->tm_class->tc_opened(tm, 0);
383219888Sed}
384219888Sed
385219888Sedstatic void
386219888Sedtermtty_outwakeup(struct tty *tp)
387219888Sed{
388219888Sed	struct terminal *tm = tty_softc(tp);
389219888Sed	char obuf[128];
390219888Sed	size_t olen;
391219888Sed	unsigned int flags = 0;
392219888Sed
393219888Sed	while ((olen = ttydisc_getc(tp, obuf, sizeof obuf)) > 0) {
394219888Sed		TERMINAL_LOCK_TTY(tm);
395219888Sed		if (!(tm->tm_flags & TF_MUTE)) {
396219888Sed			tm->tm_flags &= ~TF_BELL;
397219888Sed			teken_input(&tm->tm_emulator, obuf, olen);
398219888Sed			flags |= tm->tm_flags;
399219888Sed		}
400219888Sed		TERMINAL_UNLOCK_TTY(tm);
401219888Sed	}
402219888Sed
403332831Sjtl	TERMINAL_LOCK_TTY(tm);
404332831Sjtl	if (!(tm->tm_flags & TF_MUTE))
405332831Sjtl		tm->tm_class->tc_done(tm);
406332831Sjtl	TERMINAL_UNLOCK_TTY(tm);
407219888Sed	if (flags & TF_BELL)
408219888Sed		tm->tm_class->tc_bell(tm);
409219888Sed}
410219888Sed
411219888Sedstatic int
412219888Sedtermtty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
413219888Sed{
414219888Sed	struct terminal *tm = tty_softc(tp);
415219888Sed	int error;
416219888Sed
417219888Sed	switch (cmd) {
418219888Sed	case CONS_GETINFO: {
419219888Sed		vid_info_t *vi = (vid_info_t *)data;
420219888Sed		const teken_pos_t *p;
421219888Sed		int fg, bg;
422219888Sed
423219888Sed		if (vi->size != sizeof(vid_info_t))
424219888Sed			return (EINVAL);
425219888Sed
426219888Sed		/* Already help the console driver by filling in some data. */
427219888Sed		p = teken_get_cursor(&tm->tm_emulator);
428219888Sed		vi->mv_row = p->tp_row;
429219888Sed		vi->mv_col = p->tp_col;
430219888Sed
431219888Sed		p = teken_get_winsize(&tm->tm_emulator);
432219888Sed		vi->mv_rsz = p->tp_row;
433219888Sed		vi->mv_csz = p->tp_col;
434219888Sed
435219888Sed		teken_get_defattr_cons25(&tm->tm_emulator, &fg, &bg);
436219888Sed		vi->mv_norm.fore = fg;
437219888Sed		vi->mv_norm.back = bg;
438219888Sed		/* XXX: keep vidcontrol happy; bold backgrounds. */
439219888Sed		vi->mv_rev.fore = bg;
440219888Sed		vi->mv_rev.back = fg & 0x7;
441219888Sed		break;
442219888Sed	}
443219888Sed	}
444219888Sed
445219888Sed	/*
446219888Sed	 * Unlike various other drivers, this driver will never
447219888Sed	 * deallocate TTYs.  This means it's safe to temporarily unlock
448219888Sed	 * the TTY when handling ioctls.
449219888Sed	 */
450219888Sed	tty_unlock(tp);
451219888Sed	error = tm->tm_class->tc_ioctl(tm, cmd, data, td);
452219888Sed	tty_lock(tp);
453219888Sed	return (error);
454219888Sed}
455219888Sed
456259777Sraystatic int
457259777Sraytermtty_mmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t * paddr,
458259777Sray    int nprot, vm_memattr_t *memattr)
459259777Sray{
460259777Sray	struct terminal *tm = tty_softc(tp);
461259777Sray
462259777Sray	return (tm->tm_class->tc_mmap(tm, offset, paddr, nprot, memattr));
463259777Sray}
464259777Sray
465219888Sed/*
466219888Sed * Binding with the kernel and debug console.
467219888Sed */
468219888Sed
469256143Sraystatic cn_probe_t	termcn_cnprobe;
470256143Sraystatic cn_init_t	termcn_cninit;
471256143Sraystatic cn_term_t	termcn_cnterm;
472256143Sraystatic cn_getc_t	termcn_cngetc;
473256143Sraystatic cn_putc_t	termcn_cnputc;
474256143Sraystatic cn_grab_t	termcn_cngrab;
475256143Sraystatic cn_ungrab_t	termcn_cnungrab;
476219888Sed
477256143Srayconst struct consdev_ops termcn_cnops = {
478256143Sray	.cn_probe	= termcn_cnprobe,
479256143Sray	.cn_init	= termcn_cninit,
480256143Sray	.cn_term	= termcn_cnterm,
481256143Sray	.cn_getc	= termcn_cngetc,
482256143Sray	.cn_putc	= termcn_cnputc,
483256143Sray	.cn_grab	= termcn_cngrab,
484256143Sray	.cn_ungrab	= termcn_cnungrab,
485219888Sed};
486219888Sed
487256143Srayvoid
488256143Sraytermcn_cnregister(struct terminal *tm)
489256143Sray{
490256143Sray	struct consdev *cp;
491256143Sray
492256143Sray	cp = tm->consdev;
493256143Sray	if (cp == NULL) {
494256143Sray		cp = malloc(sizeof(struct consdev), M_TERMINAL,
495256143Sray		    M_WAITOK|M_ZERO);
496256143Sray		cp->cn_ops = &termcn_cnops;
497256143Sray		cp->cn_arg = tm;
498256143Sray		cp->cn_pri = CN_INTERNAL;
499256143Sray		sprintf(cp->cn_name, "ttyv0");
500256143Sray
501256143Sray		tm->tm_flags = TF_CONS;
502256143Sray		tm->consdev = cp;
503256143Sray
504256143Sray		terminal_init(tm);
505256143Sray	}
506256143Sray
507256143Sray	/* Attach terminal as console. */
508256143Sray	cnadd(cp);
509256143Sray}
510256143Sray
511219888Sedstatic void
512256143Sraytermcn_cngrab(struct consdev *cp)
513219888Sed{
514270705Sdumbbell	struct terminal *tm = cp->cn_arg;
515256143Sray
516270705Sdumbbell	tm->tm_class->tc_cngrab(tm);
517256143Sray}
518256143Sray
519256143Sraystatic void
520256143Sraytermcn_cnungrab(struct consdev *cp)
521256143Sray{
522270705Sdumbbell	struct terminal *tm = cp->cn_arg;
523256143Sray
524270705Sdumbbell	tm->tm_class->tc_cnungrab(tm);
525256143Sray}
526256143Sray
527256143Sraystatic void
528256143Sraytermcn_cnprobe(struct consdev *cp)
529256143Sray{
530219888Sed	struct terminal *tm = cp->cn_arg;
531219888Sed
532256143Sray	if (tm == NULL) {
533256143Sray		cp->cn_pri = CN_DEAD;
534256143Sray		return;
535256143Sray	}
536256143Sray
537256143Sray	tm->consdev = cp;
538219888Sed	terminal_init(tm);
539219888Sed
540219888Sed	tm->tm_class->tc_cnprobe(tm, cp);
541219888Sed}
542219888Sed
543219888Sedstatic void
544256143Sraytermcn_cninit(struct consdev *cp)
545219888Sed{
546256143Sray
547219888Sed}
548219888Sed
549219888Sedstatic void
550256143Sraytermcn_cnterm(struct consdev *cp)
551219888Sed{
552256143Sray
553219888Sed}
554219888Sed
555219888Sedstatic int
556256143Sraytermcn_cngetc(struct consdev *cp)
557219888Sed{
558219888Sed	struct terminal *tm = cp->cn_arg;
559219888Sed
560219888Sed	return (tm->tm_class->tc_cngetc(tm));
561219888Sed}
562219888Sed
563219888Sedstatic void
564256143Sraytermcn_cnputc(struct consdev *cp, int c)
565219888Sed{
566219888Sed	struct terminal *tm = cp->cn_arg;
567219888Sed	teken_attr_t backup;
568219888Sed	char cv = c;
569219888Sed
570219888Sed	TERMINAL_LOCK_CONS(tm);
571219888Sed	if (!(tm->tm_flags & TF_MUTE)) {
572219888Sed		backup = *teken_get_curattr(&tm->tm_emulator);
573219888Sed		teken_set_curattr(&tm->tm_emulator, &kernel_message);
574219888Sed		teken_input(&tm->tm_emulator, &cv, 1);
575219888Sed		teken_set_curattr(&tm->tm_emulator, &backup);
576332831Sjtl		tm->tm_class->tc_done(tm);
577219888Sed	}
578219888Sed	TERMINAL_UNLOCK_CONS(tm);
579219888Sed}
580219888Sed
581219888Sed/*
582219888Sed * Binding with the terminal emulator.
583219888Sed */
584219888Sed
585219888Sedstatic void
586219888Sedtermteken_bell(void *softc)
587219888Sed{
588219888Sed	struct terminal *tm = softc;
589219888Sed
590219888Sed	tm->tm_flags |= TF_BELL;
591219888Sed}
592219888Sed
593219888Sedstatic void
594219888Sedtermteken_cursor(void *softc, const teken_pos_t *p)
595219888Sed{
596219888Sed	struct terminal *tm = softc;
597219888Sed
598219888Sed	tm->tm_class->tc_cursor(tm, p);
599219888Sed}
600219888Sed
601219888Sedstatic void
602219888Sedtermteken_putchar(void *softc, const teken_pos_t *p, teken_char_t c,
603219888Sed    const teken_attr_t *a)
604219888Sed{
605219888Sed	struct terminal *tm = softc;
606219888Sed
607219888Sed	tm->tm_class->tc_putchar(tm, p, TCHAR_CREATE(c, a));
608219888Sed}
609219888Sed
610219888Sedstatic void
611219888Sedtermteken_fill(void *softc, const teken_rect_t *r, teken_char_t c,
612219888Sed    const teken_attr_t *a)
613219888Sed{
614219888Sed	struct terminal *tm = softc;
615219888Sed
616219888Sed	tm->tm_class->tc_fill(tm, r, TCHAR_CREATE(c, a));
617219888Sed}
618219888Sed
619219888Sedstatic void
620219888Sedtermteken_copy(void *softc, const teken_rect_t *r, const teken_pos_t *p)
621219888Sed{
622219888Sed	struct terminal *tm = softc;
623219888Sed
624219888Sed	tm->tm_class->tc_copy(tm, r, p);
625219888Sed}
626219888Sed
627219888Sedstatic void
628219888Sedtermteken_param(void *softc, int cmd, unsigned int arg)
629219888Sed{
630219888Sed	struct terminal *tm = softc;
631219888Sed
632219888Sed	tm->tm_class->tc_param(tm, cmd, arg);
633219888Sed}
634219888Sed
635219888Sedstatic void
636219888Sedtermteken_respond(void *softc, const void *buf, size_t len)
637219888Sed{
638219888Sed#if 0
639219888Sed	struct terminal *tm = softc;
640219888Sed	struct tty *tp;
641219888Sed
642219888Sed	/*
643219888Sed	 * Only inject a response into the TTY if the data actually
644219888Sed	 * originated from the TTY.
645219888Sed	 *
646219888Sed	 * XXX: This cannot be done right now.  The TTY could pick up
647219888Sed	 * other locks.  It could also in theory cause loops, when the
648219888Sed	 * TTY performs echoing of a command that generates even more
649219888Sed	 * input.
650219888Sed	 */
651219888Sed	tp = tm->tm_tty;
652219888Sed	if (tp == NULL)
653219888Sed		return;
654219888Sed
655219888Sed	ttydisc_rint_simple(tp, buf, len);
656219888Sed	ttydisc_rint_done(tp);
657219888Sed#endif
658219888Sed}
659