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