1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1987, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2019 Toomas Soome <tsoome@me.com> 25 */ 26 27 /* 28 * "Workstation console" multiplexor driver for Sun. 29 * 30 * Sends output to the primary frame buffer using the PROM monitor; 31 * gets input from a stream linked below us that is the "keyboard 32 * driver", below which is linked the primary keyboard. 33 */ 34 35 /* 36 * Locking Policy: 37 * This module has a D_MTPERMOD inner perimeter which means STREAMS 38 * only allows one thread to enter this module through STREAMS entry 39 * points each time -- open() close() put() srv() qtimeout(). 40 * So for the most time we do not need locking in this module, but with 41 * the following exceptions: 42 * 43 * - wc shares three global variables (wc_dip, vc_active_console, 44 * vc_cons_user, vc_avl_root) with virtual console devname part 45 * (fs/dev/sdev_vtops.c) which get compiled into genunix. 46 * 47 * - wc_modechg_cb() is a callback function which will triggered when 48 * framebuffer display mode is changed. 49 * 50 * - vt_send_hotkeys() is triggered by timeout() which is not STREAMS MT 51 * safe. 52 * 53 * Based on the fact that virtual console devname part and wc_modechg_cb() 54 * only do read access to the above mentioned shared four global variables, 55 * It is safe to do locking this way: 56 * 1) all read access to the four global variables in THIS WC MODULE do not 57 * need locking; 58 * 2) all write access to the four global variables in THIS WC MODULE must 59 * hold vc_lock; 60 * 3) any access to the four global variables in either DEVNAME PART or the 61 * CALLBACK must hold vc_lock; 62 * 4) other global variables which are only shared in this wc module and only 63 * accessible through STREAMS entry points such as "vc_last_console", 64 * "vc_inuse_max_minor", "vc_target_console" and "vc_waitactive_list" 65 * do not need explict locking. 66 * 67 * wc_modechg_cb() does read access to vc_state_t::vc_flags, 68 * vc_state_t::vc_state_lock is used to protect concurrently accesses to 69 * vc_state_t::vc_flags which may happen from both through STREAMS entry 70 * points and wc_modechg_cb(). 71 * Since wc_modechg_cb() only does read access to vc_state_t::vc_flags, 72 * The other parts of wc module (except wc_modechg_cb()) only has to hold 73 * vc_state_t::vc_flags when writing to vc_state_t::vc_flags. 74 * 75 * vt_send_hotkeys() could access vt_pending_vtno at the same time with 76 * the rest of wc module, vt_pending_vtno_lock is used to protect 77 * vt_pending_vtno. 78 * 79 * Lock order: vc_lock -> vc_state_t::vc_state_lock. 80 * No overlap between vc_lock and vt_pending_vtno_lock. 81 */ 82 83 #include <sys/types.h> 84 #include <sys/param.h> 85 #include <sys/signal.h> 86 #include <sys/cred.h> 87 #include <sys/vnode.h> 88 #include <sys/termios.h> 89 #include <sys/termio.h> 90 #include <sys/ttold.h> 91 #include <sys/stropts.h> 92 #include <sys/stream.h> 93 #include <sys/strsun.h> 94 #include <sys/tty.h> 95 #include <sys/buf.h> 96 #include <sys/uio.h> 97 #include <sys/stat.h> 98 #include <sys/sysmacros.h> 99 #include <sys/errno.h> 100 #include <sys/proc.h> 101 #include <sys/procset.h> 102 #include <sys/fault.h> 103 #include <sys/siginfo.h> 104 #include <sys/debug.h> 105 #include <sys/session.h> 106 #include <sys/kmem.h> 107 #include <sys/cpuvar.h> 108 #include <sys/kbio.h> 109 #include <sys/strredir.h> 110 #include <sys/fs/snode.h> 111 #include <sys/consdev.h> 112 #include <sys/conf.h> 113 #include <sys/cmn_err.h> 114 #include <sys/console.h> 115 #include <sys/promif.h> 116 #include <sys/note.h> 117 #include <sys/polled_io.h> 118 #include <sys/systm.h> 119 #include <sys/ddi.h> 120 #include <sys/sunddi.h> 121 #include <sys/sunndi.h> 122 #include <sys/esunddi.h> 123 #include <sys/sunldi.h> 124 #include <sys/debug.h> 125 #include <sys/console.h> 126 #include <sys/ddi_impldefs.h> 127 #include <sys/policy.h> 128 #include <sys/modctl.h> 129 #include <sys/tem.h> 130 #include <sys/wscons.h> 131 #include <sys/vt_impl.h> 132 133 /* streams stuff */ 134 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", copyreq)) 135 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", copyresp)) 136 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", datab)) 137 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", iocblk)) 138 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", msgb)) 139 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", queue)) 140 141 #define MINLINES 10 142 #define MAXLINES 48 143 #define LOSCREENLINES 34 144 #define HISCREENLINES 48 145 146 #define MINCOLS 10 147 #define MAXCOLS 120 148 #define LOSCREENCOLS 80 149 #define HISCREENCOLS 120 150 151 struct wscons_state { 152 dev_t wc_dev; /* major/minor for this device */ 153 #ifdef _HAVE_TEM_FIRMWARE 154 int wc_defer_output; /* set if output device is "slow" */ 155 #endif /* _HAVE_TEM_FIRMWARE */ 156 queue_t *wc_kbdqueue; /* "console keyboard" device queue */ 157 /* below us */ 158 cons_polledio_t wc_polledio; /* polled I/O function pointers */ 159 cons_polledio_t *wc_kb_polledio; /* keyboard's polledio */ 160 unsigned int wc_kb_getpolledio_id; /* id for kb CONSOPENPOLLEDIO */ 161 queue_t *wc_pending_wq; 162 mblk_t *wc_pending_link; /* I_PLINK pending for kb polledio */ 163 } wscons; 164 165 /* 166 * This module has a D_MTPERMOD inner perimeter, so we don't need to protect 167 * the variables only shared within this module 168 */ 169 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", wscons)) 170 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", wscons_state)) 171 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vt_stat)) 172 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_waitactive_msg)) 173 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", tty_common)) 174 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vt_mode)) 175 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vt_dispinfo)) 176 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", winsize)) 177 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_last_console)) 178 179 #ifdef _HAVE_TEM_FIRMWARE 180 ssize_t wc_cons_wrtvec(promif_redir_arg_t arg, uchar_t *s, size_t n); 181 #endif /* _HAVE_TEM_FIRMWARE */ 182 183 static int wcopen(queue_t *, dev_t *, int, int, cred_t *); 184 static int wcclose(queue_t *, int, cred_t *); 185 static int wcuwsrv(queue_t *); 186 static int wcuwput(queue_t *, mblk_t *); 187 static int wclrput(queue_t *, mblk_t *); 188 189 static struct module_info wcm_info = { 190 0, 191 "wc", 192 0, 193 INFPSZ, 194 2048, 195 128 196 }; 197 198 static struct qinit wcurinit = { 199 putq, 200 NULL, 201 wcopen, 202 wcclose, 203 NULL, 204 &wcm_info, 205 NULL 206 }; 207 208 static struct qinit wcuwinit = { 209 wcuwput, 210 wcuwsrv, 211 wcopen, 212 wcclose, 213 NULL, 214 &wcm_info, 215 NULL 216 }; 217 218 static struct qinit wclrinit = { 219 wclrput, 220 NULL, 221 NULL, 222 NULL, 223 NULL, 224 &wcm_info, 225 NULL 226 }; 227 228 /* 229 * We always putnext directly to the underlying queue. 230 */ 231 static struct qinit wclwinit = { 232 NULL, 233 NULL, 234 NULL, 235 NULL, 236 NULL, 237 &wcm_info, 238 NULL 239 }; 240 241 static struct streamtab wcinfo = { 242 &wcurinit, 243 &wcuwinit, 244 &wclrinit, 245 &wclwinit, 246 }; 247 248 static int wc_info(dev_info_t *, ddi_info_cmd_t, void *, void **result); 249 static int wc_attach(dev_info_t *, ddi_attach_cmd_t); 250 251 DDI_DEFINE_STREAM_OPS(wc_ops, nulldev, nulldev, wc_attach, nodev, nodev, 252 wc_info, D_MTPERMOD | D_MP, &wcinfo, ddi_quiesce_not_supported); 253 254 static void wcreioctl(void *); 255 static void wcioctl(queue_t *, mblk_t *); 256 #ifdef _HAVE_TEM_FIRMWARE 257 static void wcopoll(void *); 258 #endif /* _HAVE_TEM_FIRMWARE */ 259 static void wcrstrt(void *); 260 static void wc_open_kb_polledio(struct wscons_state *wc, queue_t *q, 261 mblk_t *mp); 262 static void wc_close_kb_polledio(struct wscons_state *wc, queue_t *q, 263 mblk_t *mp); 264 static void wc_polled_putchar(cons_polledio_arg_t arg, 265 unsigned char c); 266 static boolean_t wc_polled_ischar(cons_polledio_arg_t arg); 267 static int wc_polled_getchar(cons_polledio_arg_t arg); 268 static void wc_polled_enter(cons_polledio_arg_t arg); 269 static void wc_polled_exit(cons_polledio_arg_t arg); 270 void wc_get_size(vc_state_t *pvc); 271 static void wc_modechg_cb(tem_modechg_cb_arg_t arg); 272 static tem_vt_state_t wc_get_screen_tem(vc_state_t *); 273 274 static struct dev_ops wc_ops; 275 276 /* 277 * Debug printing 278 */ 279 #ifndef DPRINTF 280 #ifdef DEBUG 281 /*PRINTFLIKE1*/ 282 static void wc_dprintf(const char *fmt, ...) __KPRINTFLIKE(1); 283 #define DPRINTF(l, m, args) \ 284 (((l) >= wc_errlevel) && ((m) & wc_errmask) ? \ 285 wc_dprintf args : \ 286 (void) 0) 287 /* 288 * Severity levels for printing 289 */ 290 #define PRINT_L0 0 /* print every message */ 291 #define PRINT_L1 1 /* debug */ 292 #define PRINT_L2 2 /* quiet */ 293 294 /* 295 * Masks 296 */ 297 #define PRINT_MASK_ALL 0xFFFFFFFFU 298 uint_t wc_errmask = PRINT_MASK_ALL; 299 uint_t wc_errlevel = PRINT_L2; 300 301 #else 302 #define DPRINTF(l, m, args) /* NOTHING */ 303 #endif 304 #endif 305 306 /* 307 * Module linkage information for the kernel. 308 */ 309 static struct modldrv modldrv = { 310 &mod_driverops, /* Type of module. This one is a pseudo driver */ 311 "Workstation multiplexer Driver 'wc'", 312 &wc_ops, /* driver ops */ 313 }; 314 315 static struct modlinkage modlinkage = { 316 MODREV_1, 317 &modldrv, 318 NULL 319 }; 320 321 int 322 _init(void) 323 { 324 int rc; 325 if ((rc = mod_install(&modlinkage)) == 0) 326 vt_init(); 327 return (rc); 328 } 329 330 int 331 _fini(void) 332 { 333 return (mod_remove(&modlinkage)); 334 } 335 336 int 337 _info(struct modinfo *modinfop) 338 { 339 return (mod_info(&modlinkage, modinfop)); 340 } 341 342 /*ARGSUSED*/ 343 static int 344 wc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 345 { 346 /* create minor node for workstation hard console */ 347 if (ddi_create_minor_node(devi, "wscons", S_IFCHR, 348 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 349 ddi_remove_minor_node(devi, NULL); 350 return (DDI_FAILURE); 351 } 352 353 mutex_enter(&vc_lock); 354 355 wc_dip = devi; 356 357 bzero(&(wscons.wc_polledio), sizeof (wscons.wc_polledio)); 358 359 vt_resize(VC_DEFAULT_COUNT); 360 361 mutex_exit(&vc_lock); 362 363 return (DDI_SUCCESS); 364 } 365 366 /* ARGSUSED */ 367 static int 368 wc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 369 void **result) 370 { 371 int error; 372 373 switch (infocmd) { 374 case DDI_INFO_DEVT2DEVINFO: 375 if (wc_dip == NULL) { 376 error = DDI_FAILURE; 377 } else { 378 *result = (void *) wc_dip; 379 error = DDI_SUCCESS; 380 } 381 break; 382 case DDI_INFO_DEVT2INSTANCE: 383 *result = (void *)0; 384 error = DDI_SUCCESS; 385 break; 386 default: 387 error = DDI_FAILURE; 388 } 389 return (error); 390 } 391 392 static void 393 wc_init_polledio(void) 394 { 395 static boolean_t polledio_inited = B_FALSE; 396 _NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", 397 polledio_inited)) 398 399 if (polledio_inited) 400 return; 401 402 polledio_inited = B_TRUE; 403 404 /* 405 * Initialize the parts of the polled I/O struct that 406 * are common to both input and output modes, but which 407 * don't flag to the upper layers, which if any of the 408 * two modes are available. We don't know at this point 409 * if system is configured CONS_KFB, but we will when 410 * consconfig_dacf asks us with CONSOPENPOLLED I/O. 411 */ 412 bzero(&(wscons.wc_polledio), sizeof (wscons.wc_polledio)); 413 wscons.wc_polledio.cons_polledio_version = 414 CONSPOLLEDIO_V0; 415 wscons.wc_polledio.cons_polledio_argument = 416 (cons_polledio_arg_t)&wscons; 417 wscons.wc_polledio.cons_polledio_enter = 418 wc_polled_enter; 419 wscons.wc_polledio.cons_polledio_exit = 420 wc_polled_exit; 421 422 #ifdef _HAVE_TEM_FIRMWARE 423 /* 424 * If we're talking directly to a framebuffer, we assume 425 * that it's a "slow" device, so that rendering should 426 * be deferred to a timeout or softcall so that we write 427 * a bunch of characters at once. 428 */ 429 wscons.wc_defer_output = prom_stdout_is_framebuffer(); 430 #endif /* _HAVE_TEM_FIRMWARE */ 431 } 432 433 /*ARGSUSED*/ 434 static int 435 wcopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 436 { 437 int minor; 438 439 wc_init_polledio(); 440 minor = (int)getminor(*devp); 441 return (vt_open(minor, q, crp)); 442 } 443 444 /*ARGSUSED*/ 445 static int 446 wcclose(queue_t *q, int flag, cred_t *crp) 447 { 448 vc_state_t *pvc = (vc_state_t *)q->q_ptr; 449 450 qprocsoff(q); 451 452 mutex_enter(&vc_lock); 453 454 /* 455 * If we are closing the VT node which 456 * /dev/vt/console_user points to, revert 457 * /dev/vt/console to /dev/console 458 */ 459 if (vc_cons_user == pvc->vc_minor) 460 vc_cons_user = VT_MINOR_INVALID; 461 462 if (pvc->vc_minor == 0 || pvc->vc_minor == vc_active_console) { 463 464 /* 465 * If we lose the system console, 466 * no any other active consoles. 467 */ 468 if (pvc->vc_minor == 0 && pvc->vc_minor == vc_active_console) { 469 vc_active_console = VT_MINOR_INVALID; 470 vc_last_console = VT_MINOR_INVALID; 471 } 472 473 /* 474 * just clean for our primary console 475 * and active console 476 */ 477 mutex_enter(&pvc->vc_state_lock); 478 vt_clean(q, pvc); 479 mutex_exit(&pvc->vc_state_lock); 480 481 mutex_exit(&vc_lock); 482 483 return (0); 484 } 485 vt_close(q, pvc, crp); 486 487 mutex_exit(&vc_lock); 488 489 return (0); 490 } 491 492 /* 493 * Service procedure for upper write queue. 494 * We need to have service procedure to make sure the keyboard events 495 * are queued up for screen output and are not dependant on the screen 496 * updates. 497 */ 498 static int 499 wcuwsrv(queue_t *q) 500 { 501 vc_state_t *pvc = (vc_state_t *)q->q_ptr; 502 tem_vt_state_t ptem = NULL; 503 mblk_t *mp; 504 ssize_t cc; 505 506 while ((mp = getq(q)) != NULL) { 507 /* 508 * If we're waiting for something to happen (delay timeout to 509 * expire, current transmission to finish, output to be 510 * restarted, output to finish draining), don't grab anything 511 * new. 512 */ 513 if (pvc->vc_flags & (WCS_DELAY|WCS_BUSY|WCS_STOPPED)) { 514 putbq(q, mp); 515 return (0); 516 } 517 518 switch (mp->b_datap->db_type) { 519 default: /* drop unknown type */ 520 freemsg(mp); 521 continue; 522 523 case M_IOCTL: 524 wcioctl(q, mp); 525 continue; 526 527 case M_DELAY: 528 /* 529 * Arrange for "wcrstrt" to be called when the 530 * delay expires; it will turn WCS_DELAY off. 531 */ 532 if (pvc->vc_timeoutid != 0) 533 (void) quntimeout(q, pvc->vc_timeoutid); 534 pvc->vc_timeoutid = qtimeout(q, wcrstrt, pvc, 535 (clock_t)(*(unsigned char *)mp->b_rptr + 6)); 536 537 mutex_enter(&pvc->vc_state_lock); 538 pvc->vc_flags |= WCS_DELAY; 539 mutex_exit(&pvc->vc_state_lock); 540 541 freemsg(mp); 542 continue; 543 544 case M_DATA: 545 break; 546 } 547 548 if ((cc = mp->b_wptr - mp->b_rptr) == 0) { 549 freemsg(mp); 550 continue; 551 } 552 553 #ifdef _HAVE_TEM_FIRMWARE 554 if (consmode == CONS_KFB) { 555 #endif /* _HAVE_TEM_FIRMWARE */ 556 ptem = wc_get_screen_tem(pvc); 557 558 if (ptem == NULL) { 559 freemsg(mp); 560 continue; 561 } 562 563 for (mblk_t *nbp = mp; nbp != NULL; nbp = nbp->b_cont) { 564 cc = nbp->b_wptr - nbp->b_rptr; 565 566 if (cc <= 0) 567 continue; 568 569 tem_write(ptem, nbp->b_rptr, cc, kcred); 570 } 571 freemsg(mp); 572 #ifdef _HAVE_TEM_FIRMWARE 573 continue; 574 } 575 576 /* consmode = CONS_FW */ 577 if (pvc->vc_minor != 0) { 578 freemsg(mp); 579 continue; 580 } 581 582 /* 583 * Direct output to the frame buffer if this device 584 * is not the "hardware" console. 585 */ 586 if (wscons.wc_defer_output) { 587 mutex_enter(&pvc->vc_state_lock); 588 pvc->vc_flags |= WCS_BUSY; 589 mutex_exit(&pvc->vc_state_lock); 590 591 pvc->vc_pendc = -1; 592 593 for (mblk_t *nbp = mp; nbp != NULL; nbp = nbp->b_cont) { 594 cc = nbp->b_wptr - nbp->b_rptr; 595 596 if (cc <= 0) 597 continue; 598 599 console_puts((const char *)nbp->b_rptr, cc); 600 } 601 freemsg(mp); 602 mutex_enter(&pvc->vc_state_lock); 603 pvc->vc_flags &= ~WCS_BUSY; 604 mutex_exit(&pvc->vc_state_lock); 605 continue; 606 } 607 for (boolean_t done = B_FALSE; done != B_TRUE; ) { 608 int c; 609 610 c = *mp->b_rptr++; 611 cc--; 612 if (prom_mayput((char)c) != 0) { 613 614 mutex_enter(&pvc->vc_state_lock); 615 pvc->vc_flags |= WCS_BUSY; 616 mutex_exit(&pvc->vc_state_lock); 617 618 pvc->vc_pendc = c; 619 if (pvc->vc_timeoutid != 0) 620 (void) quntimeout(q, 621 pvc->vc_timeoutid); 622 pvc->vc_timeoutid = qtimeout(q, wcopoll, 623 pvc, 1); 624 if (mp != NULL) { 625 /* not done with this message yet */ 626 (void) putbq(q, mp); 627 return (0); 628 } 629 break; 630 } 631 while (cc <= 0) { 632 mblk_t *nbp = mp; 633 mp = mp->b_cont; 634 freeb(nbp); 635 if (mp == NULL) { 636 done = B_TRUE; 637 break; 638 } 639 /* LINTED E_PTRDIFF_OVERFLOW */ 640 cc = mp->b_wptr - mp->b_rptr; 641 } 642 } 643 #endif /* _HAVE_TEM_FIRMWARE */ 644 } 645 return (0); 646 } 647 648 /* 649 * Put procedure for upper write queue. 650 * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here; 651 * queue up M_BREAK, M_DELAY, and M_DATA messages for processing by 652 * the service routine. Discard everything else. 653 */ 654 static int 655 wcuwput(queue_t *q, mblk_t *mp) 656 { 657 vc_state_t *pvc = (vc_state_t *)q->q_ptr; 658 659 switch (mp->b_datap->db_type) { 660 661 case M_STOP: 662 mutex_enter(&pvc->vc_state_lock); 663 pvc->vc_flags |= WCS_STOPPED; 664 mutex_exit(&pvc->vc_state_lock); 665 666 freemsg(mp); 667 break; 668 669 case M_START: 670 mutex_enter(&pvc->vc_state_lock); 671 pvc->vc_flags &= ~WCS_STOPPED; 672 mutex_exit(&pvc->vc_state_lock); 673 674 qenable(q); 675 freemsg(mp); 676 break; 677 678 case M_IOCTL: { 679 struct iocblk *iocp; 680 struct linkblk *linkp; 681 682 iocp = (struct iocblk *)(void *)mp->b_rptr; 683 switch (iocp->ioc_cmd) { 684 685 case I_LINK: /* stupid, but permitted */ 686 case I_PLINK: 687 if (wscons.wc_kbdqueue != NULL) { 688 /* somebody already linked */ 689 miocnak(q, mp, 0, EINVAL); 690 return (0); 691 } 692 linkp = (struct linkblk *)(void *)mp->b_cont->b_rptr; 693 wscons.wc_kbdqueue = WR(linkp->l_qbot); 694 mp->b_datap->db_type = M_IOCACK; 695 iocp->ioc_count = 0; 696 wc_open_kb_polledio(&wscons, q, mp); 697 break; 698 699 case I_UNLINK: /* stupid, but permitted */ 700 case I_PUNLINK: 701 linkp = (struct linkblk *)(void *)mp->b_cont->b_rptr; 702 if (wscons.wc_kbdqueue != WR(linkp->l_qbot)) { 703 /* not us */ 704 miocnak(q, mp, 0, EINVAL); 705 return (0); 706 } 707 708 mp->b_datap->db_type = M_IOCACK; 709 iocp->ioc_count = 0; 710 wc_close_kb_polledio(&wscons, q, mp); 711 break; 712 713 case TCSETSW: 714 case TCSETSF: 715 case TCSETAW: 716 case TCSETAF: 717 case TCSBRK: 718 /* 719 * The changes do not take effect until all 720 * output queued before them is drained. 721 * Put this message on the queue, so that 722 * "wcuwsrv" will see it when it's done 723 * with the output before it. 724 */ 725 if (putq(q, mp) == 0) 726 freemsg(mp); 727 break; 728 729 case CONSSETABORTENABLE: 730 case CONSGETABORTENABLE: 731 case KIOCSDIRECT: 732 if (wscons.wc_kbdqueue != NULL) { 733 wscons.wc_pending_wq = q; 734 (void) putnext(wscons.wc_kbdqueue, mp); 735 break; 736 } 737 /* fall through */ 738 739 default: 740 /* 741 * Do it now. 742 */ 743 wcioctl(q, mp); 744 break; 745 } 746 break; 747 } 748 749 case M_FLUSH: 750 if (*mp->b_rptr & FLUSHW) { 751 /* 752 * Flush our write queue. 753 */ 754 flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */ 755 *mp->b_rptr &= ~FLUSHW; /* it has been flushed */ 756 } 757 if (*mp->b_rptr & FLUSHR) { 758 flushq(RD(q), FLUSHDATA); 759 qreply(q, mp); /* give the read queues a crack at it */ 760 } else 761 freemsg(mp); 762 break; 763 764 case M_BREAK: 765 /* 766 * Ignore these, as they make no sense. 767 */ 768 freemsg(mp); 769 break; 770 771 case M_DELAY: 772 case M_DATA: 773 /* 774 * Queue the message up to be transmitted. 775 */ 776 if (putq(q, mp) == 0) 777 freemsg(mp); 778 break; 779 780 case M_IOCDATA: 781 vt_miocdata(q, mp); 782 break; 783 784 default: 785 /* 786 * "No, I don't want a subscription to Chain Store Age, 787 * thank you anyway." 788 */ 789 freemsg(mp); 790 break; 791 } 792 793 return (0); 794 } 795 796 /* 797 * Retry an "ioctl", now that "qbufcall" claims we may be able to allocate 798 * the buffer we need. 799 */ 800 /*ARGSUSED*/ 801 static void 802 wcreioctl(void *arg) 803 { 804 vc_state_t *pvc = (vc_state_t *)arg; 805 queue_t *q; 806 mblk_t *mp; 807 808 pvc->vc_bufcallid = 0; 809 q = pvc->vc_ttycommon.t_writeq; 810 if ((mp = pvc->vc_ttycommon.t_iocpending) != NULL) { 811 /* not pending any more */ 812 pvc->vc_ttycommon.t_iocpending = NULL; 813 wcioctl(q, mp); 814 } 815 } 816 817 static int 818 wc_getterm(mblk_t *mp) 819 { 820 char *term; 821 intptr_t arg; 822 int flag = ((struct iocblk *)(void *)mp->b_rptr)->ioc_flag; 823 824 STRUCT_DECL(cons_getterm, wcterm); 825 STRUCT_INIT(wcterm, flag); 826 827 arg = *((intptr_t *)(void *)mp->b_cont->b_rptr); 828 829 if (ddi_copyin((void *)arg, STRUCT_BUF(wcterm), 830 STRUCT_SIZE(wcterm), flag) != 0) { 831 return (EFAULT); 832 } 833 834 if (consmode == CONS_FW) { 835 /* PROM terminal emulator */ 836 term = "sun"; 837 } else { 838 /* Kernel terminal emulator */ 839 ASSERT(consmode == CONS_KFB); 840 term = "sun-color"; 841 } 842 843 if (STRUCT_FGET(wcterm, cn_term_len) < 844 strlen(term) + 1) { 845 return (EOVERFLOW); 846 } 847 848 if (ddi_copyout(term, 849 STRUCT_FGETP(wcterm, cn_term_type), 850 strlen(term) + 1, flag) != 0) { 851 return (EFAULT); 852 } 853 854 return (0); 855 } 856 857 /* 858 * Process an "ioctl" message sent down to us. 859 */ 860 static void 861 wcioctl(queue_t *q, mblk_t *mp) 862 { 863 vc_state_t *pvc = (vc_state_t *)q->q_ptr; 864 struct iocblk *iocp; 865 size_t datasize; 866 int error; 867 long len; 868 869 iocp = (struct iocblk *)(void *)mp->b_rptr; 870 871 if ((iocp->ioc_cmd & VTIOC) == VTIOC || 872 (iocp->ioc_cmd & KDIOC) == KDIOC) { 873 vt_ioctl(q, mp); 874 return; 875 } 876 877 switch (iocp->ioc_cmd) { 878 case TIOCSWINSZ: 879 /* 880 * Ignore all attempts to set the screen size; the 881 * value in the EEPROM is guaranteed (modulo PROM bugs) 882 * to be the value used by the PROM monitor code, so it 883 * is by definition correct. Many programs (e.g., 884 * "login" and "tset") will attempt to reset the size 885 * to (0, 0) or (34, 80), neither of which is 886 * necessarily correct. 887 * We just ACK the message, so as not to disturb 888 * programs that set the sizes. 889 */ 890 iocp->ioc_count = 0; /* no data returned */ 891 mp->b_datap->db_type = M_IOCACK; 892 qreply(q, mp); 893 return; 894 895 case CONSOPENPOLLEDIO: 896 DPRINTF(PRINT_L1, PRINT_MASK_ALL, 897 ("wcioctl: CONSOPENPOLLEDIO\n")); 898 899 error = miocpullup(mp, sizeof (struct cons_polledio *)); 900 if (error != 0) { 901 miocnak(q, mp, 0, error); 902 return; 903 } 904 905 /* 906 * We are given an appropriate-sized data block, 907 * and return a pointer to our structure in it. 908 */ 909 if (consmode == CONS_KFB) 910 wscons.wc_polledio.cons_polledio_putchar = 911 wc_polled_putchar; 912 *(struct cons_polledio **)(void *)mp->b_cont->b_rptr = 913 &wscons.wc_polledio; 914 915 mp->b_datap->db_type = M_IOCACK; 916 917 qreply(q, mp); 918 break; 919 920 case CONS_GETTERM: 921 if ((error = wc_getterm(mp)) != 0) 922 miocnak(q, mp, 0, error); 923 else 924 miocack(q, mp, 0, 0); 925 return; 926 927 case WC_OPEN_FB: 928 /* 929 * Start out pessimistic, so that we can just jump to 930 * the reply to bail out. 931 */ 932 mp->b_datap->db_type = M_IOCNAK; 933 934 /* 935 * First test: really, this should be done only from 936 * inside the kernel. Unfortunately, that information 937 * doesn't seem to be available in a streams ioctl, 938 * so restrict it to root only. (Perhaps we could check 939 * for ioc_cr == kcred.) 940 */ 941 if ((iocp->ioc_error = secpolicy_console(iocp->ioc_cr)) != 0) 942 goto open_fail; 943 944 /* 945 * Some miscellaneous checks... 946 */ 947 iocp->ioc_error = EINVAL; 948 949 /* 950 * If we don't have exactly one continuation block, fail. 951 */ 952 if (mp->b_cont == NULL || 953 mp->b_cont->b_cont != NULL) 954 goto open_fail; 955 956 /* 957 * If there's no null terminator in the string, fail. 958 */ 959 /* LINTED E_PTRDIFF_OVERFLOW */ 960 len = mp->b_cont->b_wptr - mp->b_cont->b_rptr; 961 if (memchr(mp->b_cont->b_rptr, 0, len) == NULL) 962 goto open_fail; 963 964 /* 965 * NOTE: should eventually get default 966 * dimensions from a property, e.g. screen-#rows. 967 */ 968 iocp->ioc_error = tem_info_init((char *)mp->b_cont->b_rptr, 969 iocp->ioc_cr); 970 /* 971 * Of course, if the terminal emulator initialization 972 * failed, fail. 973 */ 974 if (iocp->ioc_error != 0) 975 goto open_fail; 976 977 #ifdef _HAVE_TEM_FIRMWARE 978 if (prom_stdout_is_framebuffer()) { 979 /* 980 * Drivers in the console stream may emit additional 981 * messages before we are ready. This causes text 982 * overwrite on the screen. So we set the redirection 983 * here. It is safe because the ioctl in consconfig_dacf 984 * will succeed and consmode will be set to CONS_KFB. 985 */ 986 prom_set_stdout_redirect(wc_cons_wrtvec, 987 (promif_redir_arg_t)NULL); 988 989 } 990 #endif /* _HAVE_TEM_FIRMWARE */ 991 992 tem_register_modechg_cb(wc_modechg_cb, 993 (tem_modechg_cb_arg_t)&wscons); 994 995 /* 996 * ... and succeed. 997 */ 998 mp->b_datap->db_type = M_IOCACK; 999 1000 open_fail: 1001 qreply(q, mp); 1002 break; 1003 1004 case WC_CLOSE_FB: 1005 /* 1006 * There's nothing that can call this, so it's not 1007 * really implemented. 1008 */ 1009 mp->b_datap->db_type = M_IOCNAK; 1010 /* 1011 * However, if it were implemented, it would clearly 1012 * be root-only. 1013 */ 1014 if ((iocp->ioc_error = secpolicy_console(iocp->ioc_cr)) != 0) 1015 goto close_fail; 1016 1017 iocp->ioc_error = EINVAL; 1018 1019 close_fail: 1020 qreply(q, mp); 1021 break; 1022 1023 default: 1024 1025 /* 1026 * The only way in which "ttycommon_ioctl" can fail is 1027 * if the "ioctl" requires a response containing data 1028 * to be returned to the user, and no mblk could be 1029 * allocated for the data. No such "ioctl" alters our 1030 * state. Thus, we always go ahead and do any 1031 * state-changes the "ioctl" calls for. If we couldn't 1032 * allocate the data, "ttycommon_ioctl" has stashed the 1033 * "ioctl" away safely, so we just call "qbufcall" to 1034 * request that we be called back when we stand a 1035 * better chance of allocating the data. 1036 */ 1037 datasize = ttycommon_ioctl(&pvc->vc_ttycommon, q, mp, &error); 1038 if (datasize != 0) { 1039 if (pvc->vc_bufcallid != 0) 1040 qunbufcall(q, pvc->vc_bufcallid); 1041 pvc->vc_bufcallid = qbufcall(q, datasize, BPRI_HI, 1042 wcreioctl, pvc); 1043 return; 1044 } 1045 1046 if (error < 0) { 1047 if (iocp->ioc_cmd == TCSBRK) 1048 error = 0; 1049 else 1050 error = EINVAL; 1051 } 1052 if (error != 0) { 1053 iocp->ioc_error = error; 1054 mp->b_datap->db_type = M_IOCNAK; 1055 } 1056 qreply(q, mp); 1057 break; 1058 } 1059 } 1060 1061 /* 1062 * This function gets the polled I/O structures from the lower 1063 * keyboard driver. If any initialization or resource allocation 1064 * needs to be done by the lower driver, it will be done when 1065 * the lower driver services this message. 1066 */ 1067 static void 1068 wc_open_kb_polledio(struct wscons_state *wscons, queue_t *q, mblk_t *mp) 1069 { 1070 mblk_t *mp2; 1071 struct iocblk *iocp; 1072 1073 DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1074 ("wc_open_kb_polledio: sending CONSOPENPOLLEDIO\n")); 1075 1076 mp2 = mkiocb(CONSOPENPOLLEDIO); 1077 1078 if (mp2 == NULL) { 1079 /* 1080 * If we can't get an mblk, then wait for it. 1081 */ 1082 goto nomem; 1083 } 1084 1085 mp2->b_cont = allocb(sizeof (struct cons_polledio *), BPRI_HI); 1086 1087 if (mp2->b_cont == NULL) { 1088 /* 1089 * If we can't get an mblk, then wait for it, and release 1090 * the mblk that we have already allocated. 1091 */ 1092 freemsg(mp2); 1093 goto nomem; 1094 } 1095 1096 iocp = (struct iocblk *)(void *)mp2->b_rptr; 1097 1098 iocp->ioc_count = sizeof (struct cons_polledio *); 1099 mp2->b_cont->b_wptr = mp2->b_cont->b_rptr + 1100 sizeof (struct cons_polledio *); 1101 1102 wscons->wc_pending_wq = q; 1103 wscons->wc_pending_link = mp; 1104 wscons->wc_kb_getpolledio_id = iocp->ioc_id; 1105 1106 putnext(wscons->wc_kbdqueue, mp2); 1107 1108 return; 1109 1110 nomem: 1111 iocp = (struct iocblk *)(void *)mp->b_rptr; 1112 iocp->ioc_error = ENOMEM; 1113 mp->b_datap->db_type = M_IOCNAK; 1114 qreply(q, mp); 1115 } 1116 1117 /* 1118 * This function releases the polled I/O structures from the lower 1119 * keyboard driver. If any de-initialization needs to be done, or 1120 * any resources need to be released, it will be done when the lower 1121 * driver services this message. 1122 */ 1123 static void 1124 wc_close_kb_polledio(struct wscons_state *wscons, queue_t *q, mblk_t *mp) 1125 { 1126 mblk_t *mp2; 1127 struct iocblk *iocp; 1128 1129 DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1130 ("wc_close_kb_polledio: sending CONSCLOSEPOLLEDIO\n")); 1131 1132 mp2 = mkiocb(CONSCLOSEPOLLEDIO); 1133 1134 if (mp2 == NULL) { 1135 /* 1136 * If we can't get an mblk, then wait for it. 1137 */ 1138 goto nomem; 1139 } 1140 1141 mp2->b_cont = allocb(sizeof (struct cons_polledio *), BPRI_HI); 1142 1143 if (mp2->b_cont == NULL) { 1144 /* 1145 * If we can't get an mblk, then wait for it, and release 1146 * the mblk that we have already allocated. 1147 */ 1148 freemsg(mp2); 1149 1150 goto nomem; 1151 } 1152 1153 iocp = (struct iocblk *)(void *)mp2->b_rptr; 1154 1155 iocp->ioc_count = 0; 1156 1157 wscons->wc_pending_wq = q; 1158 wscons->wc_pending_link = mp; 1159 wscons->wc_kb_getpolledio_id = iocp->ioc_id; 1160 1161 putnext(wscons->wc_kbdqueue, mp2); 1162 1163 return; 1164 1165 nomem: 1166 iocp = (struct iocblk *)(void *)mp->b_rptr; 1167 iocp->ioc_error = ENOMEM; 1168 mp->b_datap->db_type = M_IOCNAK; 1169 qreply(q, mp); 1170 } 1171 1172 #ifdef _HAVE_TEM_FIRMWARE 1173 /* ARGSUSED */ 1174 static void 1175 wcopoll(void *arg) 1176 { 1177 vc_state_t *pvc = (vc_state_t *)arg; 1178 queue_t *q; 1179 1180 q = pvc->vc_ttycommon.t_writeq; 1181 pvc->vc_timeoutid = 0; 1182 1183 mutex_enter(&pvc->vc_state_lock); 1184 1185 /* See if we can continue output */ 1186 if ((pvc->vc_flags & WCS_BUSY) && pvc->vc_pendc != -1) { 1187 if (prom_mayput((char)pvc->vc_pendc) == 0) { 1188 pvc->vc_pendc = -1; 1189 pvc->vc_flags &= ~WCS_BUSY; 1190 if (!(pvc->vc_flags&(WCS_DELAY|WCS_STOPPED))) 1191 qenable(q); 1192 } else 1193 pvc->vc_timeoutid = qtimeout(q, wcopoll, pvc, 1); 1194 } 1195 1196 mutex_exit(&pvc->vc_state_lock); 1197 } 1198 #endif /* _HAVE_TEM_FIRMWARE */ 1199 1200 /* 1201 * Restart output on the console after a timeout. 1202 */ 1203 /* ARGSUSED */ 1204 static void 1205 wcrstrt(void *arg) 1206 { 1207 vc_state_t *pvc = (vc_state_t *)arg; 1208 1209 ASSERT(pvc->vc_ttycommon.t_writeq != NULL); 1210 1211 mutex_enter(&pvc->vc_state_lock); 1212 pvc->vc_flags &= ~WCS_DELAY; 1213 mutex_exit(&pvc->vc_state_lock); 1214 1215 qenable(pvc->vc_ttycommon.t_writeq); 1216 } 1217 1218 /* 1219 * get screen terminal for current output 1220 */ 1221 static tem_vt_state_t 1222 wc_get_screen_tem(vc_state_t *pvc) 1223 { 1224 if (!tem_initialized(pvc->vc_tem) || 1225 tem_get_fbmode(pvc->vc_tem) != KD_TEXT) 1226 return (NULL); 1227 1228 return (pvc->vc_tem); 1229 } 1230 1231 /* 1232 * Put procedure for lower read queue. 1233 * Pass everything up to queue above "upper half". 1234 */ 1235 static int 1236 wclrput(queue_t *q, mblk_t *mp) 1237 { 1238 vc_state_t *pvc; 1239 queue_t *upq; 1240 struct iocblk *iocp; 1241 1242 pvc = vt_minor2vc(VT_ACTIVE); 1243 1244 DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1245 ("wclrput: wclrput type = 0x%x\n", mp->b_datap->db_type)); 1246 1247 switch (mp->b_datap->db_type) { 1248 1249 case M_FLUSH: 1250 if (*mp->b_rptr == FLUSHW || *mp->b_rptr == FLUSHRW) { 1251 /* 1252 * Flush our write queue. 1253 */ 1254 /* XXX doesn't flush M_DELAY */ 1255 flushq(WR(q), FLUSHDATA); 1256 *mp->b_rptr = FLUSHR; /* it has been flushed */ 1257 } 1258 if (*mp->b_rptr == FLUSHR || *mp->b_rptr == FLUSHRW) { 1259 flushq(q, FLUSHDATA); 1260 *mp->b_rptr = FLUSHW; /* it has been flushed */ 1261 qreply(q, mp); /* give the read queues a crack at it */ 1262 } else 1263 freemsg(mp); 1264 break; 1265 1266 case M_DATA: 1267 if (consmode == CONS_KFB && vt_check_hotkeys(mp)) { 1268 freemsg(mp); 1269 break; 1270 } 1271 1272 if ((upq = pvc->vc_ttycommon.t_readq) != NULL) { 1273 if (!canput(upq->q_next)) { 1274 ttycommon_qfull(&pvc->vc_ttycommon, upq); 1275 qenable(WR(upq)); 1276 freemsg(mp); 1277 } else { 1278 putnext(upq, mp); 1279 } 1280 } else 1281 freemsg(mp); 1282 break; 1283 1284 case M_IOCACK: 1285 case M_IOCNAK: 1286 iocp = (struct iocblk *)(void *)mp->b_rptr; 1287 if (wscons.wc_pending_link != NULL && 1288 iocp->ioc_id == wscons.wc_kb_getpolledio_id) { 1289 switch (mp->b_datap->db_type) { 1290 1291 case M_IOCACK: 1292 switch (iocp->ioc_cmd) { 1293 1294 case CONSOPENPOLLEDIO: 1295 DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1296 ("wclrput: " 1297 "ACK CONSOPENPOLLEDIO\n")); 1298 wscons.wc_kb_polledio = 1299 *(struct cons_polledio **) 1300 (void *)mp->b_cont->b_rptr; 1301 wscons.wc_polledio. 1302 cons_polledio_getchar = 1303 wc_polled_getchar; 1304 wscons.wc_polledio. 1305 cons_polledio_ischar = 1306 wc_polled_ischar; 1307 break; 1308 1309 case CONSCLOSEPOLLEDIO: 1310 DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1311 ("wclrput: " 1312 "ACK CONSCLOSEPOLLEDIO\n")); 1313 wscons.wc_kb_polledio = NULL; 1314 wscons.wc_kbdqueue = NULL; 1315 wscons.wc_polledio. 1316 cons_polledio_getchar = NULL; 1317 wscons.wc_polledio. 1318 cons_polledio_ischar = NULL; 1319 break; 1320 default: 1321 DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1322 ("wclrput: " 1323 "ACK UNKNOWN\n")); 1324 } 1325 1326 break; 1327 case M_IOCNAK: 1328 /* 1329 * Keyboard may or may not support polled I/O. 1330 * This ioctl may have been rejected because 1331 * we only have the wc->conskbd chain built, 1332 * and the keyboard driver has not been linked 1333 * underneath conskbd yet. 1334 */ 1335 DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1336 ("wclrput: NAK\n")); 1337 1338 switch (iocp->ioc_cmd) { 1339 1340 case CONSCLOSEPOLLEDIO: 1341 wscons.wc_kb_polledio = NULL; 1342 wscons.wc_kbdqueue = NULL; 1343 wscons.wc_polledio. 1344 cons_polledio_getchar = NULL; 1345 wscons.wc_polledio. 1346 cons_polledio_ischar = NULL; 1347 break; 1348 } 1349 break; 1350 } 1351 1352 /* 1353 * Discard the response, replace it with the 1354 * pending response to the I_PLINK, then let it 1355 * flow upward. 1356 */ 1357 freemsg(mp); 1358 mp = wscons.wc_pending_link; 1359 wscons.wc_pending_link = NULL; 1360 wscons.wc_kb_getpolledio_id = 0; 1361 } 1362 /* FALLTHROUGH */ 1363 1364 default: /* inc M_ERROR, M_HANGUP, M_IOCACK, M_IOCNAK, ... */ 1365 if (wscons.wc_pending_wq != NULL) { 1366 qreply(wscons.wc_pending_wq, mp); 1367 wscons.wc_pending_wq = NULL; 1368 break; 1369 } 1370 1371 if ((upq = pvc->vc_ttycommon.t_readq) != NULL) { 1372 putnext(upq, mp); 1373 } else { 1374 DPRINTF(PRINT_L1, PRINT_MASK_ALL, 1375 ("wclrput: Message DISCARDED\n")); 1376 freemsg(mp); 1377 } 1378 break; 1379 } 1380 1381 return (0); 1382 } 1383 1384 #ifdef _HAVE_TEM_FIRMWARE 1385 /* 1386 * This routine exists so that prom_write() can redirect writes 1387 * to the framebuffer through the kernel terminal emulator, if 1388 * that configuration is selected during consconfig. 1389 * When the kernel terminal emulator is enabled, consconfig_dacf 1390 * sets up the PROM output redirect vector to enter this function. 1391 * During panic the console will already be powered up as part of 1392 * calling into the prom_*() layer. 1393 */ 1394 /* ARGSUSED */ 1395 ssize_t 1396 wc_cons_wrtvec(promif_redir_arg_t arg, uchar_t *s, size_t n) 1397 { 1398 vc_state_t *pvc; 1399 1400 pvc = vt_minor2vc(VT_ACTIVE); 1401 1402 if (pvc->vc_tem == NULL) 1403 return (0); 1404 1405 ASSERT(consmode == CONS_KFB); 1406 1407 if (panicstr) 1408 polled_io_cons_write(s, n); 1409 else 1410 (void) tem_write(pvc->vc_tem, s, n, kcred); 1411 1412 return (n); 1413 } 1414 #endif /* _HAVE_TEM_FIRMWARE */ 1415 1416 /* 1417 * These are for systems without OBP, and for devices that cannot be 1418 * shared between Solaris and the OBP. 1419 */ 1420 static void 1421 wc_polled_putchar(cons_polledio_arg_t arg, unsigned char c) 1422 { 1423 vc_state_t *pvc; 1424 1425 pvc = vt_minor2vc(VT_ACTIVE); 1426 1427 if (c == '\n') 1428 wc_polled_putchar(arg, '\r'); 1429 1430 if (pvc->vc_tem == NULL) { 1431 /* 1432 * We have no terminal emulator configured. We have no 1433 * recourse but to drop the output on the floor. 1434 */ 1435 return; 1436 } 1437 1438 tem_safe_polled_write(pvc->vc_tem, &c, 1); 1439 } 1440 1441 /* 1442 * These are for systems without OBP, and for devices that cannot be 1443 * shared between Solaris and the OBP. 1444 */ 1445 static int 1446 wc_polled_getchar(cons_polledio_arg_t arg) 1447 { 1448 struct wscons_state *wscons = (struct wscons_state *)arg; 1449 1450 if (wscons->wc_kb_polledio == NULL) { 1451 prom_printf("wscons: getchar with no keyboard support"); 1452 prom_printf("Halted..."); 1453 for (;;) 1454 /* HANG FOREVER */; 1455 } 1456 1457 return (wscons->wc_kb_polledio->cons_polledio_getchar( 1458 wscons->wc_kb_polledio->cons_polledio_argument)); 1459 } 1460 1461 static boolean_t 1462 wc_polled_ischar(cons_polledio_arg_t arg) 1463 { 1464 struct wscons_state *wscons = (struct wscons_state *)arg; 1465 1466 if (wscons->wc_kb_polledio == NULL) 1467 return (B_FALSE); 1468 1469 return (wscons->wc_kb_polledio->cons_polledio_ischar( 1470 wscons->wc_kb_polledio->cons_polledio_argument)); 1471 } 1472 1473 static void 1474 wc_polled_enter(cons_polledio_arg_t arg) 1475 { 1476 struct wscons_state *wscons = (struct wscons_state *)arg; 1477 1478 if (wscons->wc_kb_polledio == NULL) 1479 return; 1480 1481 if (wscons->wc_kb_polledio->cons_polledio_enter != NULL) { 1482 wscons->wc_kb_polledio->cons_polledio_enter( 1483 wscons->wc_kb_polledio->cons_polledio_argument); 1484 } 1485 } 1486 1487 static void 1488 wc_polled_exit(cons_polledio_arg_t arg) 1489 { 1490 struct wscons_state *wscons = (struct wscons_state *)arg; 1491 1492 if (wscons->wc_kb_polledio == NULL) 1493 return; 1494 1495 if (wscons->wc_kb_polledio->cons_polledio_exit != NULL) { 1496 wscons->wc_kb_polledio->cons_polledio_exit( 1497 wscons->wc_kb_polledio->cons_polledio_argument); 1498 } 1499 } 1500 1501 1502 #ifdef DEBUG 1503 static void 1504 wc_dprintf(const char *fmt, ...) 1505 { 1506 char buf[256]; 1507 va_list ap; 1508 1509 va_start(ap, fmt); 1510 (void) vsprintf(buf, fmt, ap); 1511 va_end(ap); 1512 1513 cmn_err(CE_WARN, "wc: %s", buf); 1514 } 1515 #endif 1516 1517 /*ARGSUSED*/ 1518 static void 1519 update_property(vc_state_t *pvc, char *name, ushort_t value) 1520 { 1521 char data[8]; 1522 1523 (void) snprintf(data, sizeof (data), "%u", value); 1524 1525 (void) ddi_prop_update_string(wscons.wc_dev, wc_dip, name, data); 1526 } 1527 1528 /* 1529 * Gets the number of text rows and columns and the 1530 * width and height (in pixels) of the console. 1531 */ 1532 void 1533 wc_get_size(vc_state_t *pvc) 1534 { 1535 struct winsize *t = &pvc->vc_ttycommon.t_size; 1536 ushort_t r = LOSCREENLINES, c = LOSCREENCOLS, x = 0, y = 0; 1537 1538 if (pvc->vc_tem != NULL) 1539 tem_get_size(&r, &c, &x, &y); 1540 #ifdef _HAVE_TEM_FIRMWARE 1541 else 1542 console_get_size(&r, &c, &x, &y); 1543 #endif /* _HAVE_TEM_FIRMWARE */ 1544 1545 mutex_enter(&pvc->vc_ttycommon.t_excl); 1546 t->ws_col = c; 1547 t->ws_row = r; 1548 t->ws_xpixel = x; 1549 t->ws_ypixel = y; 1550 mutex_exit(&pvc->vc_ttycommon.t_excl); 1551 1552 if (pvc->vc_minor != 0) 1553 return; 1554 1555 /* only for the wscons:0 */ 1556 update_property(pvc, "screen-#cols", c); 1557 update_property(pvc, "screen-#rows", r); 1558 update_property(pvc, "screen-width", x); 1559 update_property(pvc, "screen-height", y); 1560 } 1561 1562 /*ARGSUSED*/ 1563 static void 1564 wc_modechg_cb(tem_modechg_cb_arg_t arg) 1565 { 1566 minor_t index; 1567 vc_state_t *pvc; 1568 1569 mutex_enter(&vc_lock); 1570 for (index = 0; index < VC_INSTANCES_COUNT; index++) { 1571 pvc = vt_minor2vc(index); 1572 1573 mutex_enter(&pvc->vc_state_lock); 1574 1575 if ((pvc->vc_flags & WCS_ISOPEN) && 1576 (pvc->vc_flags & WCS_INIT)) 1577 wc_get_size(pvc); 1578 1579 mutex_exit(&pvc->vc_state_lock); 1580 } 1581 mutex_exit(&vc_lock); 1582 }