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