1*27cf7d04SAleksandr Rybalko /*- 2*27cf7d04SAleksandr Rybalko * Copyright (c) 2009 The FreeBSD Foundation 3*27cf7d04SAleksandr Rybalko * All rights reserved. 4*27cf7d04SAleksandr Rybalko * 5*27cf7d04SAleksandr Rybalko * This software was developed by Ed Schouten under sponsorship from the 6*27cf7d04SAleksandr Rybalko * FreeBSD Foundation. 7*27cf7d04SAleksandr Rybalko * 8*27cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 9*27cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions 10*27cf7d04SAleksandr Rybalko * are met: 11*27cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 12*27cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 13*27cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 14*27cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 15*27cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 16*27cf7d04SAleksandr Rybalko * 17*27cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*27cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*27cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*27cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*27cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*27cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*27cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*27cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*27cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*27cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*27cf7d04SAleksandr Rybalko * SUCH DAMAGE. 28*27cf7d04SAleksandr Rybalko */ 29*27cf7d04SAleksandr Rybalko 30*27cf7d04SAleksandr Rybalko #include <sys/cdefs.h> 31*27cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$"); 32*27cf7d04SAleksandr Rybalko 33*27cf7d04SAleksandr Rybalko #include <sys/param.h> 34*27cf7d04SAleksandr Rybalko #include <sys/cons.h> 35*27cf7d04SAleksandr Rybalko #include <sys/consio.h> 36*27cf7d04SAleksandr Rybalko #include <sys/kernel.h> 37*27cf7d04SAleksandr Rybalko #include <sys/lock.h> 38*27cf7d04SAleksandr Rybalko #include <sys/malloc.h> 39*27cf7d04SAleksandr Rybalko #include <sys/mutex.h> 40*27cf7d04SAleksandr Rybalko #include <sys/systm.h> 41*27cf7d04SAleksandr Rybalko #include <sys/terminal.h> 42*27cf7d04SAleksandr Rybalko #include <sys/tty.h> 43*27cf7d04SAleksandr Rybalko 44*27cf7d04SAleksandr Rybalko #include <machine/stdarg.h> 45*27cf7d04SAleksandr Rybalko 46*27cf7d04SAleksandr Rybalko static MALLOC_DEFINE(M_TERMINAL, "terminal", "terminal device"); 47*27cf7d04SAleksandr Rybalko 48*27cf7d04SAleksandr Rybalko /* 49*27cf7d04SAleksandr Rybalko * Locking. 50*27cf7d04SAleksandr Rybalko * 51*27cf7d04SAleksandr Rybalko * Normally we don't need to lock down the terminal emulator, because 52*27cf7d04SAleksandr Rybalko * the TTY lock is already held when calling teken_input(). 53*27cf7d04SAleksandr Rybalko * Unfortunately this is not the case when the terminal acts as a 54*27cf7d04SAleksandr Rybalko * console device, because cnputc() can be called at the same time. 55*27cf7d04SAleksandr Rybalko * This means terminals may need to be locked down using a spin lock. 56*27cf7d04SAleksandr Rybalko */ 57*27cf7d04SAleksandr Rybalko #define TERMINAL_LOCK(tm) do { \ 58*27cf7d04SAleksandr Rybalko if ((tm)->tm_flags & TF_CONS) \ 59*27cf7d04SAleksandr Rybalko mtx_lock_spin(&(tm)->tm_mtx); \ 60*27cf7d04SAleksandr Rybalko else if ((tm)->tm_tty != NULL) \ 61*27cf7d04SAleksandr Rybalko tty_lock((tm)->tm_tty); \ 62*27cf7d04SAleksandr Rybalko } while (0) 63*27cf7d04SAleksandr Rybalko #define TERMINAL_UNLOCK(tm) do { \ 64*27cf7d04SAleksandr Rybalko if ((tm)->tm_flags & TF_CONS) \ 65*27cf7d04SAleksandr Rybalko mtx_unlock_spin(&(tm)->tm_mtx); \ 66*27cf7d04SAleksandr Rybalko else if ((tm)->tm_tty != NULL) \ 67*27cf7d04SAleksandr Rybalko tty_unlock((tm)->tm_tty); \ 68*27cf7d04SAleksandr Rybalko } while (0) 69*27cf7d04SAleksandr Rybalko #define TERMINAL_LOCK_TTY(tm) do { \ 70*27cf7d04SAleksandr Rybalko if ((tm)->tm_flags & TF_CONS) \ 71*27cf7d04SAleksandr Rybalko mtx_lock_spin(&(tm)->tm_mtx); \ 72*27cf7d04SAleksandr Rybalko } while (0) 73*27cf7d04SAleksandr Rybalko #define TERMINAL_UNLOCK_TTY(tm) do { \ 74*27cf7d04SAleksandr Rybalko if ((tm)->tm_flags & TF_CONS) \ 75*27cf7d04SAleksandr Rybalko mtx_unlock_spin(&(tm)->tm_mtx); \ 76*27cf7d04SAleksandr Rybalko } while (0) 77*27cf7d04SAleksandr Rybalko #define TERMINAL_LOCK_CONS(tm) mtx_lock_spin(&(tm)->tm_mtx) 78*27cf7d04SAleksandr Rybalko #define TERMINAL_UNLOCK_CONS(tm) mtx_unlock_spin(&(tm)->tm_mtx) 79*27cf7d04SAleksandr Rybalko 80*27cf7d04SAleksandr Rybalko /* 81*27cf7d04SAleksandr Rybalko * TTY routines. 82*27cf7d04SAleksandr Rybalko */ 83*27cf7d04SAleksandr Rybalko 84*27cf7d04SAleksandr Rybalko static tsw_open_t termtty_open; 85*27cf7d04SAleksandr Rybalko static tsw_close_t termtty_close; 86*27cf7d04SAleksandr Rybalko static tsw_outwakeup_t termtty_outwakeup; 87*27cf7d04SAleksandr Rybalko static tsw_ioctl_t termtty_ioctl; 88*27cf7d04SAleksandr Rybalko 89*27cf7d04SAleksandr Rybalko static struct ttydevsw terminal_tty_class = { 90*27cf7d04SAleksandr Rybalko .tsw_open = termtty_open, 91*27cf7d04SAleksandr Rybalko .tsw_close = termtty_close, 92*27cf7d04SAleksandr Rybalko .tsw_outwakeup = termtty_outwakeup, 93*27cf7d04SAleksandr Rybalko .tsw_ioctl = termtty_ioctl, 94*27cf7d04SAleksandr Rybalko }; 95*27cf7d04SAleksandr Rybalko 96*27cf7d04SAleksandr Rybalko /* 97*27cf7d04SAleksandr Rybalko * Terminal emulator routines. 98*27cf7d04SAleksandr Rybalko */ 99*27cf7d04SAleksandr Rybalko 100*27cf7d04SAleksandr Rybalko static tf_bell_t termteken_bell; 101*27cf7d04SAleksandr Rybalko static tf_cursor_t termteken_cursor; 102*27cf7d04SAleksandr Rybalko static tf_putchar_t termteken_putchar; 103*27cf7d04SAleksandr Rybalko static tf_fill_t termteken_fill; 104*27cf7d04SAleksandr Rybalko static tf_copy_t termteken_copy; 105*27cf7d04SAleksandr Rybalko static tf_param_t termteken_param; 106*27cf7d04SAleksandr Rybalko static tf_respond_t termteken_respond; 107*27cf7d04SAleksandr Rybalko 108*27cf7d04SAleksandr Rybalko static teken_funcs_t terminal_drawmethods = { 109*27cf7d04SAleksandr Rybalko .tf_bell = termteken_bell, 110*27cf7d04SAleksandr Rybalko .tf_cursor = termteken_cursor, 111*27cf7d04SAleksandr Rybalko .tf_putchar = termteken_putchar, 112*27cf7d04SAleksandr Rybalko .tf_fill = termteken_fill, 113*27cf7d04SAleksandr Rybalko .tf_copy = termteken_copy, 114*27cf7d04SAleksandr Rybalko .tf_param = termteken_param, 115*27cf7d04SAleksandr Rybalko .tf_respond = termteken_respond, 116*27cf7d04SAleksandr Rybalko }; 117*27cf7d04SAleksandr Rybalko 118*27cf7d04SAleksandr Rybalko /* Kernel message formatting. */ 119*27cf7d04SAleksandr Rybalko static const teken_attr_t kernel_message = { 120*27cf7d04SAleksandr Rybalko .ta_fgcolor = TC_WHITE, 121*27cf7d04SAleksandr Rybalko .ta_bgcolor = TC_BLACK, 122*27cf7d04SAleksandr Rybalko .ta_format = TF_BOLD, 123*27cf7d04SAleksandr Rybalko }; 124*27cf7d04SAleksandr Rybalko 125*27cf7d04SAleksandr Rybalko static const teken_attr_t default_message = { 126*27cf7d04SAleksandr Rybalko .ta_fgcolor = TC_WHITE, 127*27cf7d04SAleksandr Rybalko .ta_bgcolor = TC_BLACK, 128*27cf7d04SAleksandr Rybalko }; 129*27cf7d04SAleksandr Rybalko 130*27cf7d04SAleksandr Rybalko #define TCHAR_CREATE(c, a) ((c) | \ 131*27cf7d04SAleksandr Rybalko (a)->ta_format << 22 | \ 132*27cf7d04SAleksandr Rybalko teken_256to8((a)->ta_fgcolor) << 26 | \ 133*27cf7d04SAleksandr Rybalko teken_256to8((a)->ta_bgcolor) << 29) 134*27cf7d04SAleksandr Rybalko 135*27cf7d04SAleksandr Rybalko static void 136*27cf7d04SAleksandr Rybalko terminal_init(struct terminal *tm) 137*27cf7d04SAleksandr Rybalko { 138*27cf7d04SAleksandr Rybalko 139*27cf7d04SAleksandr Rybalko if (tm->tm_flags & TF_CONS) 140*27cf7d04SAleksandr Rybalko mtx_init(&tm->tm_mtx, "trmlck", NULL, MTX_SPIN); 141*27cf7d04SAleksandr Rybalko teken_init(&tm->tm_emulator, &terminal_drawmethods, tm); 142*27cf7d04SAleksandr Rybalko teken_set_defattr(&tm->tm_emulator, &default_message); 143*27cf7d04SAleksandr Rybalko } 144*27cf7d04SAleksandr Rybalko 145*27cf7d04SAleksandr Rybalko struct terminal * 146*27cf7d04SAleksandr Rybalko terminal_alloc(const struct terminal_class *tc, void *softc) 147*27cf7d04SAleksandr Rybalko { 148*27cf7d04SAleksandr Rybalko struct terminal *tm; 149*27cf7d04SAleksandr Rybalko 150*27cf7d04SAleksandr Rybalko tm = malloc(sizeof(struct terminal), M_TERMINAL, M_WAITOK|M_ZERO); 151*27cf7d04SAleksandr Rybalko terminal_init(tm); 152*27cf7d04SAleksandr Rybalko 153*27cf7d04SAleksandr Rybalko tm->tm_class = tc; 154*27cf7d04SAleksandr Rybalko tm->tm_softc = softc; 155*27cf7d04SAleksandr Rybalko 156*27cf7d04SAleksandr Rybalko return (tm); 157*27cf7d04SAleksandr Rybalko } 158*27cf7d04SAleksandr Rybalko 159*27cf7d04SAleksandr Rybalko static void 160*27cf7d04SAleksandr Rybalko terminal_sync_ttysize(struct terminal *tm) 161*27cf7d04SAleksandr Rybalko { 162*27cf7d04SAleksandr Rybalko struct tty *tp; 163*27cf7d04SAleksandr Rybalko 164*27cf7d04SAleksandr Rybalko tp = tm->tm_tty; 165*27cf7d04SAleksandr Rybalko if (tp == NULL) 166*27cf7d04SAleksandr Rybalko return; 167*27cf7d04SAleksandr Rybalko 168*27cf7d04SAleksandr Rybalko tty_lock(tp); 169*27cf7d04SAleksandr Rybalko tty_set_winsize(tp, &tm->tm_winsize); 170*27cf7d04SAleksandr Rybalko tty_unlock(tp); 171*27cf7d04SAleksandr Rybalko } 172*27cf7d04SAleksandr Rybalko 173*27cf7d04SAleksandr Rybalko void 174*27cf7d04SAleksandr Rybalko terminal_maketty(struct terminal *tm, const char *fmt, ...) 175*27cf7d04SAleksandr Rybalko { 176*27cf7d04SAleksandr Rybalko struct tty *tp; 177*27cf7d04SAleksandr Rybalko char name[8]; 178*27cf7d04SAleksandr Rybalko va_list ap; 179*27cf7d04SAleksandr Rybalko 180*27cf7d04SAleksandr Rybalko va_start(ap, fmt); 181*27cf7d04SAleksandr Rybalko vsnrprintf(name, sizeof name, 32, fmt, ap); 182*27cf7d04SAleksandr Rybalko va_end(ap); 183*27cf7d04SAleksandr Rybalko 184*27cf7d04SAleksandr Rybalko tp = tty_alloc(&terminal_tty_class, tm); 185*27cf7d04SAleksandr Rybalko tty_makedev(tp, NULL, "%s", name); 186*27cf7d04SAleksandr Rybalko tm->tm_tty = tp; 187*27cf7d04SAleksandr Rybalko terminal_sync_ttysize(tm); 188*27cf7d04SAleksandr Rybalko } 189*27cf7d04SAleksandr Rybalko 190*27cf7d04SAleksandr Rybalko void 191*27cf7d04SAleksandr Rybalko terminal_set_winsize_blank(struct terminal *tm, const struct winsize *size, 192*27cf7d04SAleksandr Rybalko int blank) 193*27cf7d04SAleksandr Rybalko { 194*27cf7d04SAleksandr Rybalko term_rect_t r; 195*27cf7d04SAleksandr Rybalko 196*27cf7d04SAleksandr Rybalko tm->tm_winsize = *size; 197*27cf7d04SAleksandr Rybalko 198*27cf7d04SAleksandr Rybalko r.tr_begin.tp_row = r.tr_begin.tp_col = 0; 199*27cf7d04SAleksandr Rybalko r.tr_end.tp_row = size->ws_row; 200*27cf7d04SAleksandr Rybalko r.tr_end.tp_col = size->ws_col; 201*27cf7d04SAleksandr Rybalko 202*27cf7d04SAleksandr Rybalko TERMINAL_LOCK(tm); 203*27cf7d04SAleksandr Rybalko if (blank == 0) 204*27cf7d04SAleksandr Rybalko teken_set_winsize_noreset(&tm->tm_emulator, &r.tr_end); 205*27cf7d04SAleksandr Rybalko else 206*27cf7d04SAleksandr Rybalko teken_set_winsize(&tm->tm_emulator, &r.tr_end); 207*27cf7d04SAleksandr Rybalko TERMINAL_UNLOCK(tm); 208*27cf7d04SAleksandr Rybalko 209*27cf7d04SAleksandr Rybalko if (blank != 0) 210*27cf7d04SAleksandr Rybalko tm->tm_class->tc_fill(tm, &r, TCHAR_CREATE((teken_char_t)' ', 211*27cf7d04SAleksandr Rybalko &default_message)); 212*27cf7d04SAleksandr Rybalko 213*27cf7d04SAleksandr Rybalko terminal_sync_ttysize(tm); 214*27cf7d04SAleksandr Rybalko } 215*27cf7d04SAleksandr Rybalko 216*27cf7d04SAleksandr Rybalko void 217*27cf7d04SAleksandr Rybalko terminal_set_winsize(struct terminal *tm, const struct winsize *size) 218*27cf7d04SAleksandr Rybalko { 219*27cf7d04SAleksandr Rybalko 220*27cf7d04SAleksandr Rybalko terminal_set_winsize_blank(tm, size, 1); 221*27cf7d04SAleksandr Rybalko } 222*27cf7d04SAleksandr Rybalko 223*27cf7d04SAleksandr Rybalko /* 224*27cf7d04SAleksandr Rybalko * XXX: This function is a kludge. Drivers like vt(4) need to 225*27cf7d04SAleksandr Rybalko * temporarily stop input when resizing, etc. This should ideally be 226*27cf7d04SAleksandr Rybalko * handled within the driver. 227*27cf7d04SAleksandr Rybalko */ 228*27cf7d04SAleksandr Rybalko 229*27cf7d04SAleksandr Rybalko void 230*27cf7d04SAleksandr Rybalko terminal_mute(struct terminal *tm, int yes) 231*27cf7d04SAleksandr Rybalko { 232*27cf7d04SAleksandr Rybalko 233*27cf7d04SAleksandr Rybalko TERMINAL_LOCK(tm); 234*27cf7d04SAleksandr Rybalko if (yes) 235*27cf7d04SAleksandr Rybalko tm->tm_flags |= TF_MUTE; 236*27cf7d04SAleksandr Rybalko else 237*27cf7d04SAleksandr Rybalko tm->tm_flags &= ~TF_MUTE; 238*27cf7d04SAleksandr Rybalko TERMINAL_UNLOCK(tm); 239*27cf7d04SAleksandr Rybalko } 240*27cf7d04SAleksandr Rybalko 241*27cf7d04SAleksandr Rybalko void 242*27cf7d04SAleksandr Rybalko terminal_input_char(struct terminal *tm, term_char_t c) 243*27cf7d04SAleksandr Rybalko { 244*27cf7d04SAleksandr Rybalko struct tty *tp; 245*27cf7d04SAleksandr Rybalko 246*27cf7d04SAleksandr Rybalko tp = tm->tm_tty; 247*27cf7d04SAleksandr Rybalko if (tp == NULL) 248*27cf7d04SAleksandr Rybalko return; 249*27cf7d04SAleksandr Rybalko 250*27cf7d04SAleksandr Rybalko /* Strip off any attributes. */ 251*27cf7d04SAleksandr Rybalko c = TCHAR_CHARACTER(c); 252*27cf7d04SAleksandr Rybalko 253*27cf7d04SAleksandr Rybalko tty_lock(tp); 254*27cf7d04SAleksandr Rybalko /* 255*27cf7d04SAleksandr Rybalko * Conversion to UTF-8. 256*27cf7d04SAleksandr Rybalko */ 257*27cf7d04SAleksandr Rybalko if (c < 0x80) { 258*27cf7d04SAleksandr Rybalko ttydisc_rint(tp, c, 0); 259*27cf7d04SAleksandr Rybalko } else if (c < 0x800) { 260*27cf7d04SAleksandr Rybalko char str[2] = { 261*27cf7d04SAleksandr Rybalko 0xc0 | (c >> 6), 262*27cf7d04SAleksandr Rybalko 0x80 | (c & 0x3f) 263*27cf7d04SAleksandr Rybalko }; 264*27cf7d04SAleksandr Rybalko 265*27cf7d04SAleksandr Rybalko ttydisc_rint_simple(tp, str, sizeof str); 266*27cf7d04SAleksandr Rybalko } else if (c < 0x10000) { 267*27cf7d04SAleksandr Rybalko char str[3] = { 268*27cf7d04SAleksandr Rybalko 0xe0 | (c >> 12), 269*27cf7d04SAleksandr Rybalko 0x80 | ((c >> 6) & 0x3f), 270*27cf7d04SAleksandr Rybalko 0x80 | (c & 0x3f) 271*27cf7d04SAleksandr Rybalko }; 272*27cf7d04SAleksandr Rybalko 273*27cf7d04SAleksandr Rybalko ttydisc_rint_simple(tp, str, sizeof str); 274*27cf7d04SAleksandr Rybalko } else { 275*27cf7d04SAleksandr Rybalko char str[4] = { 276*27cf7d04SAleksandr Rybalko 0xf0 | (c >> 18), 277*27cf7d04SAleksandr Rybalko 0x80 | ((c >> 12) & 0x3f), 278*27cf7d04SAleksandr Rybalko 0x80 | ((c >> 6) & 0x3f), 279*27cf7d04SAleksandr Rybalko 0x80 | (c & 0x3f) 280*27cf7d04SAleksandr Rybalko }; 281*27cf7d04SAleksandr Rybalko 282*27cf7d04SAleksandr Rybalko ttydisc_rint_simple(tp, str, sizeof str); 283*27cf7d04SAleksandr Rybalko } 284*27cf7d04SAleksandr Rybalko ttydisc_rint_done(tp); 285*27cf7d04SAleksandr Rybalko tty_unlock(tp); 286*27cf7d04SAleksandr Rybalko } 287*27cf7d04SAleksandr Rybalko 288*27cf7d04SAleksandr Rybalko void 289*27cf7d04SAleksandr Rybalko terminal_input_raw(struct terminal *tm, char c) 290*27cf7d04SAleksandr Rybalko { 291*27cf7d04SAleksandr Rybalko struct tty *tp; 292*27cf7d04SAleksandr Rybalko 293*27cf7d04SAleksandr Rybalko tp = tm->tm_tty; 294*27cf7d04SAleksandr Rybalko if (tp == NULL) 295*27cf7d04SAleksandr Rybalko return; 296*27cf7d04SAleksandr Rybalko 297*27cf7d04SAleksandr Rybalko tty_lock(tp); 298*27cf7d04SAleksandr Rybalko ttydisc_rint(tp, c, 0); 299*27cf7d04SAleksandr Rybalko ttydisc_rint_done(tp); 300*27cf7d04SAleksandr Rybalko tty_unlock(tp); 301*27cf7d04SAleksandr Rybalko } 302*27cf7d04SAleksandr Rybalko 303*27cf7d04SAleksandr Rybalko void 304*27cf7d04SAleksandr Rybalko terminal_input_special(struct terminal *tm, unsigned int k) 305*27cf7d04SAleksandr Rybalko { 306*27cf7d04SAleksandr Rybalko struct tty *tp; 307*27cf7d04SAleksandr Rybalko const char *str; 308*27cf7d04SAleksandr Rybalko 309*27cf7d04SAleksandr Rybalko tp = tm->tm_tty; 310*27cf7d04SAleksandr Rybalko if (tp == NULL) 311*27cf7d04SAleksandr Rybalko return; 312*27cf7d04SAleksandr Rybalko 313*27cf7d04SAleksandr Rybalko str = teken_get_sequence(&tm->tm_emulator, k); 314*27cf7d04SAleksandr Rybalko if (str == NULL) 315*27cf7d04SAleksandr Rybalko return; 316*27cf7d04SAleksandr Rybalko 317*27cf7d04SAleksandr Rybalko tty_lock(tp); 318*27cf7d04SAleksandr Rybalko ttydisc_rint_simple(tp, str, strlen(str)); 319*27cf7d04SAleksandr Rybalko ttydisc_rint_done(tp); 320*27cf7d04SAleksandr Rybalko tty_unlock(tp); 321*27cf7d04SAleksandr Rybalko } 322*27cf7d04SAleksandr Rybalko 323*27cf7d04SAleksandr Rybalko /* 324*27cf7d04SAleksandr Rybalko * Binding with the TTY layer. 325*27cf7d04SAleksandr Rybalko */ 326*27cf7d04SAleksandr Rybalko 327*27cf7d04SAleksandr Rybalko static int 328*27cf7d04SAleksandr Rybalko termtty_open(struct tty *tp) 329*27cf7d04SAleksandr Rybalko { 330*27cf7d04SAleksandr Rybalko struct terminal *tm = tty_softc(tp); 331*27cf7d04SAleksandr Rybalko 332*27cf7d04SAleksandr Rybalko tm->tm_class->tc_opened(tm, 1); 333*27cf7d04SAleksandr Rybalko return (0); 334*27cf7d04SAleksandr Rybalko } 335*27cf7d04SAleksandr Rybalko 336*27cf7d04SAleksandr Rybalko static void 337*27cf7d04SAleksandr Rybalko termtty_close(struct tty *tp) 338*27cf7d04SAleksandr Rybalko { 339*27cf7d04SAleksandr Rybalko struct terminal *tm = tty_softc(tp); 340*27cf7d04SAleksandr Rybalko 341*27cf7d04SAleksandr Rybalko tm->tm_class->tc_opened(tm, 0); 342*27cf7d04SAleksandr Rybalko } 343*27cf7d04SAleksandr Rybalko 344*27cf7d04SAleksandr Rybalko static void 345*27cf7d04SAleksandr Rybalko termtty_outwakeup(struct tty *tp) 346*27cf7d04SAleksandr Rybalko { 347*27cf7d04SAleksandr Rybalko struct terminal *tm = tty_softc(tp); 348*27cf7d04SAleksandr Rybalko char obuf[128]; 349*27cf7d04SAleksandr Rybalko size_t olen; 350*27cf7d04SAleksandr Rybalko unsigned int flags = 0; 351*27cf7d04SAleksandr Rybalko 352*27cf7d04SAleksandr Rybalko while ((olen = ttydisc_getc(tp, obuf, sizeof obuf)) > 0) { 353*27cf7d04SAleksandr Rybalko TERMINAL_LOCK_TTY(tm); 354*27cf7d04SAleksandr Rybalko if (!(tm->tm_flags & TF_MUTE)) { 355*27cf7d04SAleksandr Rybalko tm->tm_flags &= ~TF_BELL; 356*27cf7d04SAleksandr Rybalko teken_input(&tm->tm_emulator, obuf, olen); 357*27cf7d04SAleksandr Rybalko flags |= tm->tm_flags; 358*27cf7d04SAleksandr Rybalko } 359*27cf7d04SAleksandr Rybalko TERMINAL_UNLOCK_TTY(tm); 360*27cf7d04SAleksandr Rybalko } 361*27cf7d04SAleksandr Rybalko 362*27cf7d04SAleksandr Rybalko tm->tm_class->tc_done(tm); 363*27cf7d04SAleksandr Rybalko if (flags & TF_BELL) 364*27cf7d04SAleksandr Rybalko tm->tm_class->tc_bell(tm); 365*27cf7d04SAleksandr Rybalko } 366*27cf7d04SAleksandr Rybalko 367*27cf7d04SAleksandr Rybalko static int 368*27cf7d04SAleksandr Rybalko termtty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 369*27cf7d04SAleksandr Rybalko { 370*27cf7d04SAleksandr Rybalko struct terminal *tm = tty_softc(tp); 371*27cf7d04SAleksandr Rybalko int error; 372*27cf7d04SAleksandr Rybalko 373*27cf7d04SAleksandr Rybalko switch (cmd) { 374*27cf7d04SAleksandr Rybalko case CONS_GETINFO: { 375*27cf7d04SAleksandr Rybalko vid_info_t *vi = (vid_info_t *)data; 376*27cf7d04SAleksandr Rybalko const teken_pos_t *p; 377*27cf7d04SAleksandr Rybalko int fg, bg; 378*27cf7d04SAleksandr Rybalko 379*27cf7d04SAleksandr Rybalko if (vi->size != sizeof(vid_info_t)) 380*27cf7d04SAleksandr Rybalko return (EINVAL); 381*27cf7d04SAleksandr Rybalko 382*27cf7d04SAleksandr Rybalko /* Already help the console driver by filling in some data. */ 383*27cf7d04SAleksandr Rybalko p = teken_get_cursor(&tm->tm_emulator); 384*27cf7d04SAleksandr Rybalko vi->mv_row = p->tp_row; 385*27cf7d04SAleksandr Rybalko vi->mv_col = p->tp_col; 386*27cf7d04SAleksandr Rybalko 387*27cf7d04SAleksandr Rybalko p = teken_get_winsize(&tm->tm_emulator); 388*27cf7d04SAleksandr Rybalko vi->mv_rsz = p->tp_row; 389*27cf7d04SAleksandr Rybalko vi->mv_csz = p->tp_col; 390*27cf7d04SAleksandr Rybalko 391*27cf7d04SAleksandr Rybalko teken_get_defattr_cons25(&tm->tm_emulator, &fg, &bg); 392*27cf7d04SAleksandr Rybalko vi->mv_norm.fore = fg; 393*27cf7d04SAleksandr Rybalko vi->mv_norm.back = bg; 394*27cf7d04SAleksandr Rybalko /* XXX: keep vidcontrol happy; bold backgrounds. */ 395*27cf7d04SAleksandr Rybalko vi->mv_rev.fore = bg; 396*27cf7d04SAleksandr Rybalko vi->mv_rev.back = fg & 0x7; 397*27cf7d04SAleksandr Rybalko break; 398*27cf7d04SAleksandr Rybalko } 399*27cf7d04SAleksandr Rybalko } 400*27cf7d04SAleksandr Rybalko 401*27cf7d04SAleksandr Rybalko /* 402*27cf7d04SAleksandr Rybalko * Unlike various other drivers, this driver will never 403*27cf7d04SAleksandr Rybalko * deallocate TTYs. This means it's safe to temporarily unlock 404*27cf7d04SAleksandr Rybalko * the TTY when handling ioctls. 405*27cf7d04SAleksandr Rybalko */ 406*27cf7d04SAleksandr Rybalko tty_unlock(tp); 407*27cf7d04SAleksandr Rybalko error = tm->tm_class->tc_ioctl(tm, cmd, data, td); 408*27cf7d04SAleksandr Rybalko tty_lock(tp); 409*27cf7d04SAleksandr Rybalko return (error); 410*27cf7d04SAleksandr Rybalko } 411*27cf7d04SAleksandr Rybalko 412*27cf7d04SAleksandr Rybalko /* 413*27cf7d04SAleksandr Rybalko * Binding with the kernel and debug console. 414*27cf7d04SAleksandr Rybalko */ 415*27cf7d04SAleksandr Rybalko 416*27cf7d04SAleksandr Rybalko static cn_probe_t termcn_cnprobe; 417*27cf7d04SAleksandr Rybalko static cn_init_t termcn_cninit; 418*27cf7d04SAleksandr Rybalko static cn_term_t termcn_cnterm; 419*27cf7d04SAleksandr Rybalko static cn_getc_t termcn_cngetc; 420*27cf7d04SAleksandr Rybalko static cn_putc_t termcn_cnputc; 421*27cf7d04SAleksandr Rybalko static cn_grab_t termcn_cngrab; 422*27cf7d04SAleksandr Rybalko static cn_ungrab_t termcn_cnungrab; 423*27cf7d04SAleksandr Rybalko 424*27cf7d04SAleksandr Rybalko const struct consdev_ops termcn_cnops = { 425*27cf7d04SAleksandr Rybalko .cn_probe = termcn_cnprobe, 426*27cf7d04SAleksandr Rybalko .cn_init = termcn_cninit, 427*27cf7d04SAleksandr Rybalko .cn_term = termcn_cnterm, 428*27cf7d04SAleksandr Rybalko .cn_getc = termcn_cngetc, 429*27cf7d04SAleksandr Rybalko .cn_putc = termcn_cnputc, 430*27cf7d04SAleksandr Rybalko .cn_grab = termcn_cngrab, 431*27cf7d04SAleksandr Rybalko .cn_ungrab = termcn_cnungrab, 432*27cf7d04SAleksandr Rybalko }; 433*27cf7d04SAleksandr Rybalko 434*27cf7d04SAleksandr Rybalko void 435*27cf7d04SAleksandr Rybalko termcn_cnregister(struct terminal *tm) 436*27cf7d04SAleksandr Rybalko { 437*27cf7d04SAleksandr Rybalko struct consdev *cp; 438*27cf7d04SAleksandr Rybalko 439*27cf7d04SAleksandr Rybalko cp = tm->consdev; 440*27cf7d04SAleksandr Rybalko if (cp == NULL) { 441*27cf7d04SAleksandr Rybalko cp = malloc(sizeof(struct consdev), M_TERMINAL, 442*27cf7d04SAleksandr Rybalko M_WAITOK|M_ZERO); 443*27cf7d04SAleksandr Rybalko cp->cn_ops = &termcn_cnops; 444*27cf7d04SAleksandr Rybalko cp->cn_arg = tm; 445*27cf7d04SAleksandr Rybalko cp->cn_pri = CN_INTERNAL; 446*27cf7d04SAleksandr Rybalko sprintf(cp->cn_name, "ttyv0"); 447*27cf7d04SAleksandr Rybalko 448*27cf7d04SAleksandr Rybalko tm->tm_flags = TF_CONS; 449*27cf7d04SAleksandr Rybalko tm->consdev = cp; 450*27cf7d04SAleksandr Rybalko 451*27cf7d04SAleksandr Rybalko terminal_init(tm); 452*27cf7d04SAleksandr Rybalko } 453*27cf7d04SAleksandr Rybalko 454*27cf7d04SAleksandr Rybalko /* Attach terminal as console. */ 455*27cf7d04SAleksandr Rybalko cnadd(cp); 456*27cf7d04SAleksandr Rybalko } 457*27cf7d04SAleksandr Rybalko 458*27cf7d04SAleksandr Rybalko static void 459*27cf7d04SAleksandr Rybalko termcn_cngrab(struct consdev *cp) 460*27cf7d04SAleksandr Rybalko { 461*27cf7d04SAleksandr Rybalko 462*27cf7d04SAleksandr Rybalko } 463*27cf7d04SAleksandr Rybalko 464*27cf7d04SAleksandr Rybalko static void 465*27cf7d04SAleksandr Rybalko termcn_cnungrab(struct consdev *cp) 466*27cf7d04SAleksandr Rybalko { 467*27cf7d04SAleksandr Rybalko 468*27cf7d04SAleksandr Rybalko } 469*27cf7d04SAleksandr Rybalko 470*27cf7d04SAleksandr Rybalko static void 471*27cf7d04SAleksandr Rybalko termcn_cnprobe(struct consdev *cp) 472*27cf7d04SAleksandr Rybalko { 473*27cf7d04SAleksandr Rybalko struct terminal *tm = cp->cn_arg; 474*27cf7d04SAleksandr Rybalko 475*27cf7d04SAleksandr Rybalko if (tm == NULL) { 476*27cf7d04SAleksandr Rybalko cp->cn_pri = CN_DEAD; 477*27cf7d04SAleksandr Rybalko return; 478*27cf7d04SAleksandr Rybalko } 479*27cf7d04SAleksandr Rybalko 480*27cf7d04SAleksandr Rybalko tm->consdev = cp; 481*27cf7d04SAleksandr Rybalko terminal_init(tm); 482*27cf7d04SAleksandr Rybalko 483*27cf7d04SAleksandr Rybalko tm->tm_class->tc_cnprobe(tm, cp); 484*27cf7d04SAleksandr Rybalko } 485*27cf7d04SAleksandr Rybalko 486*27cf7d04SAleksandr Rybalko static void 487*27cf7d04SAleksandr Rybalko termcn_cninit(struct consdev *cp) 488*27cf7d04SAleksandr Rybalko { 489*27cf7d04SAleksandr Rybalko 490*27cf7d04SAleksandr Rybalko } 491*27cf7d04SAleksandr Rybalko 492*27cf7d04SAleksandr Rybalko static void 493*27cf7d04SAleksandr Rybalko termcn_cnterm(struct consdev *cp) 494*27cf7d04SAleksandr Rybalko { 495*27cf7d04SAleksandr Rybalko 496*27cf7d04SAleksandr Rybalko } 497*27cf7d04SAleksandr Rybalko 498*27cf7d04SAleksandr Rybalko static int 499*27cf7d04SAleksandr Rybalko termcn_cngetc(struct consdev *cp) 500*27cf7d04SAleksandr Rybalko { 501*27cf7d04SAleksandr Rybalko struct terminal *tm = cp->cn_arg; 502*27cf7d04SAleksandr Rybalko 503*27cf7d04SAleksandr Rybalko return (tm->tm_class->tc_cngetc(tm)); 504*27cf7d04SAleksandr Rybalko } 505*27cf7d04SAleksandr Rybalko 506*27cf7d04SAleksandr Rybalko static void 507*27cf7d04SAleksandr Rybalko termcn_cnputc(struct consdev *cp, int c) 508*27cf7d04SAleksandr Rybalko { 509*27cf7d04SAleksandr Rybalko struct terminal *tm = cp->cn_arg; 510*27cf7d04SAleksandr Rybalko teken_attr_t backup; 511*27cf7d04SAleksandr Rybalko char cv = c; 512*27cf7d04SAleksandr Rybalko 513*27cf7d04SAleksandr Rybalko TERMINAL_LOCK_CONS(tm); 514*27cf7d04SAleksandr Rybalko if (!(tm->tm_flags & TF_MUTE)) { 515*27cf7d04SAleksandr Rybalko backup = *teken_get_curattr(&tm->tm_emulator); 516*27cf7d04SAleksandr Rybalko teken_set_curattr(&tm->tm_emulator, &kernel_message); 517*27cf7d04SAleksandr Rybalko teken_input(&tm->tm_emulator, &cv, 1); 518*27cf7d04SAleksandr Rybalko teken_set_curattr(&tm->tm_emulator, &backup); 519*27cf7d04SAleksandr Rybalko } 520*27cf7d04SAleksandr Rybalko TERMINAL_UNLOCK_CONS(tm); 521*27cf7d04SAleksandr Rybalko 522*27cf7d04SAleksandr Rybalko tm->tm_class->tc_done(tm); 523*27cf7d04SAleksandr Rybalko } 524*27cf7d04SAleksandr Rybalko 525*27cf7d04SAleksandr Rybalko /* 526*27cf7d04SAleksandr Rybalko * Binding with the terminal emulator. 527*27cf7d04SAleksandr Rybalko */ 528*27cf7d04SAleksandr Rybalko 529*27cf7d04SAleksandr Rybalko static void 530*27cf7d04SAleksandr Rybalko termteken_bell(void *softc) 531*27cf7d04SAleksandr Rybalko { 532*27cf7d04SAleksandr Rybalko struct terminal *tm = softc; 533*27cf7d04SAleksandr Rybalko 534*27cf7d04SAleksandr Rybalko tm->tm_flags |= TF_BELL; 535*27cf7d04SAleksandr Rybalko } 536*27cf7d04SAleksandr Rybalko 537*27cf7d04SAleksandr Rybalko static void 538*27cf7d04SAleksandr Rybalko termteken_cursor(void *softc, const teken_pos_t *p) 539*27cf7d04SAleksandr Rybalko { 540*27cf7d04SAleksandr Rybalko struct terminal *tm = softc; 541*27cf7d04SAleksandr Rybalko 542*27cf7d04SAleksandr Rybalko tm->tm_class->tc_cursor(tm, p); 543*27cf7d04SAleksandr Rybalko } 544*27cf7d04SAleksandr Rybalko 545*27cf7d04SAleksandr Rybalko static void 546*27cf7d04SAleksandr Rybalko termteken_putchar(void *softc, const teken_pos_t *p, teken_char_t c, 547*27cf7d04SAleksandr Rybalko const teken_attr_t *a) 548*27cf7d04SAleksandr Rybalko { 549*27cf7d04SAleksandr Rybalko struct terminal *tm = softc; 550*27cf7d04SAleksandr Rybalko 551*27cf7d04SAleksandr Rybalko tm->tm_class->tc_putchar(tm, p, TCHAR_CREATE(c, a)); 552*27cf7d04SAleksandr Rybalko } 553*27cf7d04SAleksandr Rybalko 554*27cf7d04SAleksandr Rybalko static void 555*27cf7d04SAleksandr Rybalko termteken_fill(void *softc, const teken_rect_t *r, teken_char_t c, 556*27cf7d04SAleksandr Rybalko const teken_attr_t *a) 557*27cf7d04SAleksandr Rybalko { 558*27cf7d04SAleksandr Rybalko struct terminal *tm = softc; 559*27cf7d04SAleksandr Rybalko 560*27cf7d04SAleksandr Rybalko tm->tm_class->tc_fill(tm, r, TCHAR_CREATE(c, a)); 561*27cf7d04SAleksandr Rybalko } 562*27cf7d04SAleksandr Rybalko 563*27cf7d04SAleksandr Rybalko static void 564*27cf7d04SAleksandr Rybalko termteken_copy(void *softc, const teken_rect_t *r, const teken_pos_t *p) 565*27cf7d04SAleksandr Rybalko { 566*27cf7d04SAleksandr Rybalko struct terminal *tm = softc; 567*27cf7d04SAleksandr Rybalko 568*27cf7d04SAleksandr Rybalko tm->tm_class->tc_copy(tm, r, p); 569*27cf7d04SAleksandr Rybalko } 570*27cf7d04SAleksandr Rybalko 571*27cf7d04SAleksandr Rybalko static void 572*27cf7d04SAleksandr Rybalko termteken_param(void *softc, int cmd, unsigned int arg) 573*27cf7d04SAleksandr Rybalko { 574*27cf7d04SAleksandr Rybalko struct terminal *tm = softc; 575*27cf7d04SAleksandr Rybalko 576*27cf7d04SAleksandr Rybalko tm->tm_class->tc_param(tm, cmd, arg); 577*27cf7d04SAleksandr Rybalko } 578*27cf7d04SAleksandr Rybalko 579*27cf7d04SAleksandr Rybalko static void 580*27cf7d04SAleksandr Rybalko termteken_respond(void *softc, const void *buf, size_t len) 581*27cf7d04SAleksandr Rybalko { 582*27cf7d04SAleksandr Rybalko #if 0 583*27cf7d04SAleksandr Rybalko struct terminal *tm = softc; 584*27cf7d04SAleksandr Rybalko struct tty *tp; 585*27cf7d04SAleksandr Rybalko 586*27cf7d04SAleksandr Rybalko /* 587*27cf7d04SAleksandr Rybalko * Only inject a response into the TTY if the data actually 588*27cf7d04SAleksandr Rybalko * originated from the TTY. 589*27cf7d04SAleksandr Rybalko * 590*27cf7d04SAleksandr Rybalko * XXX: This cannot be done right now. The TTY could pick up 591*27cf7d04SAleksandr Rybalko * other locks. It could also in theory cause loops, when the 592*27cf7d04SAleksandr Rybalko * TTY performs echoing of a command that generates even more 593*27cf7d04SAleksandr Rybalko * input. 594*27cf7d04SAleksandr Rybalko */ 595*27cf7d04SAleksandr Rybalko tp = tm->tm_tty; 596*27cf7d04SAleksandr Rybalko if (tp == NULL) 597*27cf7d04SAleksandr Rybalko return; 598*27cf7d04SAleksandr Rybalko 599*27cf7d04SAleksandr Rybalko ttydisc_rint_simple(tp, buf, len); 600*27cf7d04SAleksandr Rybalko ttydisc_rint_done(tp); 601*27cf7d04SAleksandr Rybalko #endif 602*27cf7d04SAleksandr Rybalko } 603