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