1*fea9cb91Slq150181 /* 2*fea9cb91Slq150181 * CDDL HEADER START 3*fea9cb91Slq150181 * 4*fea9cb91Slq150181 * The contents of this file are subject to the terms of the 5*fea9cb91Slq150181 * Common Development and Distribution License (the "License"). 6*fea9cb91Slq150181 * You may not use this file except in compliance with the License. 7*fea9cb91Slq150181 * 8*fea9cb91Slq150181 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*fea9cb91Slq150181 * or http://www.opensolaris.org/os/licensing. 10*fea9cb91Slq150181 * See the License for the specific language governing permissions 11*fea9cb91Slq150181 * and limitations under the License. 12*fea9cb91Slq150181 * 13*fea9cb91Slq150181 * When distributing Covered Code, include this CDDL HEADER in each 14*fea9cb91Slq150181 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*fea9cb91Slq150181 * If applicable, add the following below this CDDL HEADER, with the 16*fea9cb91Slq150181 * fields enclosed by brackets "[]" replaced with your own identifying 17*fea9cb91Slq150181 * information: Portions Copyright [yyyy] [name of copyright owner] 18*fea9cb91Slq150181 * 19*fea9cb91Slq150181 * CDDL HEADER END 20*fea9cb91Slq150181 */ 21*fea9cb91Slq150181 22*fea9cb91Slq150181 /* 23*fea9cb91Slq150181 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*fea9cb91Slq150181 * Use is subject to license terms. 25*fea9cb91Slq150181 */ 26*fea9cb91Slq150181 27*fea9cb91Slq150181 #pragma ident "%Z%%M% %I% %E% SMI" 28*fea9cb91Slq150181 29*fea9cb91Slq150181 /* 30*fea9cb91Slq150181 * ANSI terminal emulator module; parse ANSI X3.64 escape sequences and 31*fea9cb91Slq150181 * the like. 32*fea9cb91Slq150181 */ 33*fea9cb91Slq150181 34*fea9cb91Slq150181 #include <sys/types.h> 35*fea9cb91Slq150181 #include <sys/file.h> 36*fea9cb91Slq150181 #include <sys/conf.h> 37*fea9cb91Slq150181 #include <sys/errno.h> 38*fea9cb91Slq150181 #include <sys/open.h> 39*fea9cb91Slq150181 #include <sys/cred.h> 40*fea9cb91Slq150181 #include <sys/cred_impl.h> 41*fea9cb91Slq150181 #include <sys/kmem.h> 42*fea9cb91Slq150181 #include <sys/ascii.h> 43*fea9cb91Slq150181 #include <sys/consdev.h> 44*fea9cb91Slq150181 #include <sys/font.h> 45*fea9cb91Slq150181 #include <sys/fbio.h> 46*fea9cb91Slq150181 #include <sys/conf.h> 47*fea9cb91Slq150181 #include <sys/modctl.h> 48*fea9cb91Slq150181 #include <sys/strsubr.h> 49*fea9cb91Slq150181 #include <sys/stat.h> 50*fea9cb91Slq150181 #include <sys/visual_io.h> 51*fea9cb91Slq150181 #include <sys/mutex.h> 52*fea9cb91Slq150181 #include <sys/param.h> 53*fea9cb91Slq150181 #include <sys/debug.h> 54*fea9cb91Slq150181 #include <sys/cmn_err.h> 55*fea9cb91Slq150181 #include <sys/console.h> 56*fea9cb91Slq150181 #include <sys/ddi.h> 57*fea9cb91Slq150181 #include <sys/sunddi.h> 58*fea9cb91Slq150181 #include <sys/sunldi.h> 59*fea9cb91Slq150181 #include <sys/tem_impl.h> 60*fea9cb91Slq150181 #include <sys/tem.h> 61*fea9cb91Slq150181 #ifdef _HAVE_TEM_FIRMWARE 62*fea9cb91Slq150181 #include <sys/promif.h> 63*fea9cb91Slq150181 #endif /* _HAVE_TEM_FIRMWARE */ 64*fea9cb91Slq150181 #include <sys/consconfig_dacf.h> 65*fea9cb91Slq150181 66*fea9cb91Slq150181 /* Terminal emulator functions */ 67*fea9cb91Slq150181 static int tem_setup_terminal(struct vis_devinit *, tem_t *, 68*fea9cb91Slq150181 size_t, size_t); 69*fea9cb91Slq150181 static void tem_modechange_callback(tem_t *, struct vis_devinit *); 70*fea9cb91Slq150181 static void tem_free(tem_t *); 71*fea9cb91Slq150181 72*fea9cb91Slq150181 static int tem_adjust_row(tem_t *, int, cred_t *); 73*fea9cb91Slq150181 74*fea9cb91Slq150181 /* 75*fea9cb91Slq150181 * Globals 76*fea9cb91Slq150181 */ 77*fea9cb91Slq150181 ldi_ident_t term_li = NULL; 78*fea9cb91Slq150181 79*fea9cb91Slq150181 80*fea9cb91Slq150181 extern struct mod_ops mod_miscops; 81*fea9cb91Slq150181 82*fea9cb91Slq150181 static struct modlmisc modlmisc = { 83*fea9cb91Slq150181 &mod_miscops, /* modops */ 84*fea9cb91Slq150181 "ANSI Terminal Emulator", /* name */ 85*fea9cb91Slq150181 }; 86*fea9cb91Slq150181 87*fea9cb91Slq150181 static struct modlinkage modlinkage = { 88*fea9cb91Slq150181 MODREV_1, (void *)&modlmisc, NULL 89*fea9cb91Slq150181 }; 90*fea9cb91Slq150181 91*fea9cb91Slq150181 int 92*fea9cb91Slq150181 _init(void) 93*fea9cb91Slq150181 { 94*fea9cb91Slq150181 int ret; 95*fea9cb91Slq150181 ret = mod_install(&modlinkage); 96*fea9cb91Slq150181 if (ret != 0) 97*fea9cb91Slq150181 return (ret); 98*fea9cb91Slq150181 ret = ldi_ident_from_mod(&modlinkage, &term_li); 99*fea9cb91Slq150181 if (ret != 0) { 100*fea9cb91Slq150181 (void) mod_remove(&modlinkage); 101*fea9cb91Slq150181 return (ret); 102*fea9cb91Slq150181 } 103*fea9cb91Slq150181 return (0); 104*fea9cb91Slq150181 } 105*fea9cb91Slq150181 106*fea9cb91Slq150181 int 107*fea9cb91Slq150181 _fini() 108*fea9cb91Slq150181 { 109*fea9cb91Slq150181 int ret; 110*fea9cb91Slq150181 111*fea9cb91Slq150181 ret = mod_remove(&modlinkage); 112*fea9cb91Slq150181 if (ret == 0) { 113*fea9cb91Slq150181 ldi_ident_release(term_li); 114*fea9cb91Slq150181 term_li = NULL; 115*fea9cb91Slq150181 } 116*fea9cb91Slq150181 return (ret); 117*fea9cb91Slq150181 } 118*fea9cb91Slq150181 119*fea9cb91Slq150181 int 120*fea9cb91Slq150181 _info(struct modinfo *modinfop) 121*fea9cb91Slq150181 { 122*fea9cb91Slq150181 return (mod_info(&modlinkage, modinfop)); 123*fea9cb91Slq150181 } 124*fea9cb91Slq150181 125*fea9cb91Slq150181 int 126*fea9cb91Slq150181 tem_fini(tem_t *tem) 127*fea9cb91Slq150181 { 128*fea9cb91Slq150181 int lyr_rval; 129*fea9cb91Slq150181 130*fea9cb91Slq150181 mutex_enter(&tem->lock); 131*fea9cb91Slq150181 132*fea9cb91Slq150181 ASSERT(tem->hdl != NULL); 133*fea9cb91Slq150181 134*fea9cb91Slq150181 /* 135*fea9cb91Slq150181 * Allow layered on driver to clean up console private 136*fea9cb91Slq150181 * data. 137*fea9cb91Slq150181 */ 138*fea9cb91Slq150181 (void) ldi_ioctl(tem->hdl, VIS_DEVFINI, 139*fea9cb91Slq150181 0, FKIOCTL, kcred, &lyr_rval); 140*fea9cb91Slq150181 141*fea9cb91Slq150181 /* 142*fea9cb91Slq150181 * Close layered on driver 143*fea9cb91Slq150181 */ 144*fea9cb91Slq150181 (void) ldi_close(tem->hdl, NULL, kcred); 145*fea9cb91Slq150181 tem->hdl = NULL; 146*fea9cb91Slq150181 147*fea9cb91Slq150181 mutex_exit(&tem->lock); 148*fea9cb91Slq150181 149*fea9cb91Slq150181 tem_free(tem); 150*fea9cb91Slq150181 151*fea9cb91Slq150181 return (0); 152*fea9cb91Slq150181 } 153*fea9cb91Slq150181 154*fea9cb91Slq150181 static int 155*fea9cb91Slq150181 tem_init_failed(tem_t *tem, cred_t *credp, boolean_t finish_ioctl) 156*fea9cb91Slq150181 { 157*fea9cb91Slq150181 int lyr_rval; 158*fea9cb91Slq150181 159*fea9cb91Slq150181 if (finish_ioctl) 160*fea9cb91Slq150181 (void) ldi_ioctl(tem->hdl, VIS_DEVFINI, 0, FWRITE|FKIOCTL, 161*fea9cb91Slq150181 credp, &lyr_rval); 162*fea9cb91Slq150181 163*fea9cb91Slq150181 (void) ldi_close(tem->hdl, NULL, credp); 164*fea9cb91Slq150181 tem_free(tem); 165*fea9cb91Slq150181 return (ENXIO); 166*fea9cb91Slq150181 } 167*fea9cb91Slq150181 168*fea9cb91Slq150181 static void 169*fea9cb91Slq150181 tem_free_state(struct tem_state *tems) 170*fea9cb91Slq150181 { 171*fea9cb91Slq150181 ASSERT(tems != NULL); 172*fea9cb91Slq150181 173*fea9cb91Slq150181 if (tems->a_outbuf != NULL) 174*fea9cb91Slq150181 kmem_free(tems->a_outbuf, 175*fea9cb91Slq150181 tems->a_c_dimension.width); 176*fea9cb91Slq150181 if (tems->a_blank_line != NULL) 177*fea9cb91Slq150181 kmem_free(tems->a_blank_line, 178*fea9cb91Slq150181 tems->a_c_dimension.width); 179*fea9cb91Slq150181 if (tems->a_pix_data != NULL) 180*fea9cb91Slq150181 kmem_free(tems->a_pix_data, 181*fea9cb91Slq150181 tems->a_pix_data_size); 182*fea9cb91Slq150181 kmem_free(tems, sizeof (struct tem_state)); 183*fea9cb91Slq150181 } 184*fea9cb91Slq150181 185*fea9cb91Slq150181 static void 186*fea9cb91Slq150181 tem_free(tem_t *tem) 187*fea9cb91Slq150181 { 188*fea9cb91Slq150181 ASSERT(tem != NULL); 189*fea9cb91Slq150181 190*fea9cb91Slq150181 if (tem->state != NULL) 191*fea9cb91Slq150181 tem_free_state(tem->state); 192*fea9cb91Slq150181 193*fea9cb91Slq150181 kmem_free(tem, sizeof (struct tem)); 194*fea9cb91Slq150181 } 195*fea9cb91Slq150181 196*fea9cb91Slq150181 /* 197*fea9cb91Slq150181 * This is the main entry point to the module. It handles output requests 198*fea9cb91Slq150181 * during normal system operation, when (e.g.) mutexes are available. 199*fea9cb91Slq150181 */ 200*fea9cb91Slq150181 void 201*fea9cb91Slq150181 tem_write(tem_t *tem, uchar_t *buf, ssize_t len, cred_t *credp) 202*fea9cb91Slq150181 { 203*fea9cb91Slq150181 mutex_enter(&tem->lock); 204*fea9cb91Slq150181 205*fea9cb91Slq150181 ASSERT(tem->hdl != NULL); 206*fea9cb91Slq150181 207*fea9cb91Slq150181 tem_check_first_time(tem, credp, CALLED_FROM_NORMAL); 208*fea9cb91Slq150181 tem_terminal_emulate(tem, buf, len, credp, CALLED_FROM_NORMAL); 209*fea9cb91Slq150181 210*fea9cb91Slq150181 mutex_exit(&tem->lock); 211*fea9cb91Slq150181 } 212*fea9cb91Slq150181 213*fea9cb91Slq150181 int 214*fea9cb91Slq150181 tem_init(tem_t **ptem, char *pathname, cred_t *credp) 215*fea9cb91Slq150181 { 216*fea9cb91Slq150181 struct vis_devinit devinit; 217*fea9cb91Slq150181 tem_t *tem; 218*fea9cb91Slq150181 size_t height = 0; 219*fea9cb91Slq150181 size_t width = 0; 220*fea9cb91Slq150181 uint32_t row = 0; 221*fea9cb91Slq150181 uint32_t col = 0; 222*fea9cb91Slq150181 char *pathbuf; 223*fea9cb91Slq150181 int err = 0; 224*fea9cb91Slq150181 int lyr_rval; 225*fea9cb91Slq150181 226*fea9cb91Slq150181 tem = kmem_zalloc(sizeof (struct tem), KM_SLEEP); 227*fea9cb91Slq150181 228*fea9cb91Slq150181 mutex_init(&tem->lock, (char *)NULL, MUTEX_DRIVER, NULL); 229*fea9cb91Slq150181 230*fea9cb91Slq150181 #ifdef _HAVE_TEM_FIRMWARE 231*fea9cb91Slq150181 tem->cons_wrtvec = tem_write; 232*fea9cb91Slq150181 #endif /* _HAVE_TEM_FIRMWARE */ 233*fea9cb91Slq150181 234*fea9cb91Slq150181 /* 235*fea9cb91Slq150181 * Open the layered device using the devfs physical device name 236*fea9cb91Slq150181 * after adding the /devices prefix. 237*fea9cb91Slq150181 */ 238*fea9cb91Slq150181 pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 239*fea9cb91Slq150181 (void) strcpy(pathbuf, "/devices"); 240*fea9cb91Slq150181 if (i_ddi_prompath_to_devfspath(pathname, 241*fea9cb91Slq150181 pathbuf + strlen("/devices")) != DDI_SUCCESS) { 242*fea9cb91Slq150181 cmn_err(CE_WARN, "terminal emulator: Path conversion error"); 243*fea9cb91Slq150181 kmem_free(pathbuf, MAXPATHLEN); 244*fea9cb91Slq150181 tem_free(tem); 245*fea9cb91Slq150181 return (ENXIO); 246*fea9cb91Slq150181 } 247*fea9cb91Slq150181 if (ldi_open_by_name(pathbuf, FWRITE, credp, &tem->hdl, term_li) != 0) { 248*fea9cb91Slq150181 cmn_err(CE_WARN, "terminal emulator: Device path open error"); 249*fea9cb91Slq150181 kmem_free(pathbuf, MAXPATHLEN); 250*fea9cb91Slq150181 tem_free(tem); 251*fea9cb91Slq150181 return (ENXIO); 252*fea9cb91Slq150181 } 253*fea9cb91Slq150181 kmem_free(pathbuf, MAXPATHLEN); 254*fea9cb91Slq150181 255*fea9cb91Slq150181 devinit.modechg_cb = (vis_modechg_cb_t)tem_modechange_callback; 256*fea9cb91Slq150181 devinit.modechg_arg = (struct vis_modechg_arg *)tem; 257*fea9cb91Slq150181 258*fea9cb91Slq150181 /* 259*fea9cb91Slq150181 * Initialize the console and get the device parameters 260*fea9cb91Slq150181 */ 261*fea9cb91Slq150181 if ((err = ldi_ioctl(tem->hdl, VIS_DEVINIT, 262*fea9cb91Slq150181 (intptr_t)&devinit, FWRITE|FKIOCTL, credp, &lyr_rval)) != 0) { 263*fea9cb91Slq150181 cmn_err(CE_WARN, "terminal emulator: Compatible fb not found"); 264*fea9cb91Slq150181 return (tem_init_failed(tem, credp, B_FALSE)); 265*fea9cb91Slq150181 } 266*fea9cb91Slq150181 267*fea9cb91Slq150181 /* Make sure the fb driver and terminal emulator versions match */ 268*fea9cb91Slq150181 if (devinit.version != VIS_CONS_REV) { 269*fea9cb91Slq150181 cmn_err(CE_WARN, 270*fea9cb91Slq150181 "terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) " 271*fea9cb91Slq150181 "of console fb driver not supported", devinit.version); 272*fea9cb91Slq150181 return (tem_init_failed(tem, credp, B_TRUE)); 273*fea9cb91Slq150181 } 274*fea9cb91Slq150181 275*fea9cb91Slq150181 if ((tem->fb_polledio = devinit.polledio) == NULL) { 276*fea9cb91Slq150181 cmn_err(CE_WARN, "terminal emulator: fb doesn't support polled " 277*fea9cb91Slq150181 "I/O"); 278*fea9cb91Slq150181 return (tem_init_failed(tem, credp, B_TRUE)); 279*fea9cb91Slq150181 } 280*fea9cb91Slq150181 281*fea9cb91Slq150181 /* other sanity checks */ 282*fea9cb91Slq150181 if (!((devinit.depth == 4) || (devinit.depth == 8) || 283*fea9cb91Slq150181 (devinit.depth == 24) || (devinit.depth == 32))) { 284*fea9cb91Slq150181 cmn_err(CE_WARN, "terminal emulator: unsupported depth"); 285*fea9cb91Slq150181 return (tem_init_failed(tem, credp, B_TRUE)); 286*fea9cb91Slq150181 } 287*fea9cb91Slq150181 288*fea9cb91Slq150181 if ((devinit.mode != VIS_TEXT) && (devinit.mode != VIS_PIXEL)) { 289*fea9cb91Slq150181 cmn_err(CE_WARN, "terminal emulator: unsupported mode"); 290*fea9cb91Slq150181 return (tem_init_failed(tem, credp, B_TRUE)); 291*fea9cb91Slq150181 } 292*fea9cb91Slq150181 293*fea9cb91Slq150181 if ((devinit.mode == VIS_PIXEL) && plat_stdout_is_framebuffer()) { 294*fea9cb91Slq150181 plat_tem_get_prom_size(&height, &width); 295*fea9cb91Slq150181 } 296*fea9cb91Slq150181 297*fea9cb91Slq150181 /* 298*fea9cb91Slq150181 * Initialize the terminal emulator 299*fea9cb91Slq150181 */ 300*fea9cb91Slq150181 mutex_enter(&tem->lock); 301*fea9cb91Slq150181 if ((err = tem_setup_terminal(&devinit, tem, height, width)) != 0) { 302*fea9cb91Slq150181 cmn_err(CE_WARN, "terminal emulator: Init failed"); 303*fea9cb91Slq150181 (void) ldi_ioctl(tem->hdl, VIS_DEVFINI, 0, FWRITE|FKIOCTL, 304*fea9cb91Slq150181 credp, &lyr_rval); 305*fea9cb91Slq150181 (void) ldi_close(tem->hdl, NULL, credp); 306*fea9cb91Slq150181 mutex_exit(&tem->lock); 307*fea9cb91Slq150181 tem_free(tem); 308*fea9cb91Slq150181 return (err); 309*fea9cb91Slq150181 } 310*fea9cb91Slq150181 311*fea9cb91Slq150181 /* 312*fea9cb91Slq150181 * On SPARC don't clear the screen if the console is the framebuffer. 313*fea9cb91Slq150181 * Otherwise it needs to be cleared to get rid of junk that may be 314*fea9cb91Slq150181 * in frameuffer memory, since the screen isn't cleared when 315*fea9cb91Slq150181 * boot messages are directed elsewhere. 316*fea9cb91Slq150181 */ 317*fea9cb91Slq150181 if (devinit.mode == VIS_TEXT) { 318*fea9cb91Slq150181 /* 319*fea9cb91Slq150181 * The old getting current cursor position code, which 320*fea9cb91Slq150181 * is not needed here, has been in tem_write/tem_polled_write. 321*fea9cb91Slq150181 */ 322*fea9cb91Slq150181 tem_reset_display(tem, credp, CALLED_FROM_NORMAL, 0); 323*fea9cb91Slq150181 } else if (plat_stdout_is_framebuffer()) { 324*fea9cb91Slq150181 ASSERT(devinit.mode == VIS_PIXEL); 325*fea9cb91Slq150181 plat_tem_hide_prom_cursor(); 326*fea9cb91Slq150181 tem_reset_display(tem, credp, CALLED_FROM_NORMAL, 0); 327*fea9cb91Slq150181 328*fea9cb91Slq150181 /* 329*fea9cb91Slq150181 * We are getting the current cursor position in pixel 330*fea9cb91Slq150181 * mode so that we don't over-write the console output 331*fea9cb91Slq150181 * during boot. 332*fea9cb91Slq150181 */ 333*fea9cb91Slq150181 plat_tem_get_prom_pos(&row, &col); 334*fea9cb91Slq150181 335*fea9cb91Slq150181 /* 336*fea9cb91Slq150181 * Adjust the row if necessary when the font of our 337*fea9cb91Slq150181 * kernel console tem is different with that of prom 338*fea9cb91Slq150181 * tem. 339*fea9cb91Slq150181 */ 340*fea9cb91Slq150181 row = tem_adjust_row(tem, row, credp); 341*fea9cb91Slq150181 342*fea9cb91Slq150181 /* first line of our kernel console output */ 343*fea9cb91Slq150181 tem->state->first_line = row + 1; 344*fea9cb91Slq150181 345*fea9cb91Slq150181 /* re-set and align cusror position */ 346*fea9cb91Slq150181 tem->state->a_c_cursor.row = row; 347*fea9cb91Slq150181 tem->state->a_c_cursor.col = 0; 348*fea9cb91Slq150181 tem_align_cursor(tem); 349*fea9cb91Slq150181 } else { 350*fea9cb91Slq150181 tem_reset_display(tem, credp, CALLED_FROM_NORMAL, 1); 351*fea9cb91Slq150181 } 352*fea9cb91Slq150181 353*fea9cb91Slq150181 #ifdef _HAVE_TEM_FIRMWARE 354*fea9cb91Slq150181 if (plat_stdout_is_framebuffer()) { 355*fea9cb91Slq150181 /* 356*fea9cb91Slq150181 * Drivers in the console stream may emit additional 357*fea9cb91Slq150181 * messages before we are ready. This causes text 358*fea9cb91Slq150181 * overwrite on the screen. So we set the redirection 359*fea9cb91Slq150181 * here. It is safe because the ioctl in consconfig_dacf 360*fea9cb91Slq150181 * will succeed and consmode will be set to CONS_KFB. 361*fea9cb91Slq150181 */ 362*fea9cb91Slq150181 prom_set_stdout_redirect(console_prom_write_cb, 363*fea9cb91Slq150181 (promif_redir_arg_t)tem); 364*fea9cb91Slq150181 365*fea9cb91Slq150181 } 366*fea9cb91Slq150181 #endif /* _HAVE_TEM_FIRMWARE */ 367*fea9cb91Slq150181 368*fea9cb91Slq150181 mutex_exit(&tem->lock); 369*fea9cb91Slq150181 *ptem = tem; /* Return tem to caller only upon success */ 370*fea9cb91Slq150181 return (0); 371*fea9cb91Slq150181 } 372*fea9cb91Slq150181 373*fea9cb91Slq150181 /* 374*fea9cb91Slq150181 * This is a callback function that we register with the frame 375*fea9cb91Slq150181 * buffer driver layered underneath. It gets invoked from 376*fea9cb91Slq150181 * the underlying frame buffer driver to reconfigure the terminal 377*fea9cb91Slq150181 * emulator to a new screen size and depth in conjunction with 378*fea9cb91Slq150181 * framebuffer videomode changes. 379*fea9cb91Slq150181 */ 380*fea9cb91Slq150181 void 381*fea9cb91Slq150181 tem_modechange_callback(tem_t *tem, struct vis_devinit *devinit) 382*fea9cb91Slq150181 { 383*fea9cb91Slq150181 mutex_enter(&tem->lock); 384*fea9cb91Slq150181 385*fea9cb91Slq150181 ASSERT(tem->hdl != NULL); 386*fea9cb91Slq150181 387*fea9cb91Slq150181 (void) tem_setup_terminal(devinit, tem, 388*fea9cb91Slq150181 tem->state->a_c_dimension.height, 389*fea9cb91Slq150181 tem->state->a_c_dimension.width); 390*fea9cb91Slq150181 391*fea9cb91Slq150181 tem_reset_display(tem, kcred, CALLED_FROM_NORMAL, 1); 392*fea9cb91Slq150181 393*fea9cb91Slq150181 mutex_exit(&tem->lock); 394*fea9cb91Slq150181 395*fea9cb91Slq150181 if (tem->modechg_cb != NULL) 396*fea9cb91Slq150181 tem->modechg_cb(tem->modechg_arg); 397*fea9cb91Slq150181 } 398*fea9cb91Slq150181 399*fea9cb91Slq150181 static int 400*fea9cb91Slq150181 tem_setup_terminal( 401*fea9cb91Slq150181 struct vis_devinit *devinit, 402*fea9cb91Slq150181 tem_t *tem, 403*fea9cb91Slq150181 size_t height, size_t width) 404*fea9cb91Slq150181 { 405*fea9cb91Slq150181 int i; 406*fea9cb91Slq150181 struct tem_state *new_state, *prev_state; 407*fea9cb91Slq150181 408*fea9cb91Slq150181 ASSERT(MUTEX_HELD(&tem->lock)); 409*fea9cb91Slq150181 410*fea9cb91Slq150181 prev_state = tem->state; 411*fea9cb91Slq150181 412*fea9cb91Slq150181 new_state = kmem_zalloc(sizeof (struct tem_state), KM_SLEEP); 413*fea9cb91Slq150181 414*fea9cb91Slq150181 new_state->a_pdepth = devinit->depth; 415*fea9cb91Slq150181 new_state->display_mode = devinit->mode; 416*fea9cb91Slq150181 new_state->linebytes = devinit->linebytes; 417*fea9cb91Slq150181 418*fea9cb91Slq150181 switch (devinit->mode) { 419*fea9cb91Slq150181 case VIS_TEXT: 420*fea9cb91Slq150181 new_state->a_p_dimension.width = 0; 421*fea9cb91Slq150181 new_state->a_p_dimension.height = 0; 422*fea9cb91Slq150181 new_state->a_c_dimension.width = devinit->width; 423*fea9cb91Slq150181 new_state->a_c_dimension.height = devinit->height; 424*fea9cb91Slq150181 425*fea9cb91Slq150181 new_state->in_fp.f_display = tem_text_display; 426*fea9cb91Slq150181 new_state->in_fp.f_copy = tem_text_copy; 427*fea9cb91Slq150181 new_state->in_fp.f_cursor = tem_text_cursor; 428*fea9cb91Slq150181 new_state->in_fp.f_cls = tem_text_cls; 429*fea9cb91Slq150181 new_state->in_fp.f_bit2pix = NULL; 430*fea9cb91Slq150181 431*fea9cb91Slq150181 new_state->a_blank_line = 432*fea9cb91Slq150181 kmem_alloc(new_state->a_c_dimension.width, KM_SLEEP); 433*fea9cb91Slq150181 434*fea9cb91Slq150181 for (i = 0; i < new_state->a_c_dimension.width; i++) 435*fea9cb91Slq150181 new_state->a_blank_line[i] = ' '; 436*fea9cb91Slq150181 437*fea9cb91Slq150181 break; 438*fea9cb91Slq150181 case VIS_PIXEL: 439*fea9cb91Slq150181 440*fea9cb91Slq150181 /* 441*fea9cb91Slq150181 * First check to see if the user has specified a screen size. 442*fea9cb91Slq150181 * If so, use those values. Else use 34x80 as the default. 443*fea9cb91Slq150181 */ 444*fea9cb91Slq150181 if (width == 0) { 445*fea9cb91Slq150181 width = TEM_DEFAULT_COLS; 446*fea9cb91Slq150181 height = TEM_DEFAULT_ROWS; 447*fea9cb91Slq150181 } 448*fea9cb91Slq150181 new_state->a_c_dimension.height = height; 449*fea9cb91Slq150181 new_state->a_c_dimension.width = width; 450*fea9cb91Slq150181 451*fea9cb91Slq150181 new_state->a_p_dimension.height = devinit->height; 452*fea9cb91Slq150181 new_state->a_p_dimension.width = devinit->width; 453*fea9cb91Slq150181 454*fea9cb91Slq150181 new_state->in_fp.f_display = tem_pix_display; 455*fea9cb91Slq150181 new_state->in_fp.f_copy = tem_pix_copy; 456*fea9cb91Slq150181 new_state->in_fp.f_cursor = tem_pix_cursor; 457*fea9cb91Slq150181 new_state->in_fp.f_cls = tem_pix_cls; 458*fea9cb91Slq150181 459*fea9cb91Slq150181 new_state->a_blank_line = NULL; 460*fea9cb91Slq150181 461*fea9cb91Slq150181 /* 462*fea9cb91Slq150181 * set_font() will select a appropriate sized font for 463*fea9cb91Slq150181 * the number of rows and columns selected. If we don't 464*fea9cb91Slq150181 * have a font that will fit, then it will use the 465*fea9cb91Slq150181 * default builtin font and adjust the rows and columns 466*fea9cb91Slq150181 * to fit on the screen. 467*fea9cb91Slq150181 */ 468*fea9cb91Slq150181 set_font(&new_state->a_font, 469*fea9cb91Slq150181 &new_state->a_c_dimension.height, 470*fea9cb91Slq150181 &new_state->a_c_dimension.width, 471*fea9cb91Slq150181 new_state->a_p_dimension.height, 472*fea9cb91Slq150181 new_state->a_p_dimension.width); 473*fea9cb91Slq150181 474*fea9cb91Slq150181 new_state->a_p_offset.y = 475*fea9cb91Slq150181 (new_state->a_p_dimension.height - 476*fea9cb91Slq150181 (new_state->a_c_dimension.height * 477*fea9cb91Slq150181 new_state->a_font.height)) / 2; 478*fea9cb91Slq150181 479*fea9cb91Slq150181 new_state->a_p_offset.x = 480*fea9cb91Slq150181 (new_state->a_p_dimension.width - 481*fea9cb91Slq150181 (new_state->a_c_dimension.width * 482*fea9cb91Slq150181 new_state->a_font.width)) / 2; 483*fea9cb91Slq150181 484*fea9cb91Slq150181 switch (devinit->depth) { 485*fea9cb91Slq150181 case 4: 486*fea9cb91Slq150181 new_state->in_fp.f_bit2pix = bit_to_pix4; 487*fea9cb91Slq150181 new_state->a_pix_data_size = 488*fea9cb91Slq150181 (((new_state->a_font.width * 4) + 489*fea9cb91Slq150181 NBBY - 1) / NBBY) * new_state->a_font.height; 490*fea9cb91Slq150181 break; 491*fea9cb91Slq150181 case 8: 492*fea9cb91Slq150181 new_state->in_fp.f_bit2pix = bit_to_pix8; 493*fea9cb91Slq150181 new_state->a_pix_data_size = 494*fea9cb91Slq150181 new_state->a_font.width * 495*fea9cb91Slq150181 new_state->a_font.height; 496*fea9cb91Slq150181 break; 497*fea9cb91Slq150181 case 24: 498*fea9cb91Slq150181 case 32: 499*fea9cb91Slq150181 new_state->in_fp.f_bit2pix = bit_to_pix24; 500*fea9cb91Slq150181 new_state->a_pix_data_size = 501*fea9cb91Slq150181 new_state->a_font.width * 502*fea9cb91Slq150181 new_state->a_font.height; 503*fea9cb91Slq150181 new_state->a_pix_data_size *= 4; 504*fea9cb91Slq150181 break; 505*fea9cb91Slq150181 } 506*fea9cb91Slq150181 507*fea9cb91Slq150181 new_state->a_pix_data = 508*fea9cb91Slq150181 kmem_alloc(new_state->a_pix_data_size, KM_SLEEP); 509*fea9cb91Slq150181 510*fea9cb91Slq150181 break; 511*fea9cb91Slq150181 512*fea9cb91Slq150181 default: 513*fea9cb91Slq150181 /* 514*fea9cb91Slq150181 * The layered fb driver conveyed an unrecognized rendering 515*fea9cb91Slq150181 * mode. We cannot proceed with tem initialization. 516*fea9cb91Slq150181 */ 517*fea9cb91Slq150181 kmem_free(new_state, sizeof (struct tem_state)); 518*fea9cb91Slq150181 return (ENXIO); 519*fea9cb91Slq150181 } 520*fea9cb91Slq150181 521*fea9cb91Slq150181 new_state->a_outbuf = 522*fea9cb91Slq150181 kmem_alloc(new_state->a_c_dimension.width, KM_SLEEP); 523*fea9cb91Slq150181 524*fea9cb91Slq150181 /* 525*fea9cb91Slq150181 * Change state atomically so that polled I/O requests 526*fea9cb91Slq150181 * can be safely and reliably serviced anytime after the terminal 527*fea9cb91Slq150181 * emulator is originally initialized and the console mode has been 528*fea9cb91Slq150181 * switched over from the PROM, even while a videomode change 529*fea9cb91Slq150181 * callback is being processed. 530*fea9cb91Slq150181 */ 531*fea9cb91Slq150181 tem->state = new_state; 532*fea9cb91Slq150181 533*fea9cb91Slq150181 if (prev_state != NULL) 534*fea9cb91Slq150181 tem_free_state(prev_state); 535*fea9cb91Slq150181 536*fea9cb91Slq150181 return (0); 537*fea9cb91Slq150181 } 538*fea9cb91Slq150181 539*fea9cb91Slq150181 /* 540*fea9cb91Slq150181 * This function is used to display a rectangular blit of data 541*fea9cb91Slq150181 * of a given size and location via the underlying framebuffer driver. 542*fea9cb91Slq150181 * The blit can be as small as a pixel or as large as the screen. 543*fea9cb91Slq150181 */ 544*fea9cb91Slq150181 void 545*fea9cb91Slq150181 tem_display_layered( 546*fea9cb91Slq150181 tem_t *tem, 547*fea9cb91Slq150181 struct vis_consdisplay *pda, 548*fea9cb91Slq150181 cred_t *credp) 549*fea9cb91Slq150181 { 550*fea9cb91Slq150181 int rval; 551*fea9cb91Slq150181 552*fea9cb91Slq150181 (void) ldi_ioctl(tem->hdl, VIS_CONSDISPLAY, 553*fea9cb91Slq150181 (intptr_t)pda, FKIOCTL, credp, &rval); 554*fea9cb91Slq150181 } 555*fea9cb91Slq150181 556*fea9cb91Slq150181 /* 557*fea9cb91Slq150181 * This function is used to invoke a block copy operation in the 558*fea9cb91Slq150181 * underlying framebuffer driver. Rectangle copies are how scrolling 559*fea9cb91Slq150181 * is implemented, as well as horizontal text shifting escape seqs. 560*fea9cb91Slq150181 * such as from vi when deleting characters and words. 561*fea9cb91Slq150181 */ 562*fea9cb91Slq150181 void 563*fea9cb91Slq150181 tem_copy_layered( 564*fea9cb91Slq150181 tem_t *tem, 565*fea9cb91Slq150181 struct vis_conscopy *pma, 566*fea9cb91Slq150181 cred_t *credp) 567*fea9cb91Slq150181 { 568*fea9cb91Slq150181 int rval; 569*fea9cb91Slq150181 570*fea9cb91Slq150181 (void) ldi_ioctl(tem->hdl, VIS_CONSCOPY, 571*fea9cb91Slq150181 (intptr_t)pma, FKIOCTL, credp, &rval); 572*fea9cb91Slq150181 } 573*fea9cb91Slq150181 574*fea9cb91Slq150181 /* 575*fea9cb91Slq150181 * This function is used to show or hide a rectangluar monochrom 576*fea9cb91Slq150181 * pixel inverting, text block cursor via the underlying framebuffer. 577*fea9cb91Slq150181 */ 578*fea9cb91Slq150181 void 579*fea9cb91Slq150181 tem_cursor_layered( 580*fea9cb91Slq150181 tem_t *tem, 581*fea9cb91Slq150181 struct vis_conscursor *pca, 582*fea9cb91Slq150181 cred_t *credp) 583*fea9cb91Slq150181 { 584*fea9cb91Slq150181 int rval; 585*fea9cb91Slq150181 586*fea9cb91Slq150181 (void) ldi_ioctl(tem->hdl, VIS_CONSCURSOR, 587*fea9cb91Slq150181 (intptr_t)pca, FKIOCTL, credp, &rval); 588*fea9cb91Slq150181 } 589*fea9cb91Slq150181 590*fea9cb91Slq150181 void 591*fea9cb91Slq150181 tem_reset_colormap( 592*fea9cb91Slq150181 tem_t *tem, 593*fea9cb91Slq150181 cred_t *credp, 594*fea9cb91Slq150181 enum called_from called_from) 595*fea9cb91Slq150181 { 596*fea9cb91Slq150181 struct vis_cmap cm; 597*fea9cb91Slq150181 int rval; 598*fea9cb91Slq150181 599*fea9cb91Slq150181 if (called_from == CALLED_FROM_STANDALONE) 600*fea9cb91Slq150181 return; 601*fea9cb91Slq150181 602*fea9cb91Slq150181 switch (tem->state->a_pdepth) { 603*fea9cb91Slq150181 case 8: 604*fea9cb91Slq150181 cm.index = 0; 605*fea9cb91Slq150181 cm.count = 16; 606*fea9cb91Slq150181 cm.red = cmap4_to_24.red; /* 8-bits (1/3 of TrueColor 24) */ 607*fea9cb91Slq150181 cm.blue = cmap4_to_24.blue; /* 8-bits (1/3 of TrueColor 24) */ 608*fea9cb91Slq150181 cm.green = cmap4_to_24.green; /* 8-bits (1/3 of TrueColor 24) */ 609*fea9cb91Slq150181 (void) ldi_ioctl(tem->hdl, VIS_PUTCMAP, (intptr_t)&cm, 610*fea9cb91Slq150181 FKIOCTL, credp, &rval); 611*fea9cb91Slq150181 break; 612*fea9cb91Slq150181 } 613*fea9cb91Slq150181 } 614*fea9cb91Slq150181 615*fea9cb91Slq150181 void 616*fea9cb91Slq150181 tem_get_size(tem_t *tem, ushort_t *r, ushort_t *c, 617*fea9cb91Slq150181 ushort_t *x, ushort_t *y) 618*fea9cb91Slq150181 { 619*fea9cb91Slq150181 *r = (ushort_t)tem->state->a_c_dimension.height; 620*fea9cb91Slq150181 *c = (ushort_t)tem->state->a_c_dimension.width; 621*fea9cb91Slq150181 *x = (ushort_t)tem->state->a_p_dimension.width; 622*fea9cb91Slq150181 *y = (ushort_t)tem->state->a_p_dimension.height; 623*fea9cb91Slq150181 } 624*fea9cb91Slq150181 625*fea9cb91Slq150181 void 626*fea9cb91Slq150181 tem_register_modechg_cb(tem_t *tem, tem_modechg_cb_t func, 627*fea9cb91Slq150181 tem_modechg_cb_arg_t arg) 628*fea9cb91Slq150181 { 629*fea9cb91Slq150181 tem->modechg_cb = func; 630*fea9cb91Slq150181 tem->modechg_arg = arg; 631*fea9cb91Slq150181 } 632*fea9cb91Slq150181 633*fea9cb91Slq150181 /* 634*fea9cb91Slq150181 * This function is to scroll up the OBP output, which has 635*fea9cb91Slq150181 * different screen height and width with our kernel console. 636*fea9cb91Slq150181 */ 637*fea9cb91Slq150181 static void 638*fea9cb91Slq150181 tem_prom_scroll_up(struct tem *tem, int nrows, cred_t *credp) 639*fea9cb91Slq150181 { 640*fea9cb91Slq150181 struct tem_state *tems = tem->state; 641*fea9cb91Slq150181 struct vis_conscopy ma; 642*fea9cb91Slq150181 int ncols, width; 643*fea9cb91Slq150181 644*fea9cb91Slq150181 /* copy */ 645*fea9cb91Slq150181 ma.s_row = nrows * tems->a_font.height; 646*fea9cb91Slq150181 ma.e_row = tems->a_p_dimension.height - 1; 647*fea9cb91Slq150181 ma.t_row = 0; 648*fea9cb91Slq150181 649*fea9cb91Slq150181 ma.s_col = 0; 650*fea9cb91Slq150181 ma.e_col = tems->a_p_dimension.width - 1; 651*fea9cb91Slq150181 ma.t_col = 0; 652*fea9cb91Slq150181 653*fea9cb91Slq150181 tem_copy(tem, &ma, credp, CALLED_FROM_NORMAL); 654*fea9cb91Slq150181 655*fea9cb91Slq150181 /* clear */ 656*fea9cb91Slq150181 width = tems->a_font.width; 657*fea9cb91Slq150181 ncols = (tems->a_p_dimension.width + 658*fea9cb91Slq150181 (width - 1))/ width; 659*fea9cb91Slq150181 660*fea9cb91Slq150181 tem_pix_cls_range(tem, 661*fea9cb91Slq150181 0, nrows, tems->a_p_offset.y, 662*fea9cb91Slq150181 0, ncols, 0, 663*fea9cb91Slq150181 B_TRUE, credp, CALLED_FROM_NORMAL); 664*fea9cb91Slq150181 } 665*fea9cb91Slq150181 666*fea9cb91Slq150181 #define PROM_DEFAULT_FONT_HEIGHT 22 667*fea9cb91Slq150181 #define PROM_DEFAULT_WINDOW_TOP 0x8a 668*fea9cb91Slq150181 669*fea9cb91Slq150181 /* 670*fea9cb91Slq150181 * This function is to compute the starting row of the console, according to 671*fea9cb91Slq150181 * PROM cursor's position. Here we have to take different fonts into account. 672*fea9cb91Slq150181 */ 673*fea9cb91Slq150181 static int 674*fea9cb91Slq150181 tem_adjust_row(tem_t *tem, int prom_row, cred_t *credp) 675*fea9cb91Slq150181 { 676*fea9cb91Slq150181 int tem_row; 677*fea9cb91Slq150181 int tem_y; 678*fea9cb91Slq150181 int prom_charheight = 0; 679*fea9cb91Slq150181 int prom_window_top = 0; 680*fea9cb91Slq150181 int scroll_up_lines; 681*fea9cb91Slq150181 682*fea9cb91Slq150181 plat_tem_get_prom_font_size(&prom_charheight, &prom_window_top); 683*fea9cb91Slq150181 if (prom_charheight == 0) 684*fea9cb91Slq150181 prom_charheight = PROM_DEFAULT_FONT_HEIGHT; 685*fea9cb91Slq150181 if (prom_window_top == 0) 686*fea9cb91Slq150181 prom_window_top = PROM_DEFAULT_WINDOW_TOP; 687*fea9cb91Slq150181 688*fea9cb91Slq150181 tem_y = (prom_row + 1) * prom_charheight + prom_window_top - 689*fea9cb91Slq150181 tem->state->a_p_offset.y; 690*fea9cb91Slq150181 tem_row = (tem_y + tem->state->a_font.height - 1) / 691*fea9cb91Slq150181 tem->state->a_font.height - 1; 692*fea9cb91Slq150181 693*fea9cb91Slq150181 if (tem_row < 0) { 694*fea9cb91Slq150181 tem_row = 0; 695*fea9cb91Slq150181 } else if (tem_row >= (tem->state->a_c_dimension.height - 1)) { 696*fea9cb91Slq150181 /* 697*fea9cb91Slq150181 * Scroll up the prom outputs if the PROM cursor's position is 698*fea9cb91Slq150181 * below our tem's lower boundary. 699*fea9cb91Slq150181 */ 700*fea9cb91Slq150181 scroll_up_lines = tem_row - 701*fea9cb91Slq150181 (tem->state->a_c_dimension.height - 1); 702*fea9cb91Slq150181 tem_prom_scroll_up(tem, scroll_up_lines, credp); 703*fea9cb91Slq150181 tem_row = tem->state->a_c_dimension.height - 1; 704*fea9cb91Slq150181 } 705*fea9cb91Slq150181 706*fea9cb91Slq150181 return (tem_row); 707*fea9cb91Slq150181 } 708