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