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