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