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