wsdisplay.c revision 1.108.14.2 1 /* $NetBSD: wsdisplay.c,v 1.108.14.2 2007/10/26 15:48:05 joerg Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Christopher G. Demetriou
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: wsdisplay.c,v 1.108.14.2 2007/10/26 15:48:05 joerg Exp $");
35
36 #include "opt_wsdisplay_compat.h"
37 #include "opt_wsmsgattrs.h"
38 #include "opt_compat_netbsd.h"
39 #include "wskbd.h"
40 #include "wsmux.h"
41 #include "wsdisplay.h"
42
43 #include <sys/param.h>
44 #include <sys/conf.h>
45 #include <sys/device.h>
46 #include <sys/ioctl.h>
47 #include <sys/poll.h>
48 #include <sys/kernel.h>
49 #include <sys/proc.h>
50 #include <sys/malloc.h>
51 #include <sys/syslog.h>
52 #include <sys/systm.h>
53 #include <sys/tty.h>
54 #include <sys/signalvar.h>
55 #include <sys/errno.h>
56 #include <sys/fcntl.h>
57 #include <sys/vnode.h>
58 #include <sys/kauth.h>
59
60 #include <dev/wscons/wseventvar.h>
61 #include <dev/wscons/wsmuxvar.h>
62 #include <dev/wscons/wsconsio.h>
63 #include <dev/wscons/wsdisplayvar.h>
64 #include <dev/wscons/wsksymvar.h>
65 #include <dev/wscons/wsksymdef.h>
66 #include <dev/wscons/wsemulvar.h>
67 #include <dev/wscons/wscons_callbacks.h>
68 #include <dev/cons.h>
69
70 struct wsscreen_internal {
71 const struct wsdisplay_emulops *emulops;
72 void *emulcookie;
73
74 const struct wsscreen_descr *scrdata;
75
76 const struct wsemul_ops *wsemul;
77 void *wsemulcookie;
78 };
79
80 struct wsscreen {
81 struct wsscreen_internal *scr_dconf;
82
83 struct tty *scr_tty;
84 int scr_hold_screen; /* hold tty output */
85
86 int scr_flags;
87 #define SCR_OPEN 1 /* is it open? */
88 #define SCR_WAITACTIVE 2 /* someone waiting on activation */
89 #define SCR_GRAPHICS 4 /* graphics mode, no text (emulation) output */
90 #define SCR_DUMBFB 8 /* in use as a dumb fb (iff SCR_GRAPHICS) */
91 const struct wscons_syncops *scr_syncops;
92 void *scr_synccookie;
93
94 #ifdef WSDISPLAY_COMPAT_RAWKBD
95 int scr_rawkbd;
96 #endif
97
98 struct wsdisplay_softc *sc;
99 };
100
101 struct wsscreen *wsscreen_attach(struct wsdisplay_softc *, int,
102 const char *,
103 const struct wsscreen_descr *, void *,
104 int, int, long);
105 void wsscreen_detach(struct wsscreen *);
106 int wsdisplay_addscreen(struct wsdisplay_softc *, int, const char *, const char *);
107 static void wsdisplay_shutdownhook(void *);
108 static void wsdisplay_addscreen_print(struct wsdisplay_softc *, int, int);
109 static void wsdisplay_closescreen(struct wsdisplay_softc *, struct wsscreen *);
110 int wsdisplay_delscreen(struct wsdisplay_softc *, int, int);
111 static void wsdisplay_switchto(int);
112
113 #define WSDISPLAY_MAXSCREEN 8
114
115 struct wsdisplay_softc {
116 device_t sc_dev;
117
118 const struct wsdisplay_accessops *sc_accessops;
119 void *sc_accesscookie;
120
121 const struct wsscreen_list *sc_scrdata;
122 #ifdef WSDISPLAY_SCROLLSUPPORT
123 struct wsdisplay_scroll_data sc_scroll_values;
124 #endif
125
126 struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN];
127 int sc_focusidx; /* available only if sc_focus isn't null */
128 struct wsscreen *sc_focus;
129
130 struct wseventvar evar;
131
132 int sc_isconsole;
133
134 int sc_flags;
135 #define SC_SWITCHPENDING 1
136 int sc_screenwanted, sc_oldscreen; /* valid with SC_SWITCHPENDING */
137
138 struct wsdisplay_pmstate {
139 int screen;
140 } sc_pmstate;
141
142 #if NWSKBD > 0
143 struct wsevsrc *sc_input;
144 #ifdef WSDISPLAY_COMPAT_RAWKBD
145 int sc_rawkbd;
146 #endif
147 #endif /* NWSKBD > 0 */
148 };
149
150 #ifdef WSDISPLAY_SCROLLSUPPORT
151
152 struct wsdisplay_scroll_data wsdisplay_default_scroll_values = {
153 WSDISPLAY_SCROLL_DOALL,
154 25,
155 2,
156 };
157 #endif
158
159 extern struct cfdriver wsdisplay_cd;
160
161 /* Autoconfiguration definitions. */
162 static int wsdisplay_emul_match(device_t , struct cfdata *, void *);
163 static void wsdisplay_emul_attach(device_t, device_t, void *);
164 static int wsdisplay_noemul_match(device_t, struct cfdata *, void *);
165 static void wsdisplay_noemul_attach(device_t, device_t, void *);
166 static pnp_status_t wsdisplay_power(device_t, pnp_request_t, void *);
167
168 CFATTACH_DECL_NEW(wsdisplay_emul, sizeof (struct wsdisplay_softc),
169 wsdisplay_emul_match, wsdisplay_emul_attach, NULL, NULL);
170
171 CFATTACH_DECL_NEW(wsdisplay_noemul, sizeof (struct wsdisplay_softc),
172 wsdisplay_noemul_match, wsdisplay_noemul_attach, NULL, NULL);
173
174 dev_type_open(wsdisplayopen);
175 dev_type_close(wsdisplayclose);
176 dev_type_read(wsdisplayread);
177 dev_type_write(wsdisplaywrite);
178 dev_type_ioctl(wsdisplayioctl);
179 dev_type_stop(wsdisplaystop);
180 dev_type_tty(wsdisplaytty);
181 dev_type_poll(wsdisplaypoll);
182 dev_type_mmap(wsdisplaymmap);
183 dev_type_kqfilter(wsdisplaykqfilter);
184
185 const struct cdevsw wsdisplay_cdevsw = {
186 wsdisplayopen, wsdisplayclose, wsdisplayread, wsdisplaywrite,
187 wsdisplayioctl, wsdisplaystop, wsdisplaytty, wsdisplaypoll,
188 wsdisplaymmap, wsdisplaykqfilter, D_TTY
189 };
190
191 static void wsdisplaystart(struct tty *);
192 static int wsdisplayparam(struct tty *, struct termios *);
193
194
195 #define WSDISPLAYUNIT(dev) (minor(dev) >> 8)
196 #define WSDISPLAYSCREEN(dev) (minor(dev) & 0xff)
197 #define ISWSDISPLAYSTAT(dev) (WSDISPLAYSCREEN(dev) == 254)
198 #define ISWSDISPLAYCTL(dev) (WSDISPLAYSCREEN(dev) == 255)
199 #define WSDISPLAYMINOR(unit, screen) (((unit) << 8) | (screen))
200
201 #define WSSCREEN_HAS_EMULATOR(scr) ((scr)->scr_dconf->wsemul != NULL)
202 #define WSSCREEN_HAS_TTY(scr) ((scr)->scr_tty != NULL)
203
204 static void wsdisplay_common_attach(struct wsdisplay_softc *sc,
205 int console, int kbdmux, const struct wsscreen_list *,
206 const struct wsdisplay_accessops *accessops,
207 void *accesscookie);
208
209 #ifdef WSDISPLAY_COMPAT_RAWKBD
210 int wsdisplay_update_rawkbd(struct wsdisplay_softc *,
211 struct wsscreen *);
212 #endif
213
214 static int wsdisplay_console_initted;
215 static int wsdisplay_console_attached;
216 static struct wsdisplay_softc *wsdisplay_console_device;
217 static struct wsscreen_internal wsdisplay_console_conf;
218
219 static int wsdisplay_getc_dummy(dev_t);
220 static void wsdisplay_pollc(dev_t, int);
221
222 static int wsdisplay_cons_pollmode;
223 static void (*wsdisplay_cons_kbd_pollc)(dev_t, int);
224
225 static struct consdev wsdisplay_cons = {
226 NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc,
227 wsdisplay_pollc, NULL, NULL, NULL, NODEV, CN_NORMAL
228 };
229
230 #ifndef WSDISPLAY_DEFAULTSCREENS
231 # define WSDISPLAY_DEFAULTSCREENS 0
232 #endif
233 int wsdisplay_defaultscreens = WSDISPLAY_DEFAULTSCREENS;
234
235 static int wsdisplay_switch1(device_t, int, int);
236 static void wsdisplay_switch1_cb(void *, int, int);
237 static int wsdisplay_switch2(device_t, int, int);
238 static void wsdisplay_switch2_cb(void *, int, int);
239 static int wsdisplay_switch3(device_t, int, int);
240 static void wsdisplay_switch3_cb(void *, int, int);
241
242 int wsdisplay_clearonclose;
243
244 struct wsscreen *
245 wsscreen_attach(struct wsdisplay_softc *sc, int console, const char *emul,
246 const struct wsscreen_descr *type, void *cookie, int ccol,
247 int crow, long defattr)
248 {
249 struct wsscreen_internal *dconf;
250 struct wsscreen *scr;
251
252 scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_WAITOK);
253 if (!scr)
254 return (NULL);
255
256 if (console) {
257 dconf = &wsdisplay_console_conf;
258 /*
259 * If there's an emulation, tell it about the callback argument.
260 * The other stuff is already there.
261 */
262 if (dconf->wsemul != NULL)
263 (*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr, 0);
264 } else { /* not console */
265 dconf = malloc(sizeof(struct wsscreen_internal),
266 M_DEVBUF, M_NOWAIT);
267 dconf->emulops = type->textops;
268 dconf->emulcookie = cookie;
269 if (dconf->emulops) {
270 dconf->wsemul = wsemul_pick(emul);
271 if (dconf->wsemul == NULL) {
272 free(dconf, M_DEVBUF);
273 free(scr, M_DEVBUF);
274 return (NULL);
275 }
276 dconf->wsemulcookie =
277 (*dconf->wsemul->attach)(0, type, cookie,
278 ccol, crow, scr, defattr);
279 } else
280 dconf->wsemul = NULL;
281 dconf->scrdata = type;
282 }
283
284 scr->scr_dconf = dconf;
285
286 scr->scr_tty = ttymalloc();
287 tty_attach(scr->scr_tty);
288 scr->scr_hold_screen = 0;
289 if (WSSCREEN_HAS_EMULATOR(scr))
290 scr->scr_flags = 0;
291 else
292 scr->scr_flags = SCR_GRAPHICS;
293
294 scr->scr_syncops = 0;
295 scr->sc = sc;
296 #ifdef WSDISPLAY_COMPAT_RAWKBD
297 scr->scr_rawkbd = 0;
298 #endif
299 return (scr);
300 }
301
302 void
303 wsscreen_detach(struct wsscreen *scr)
304 {
305 u_int ccol, crow; /* XXX */
306
307 if (WSSCREEN_HAS_TTY(scr)) {
308 tty_detach(scr->scr_tty);
309 ttyfree(scr->scr_tty);
310 }
311 if (WSSCREEN_HAS_EMULATOR(scr))
312 (*scr->scr_dconf->wsemul->detach)(scr->scr_dconf->wsemulcookie,
313 &ccol, &crow);
314 free(scr->scr_dconf, M_DEVBUF);
315 free(scr, M_DEVBUF);
316 }
317
318 const struct wsscreen_descr *
319 wsdisplay_screentype_pick(const struct wsscreen_list *scrdata, const char *name)
320 {
321 int i;
322 const struct wsscreen_descr *scr;
323
324 KASSERT(scrdata->nscreens > 0);
325
326 if (name == NULL)
327 return (scrdata->screens[0]);
328
329 for (i = 0; i < scrdata->nscreens; i++) {
330 scr = scrdata->screens[i];
331 if (!strcmp(name, scr->name))
332 return (scr);
333 }
334
335 return (0);
336 }
337
338 /*
339 * print info about attached screen
340 */
341 static void
342 wsdisplay_addscreen_print(struct wsdisplay_softc *sc, int idx, int count)
343 {
344 aprint_verbose_dev(sc->sc_dev, "screen %d", idx);
345 if (count > 1)
346 aprint_verbose("-%d", idx + (count-1));
347 aprint_verbose(" added (%s", sc->sc_scr[idx]->scr_dconf->scrdata->name);
348 if (WSSCREEN_HAS_EMULATOR(sc->sc_scr[idx])) {
349 aprint_verbose(", %s emulation",
350 sc->sc_scr[idx]->scr_dconf->wsemul->name);
351 }
352 aprint_verbose(")\n");
353 }
354
355 int
356 wsdisplay_addscreen(struct wsdisplay_softc *sc, int idx,
357 const char *screentype, const char *emul)
358 {
359 const struct wsscreen_descr *scrdesc;
360 int error;
361 void *cookie;
362 int ccol, crow;
363 long defattr;
364 struct wsscreen *scr;
365 int s;
366
367 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
368 return (EINVAL);
369 if (sc->sc_scr[idx] != NULL)
370 return (EBUSY);
371
372 scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype);
373 if (!scrdesc)
374 return (ENXIO);
375 error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie,
376 scrdesc, &cookie, &ccol, &crow, &defattr);
377 if (error)
378 return (error);
379
380 scr = wsscreen_attach(sc, 0, emul, scrdesc,
381 cookie, ccol, crow, defattr);
382 if (scr == NULL) {
383 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
384 cookie);
385 return (ENXIO);
386 }
387
388 sc->sc_scr[idx] = scr;
389
390 /* if no screen has focus yet, activate the first we get */
391 s = spltty();
392 if (!sc->sc_focus) {
393 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
394 scr->scr_dconf->emulcookie,
395 0, 0, 0);
396 sc->sc_focusidx = idx;
397 sc->sc_focus = scr;
398 }
399 splx(s);
400 return (0);
401 }
402
403 static void
404 wsdisplay_closescreen(struct wsdisplay_softc *sc, struct wsscreen *scr)
405 {
406 int maj, mn, idx;
407
408 /* hangup */
409 if (WSSCREEN_HAS_TTY(scr)) {
410 struct tty *tp = scr->scr_tty;
411 (*tp->t_linesw->l_modem)(tp, 0);
412 }
413
414 /* locate the major number */
415 maj = cdevsw_lookup_major(&wsdisplay_cdevsw);
416 /* locate the screen index */
417 for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++)
418 if (scr == sc->sc_scr[idx])
419 break;
420 #ifdef DIAGNOSTIC
421 if (idx == WSDISPLAY_MAXSCREEN)
422 panic("wsdisplay_forceclose: bad screen");
423 #endif
424
425 /* nuke the vnodes */
426 mn = WSDISPLAYMINOR(device_unit(sc->sc_dev), idx);
427 vdevgone(maj, mn, mn, VCHR);
428 }
429
430 #ifdef WSDISPLAY_SCROLLSUPPORT
431 void
432 wsdisplay_scroll(void *arg, int op)
433 {
434 device_t dv = arg;
435 struct wsdisplay_softc *sc = device_private(dv);
436 struct wsscreen *scr;
437 int lines;
438
439 scr = sc->sc_focus;
440
441 if (!scr)
442 return;
443
444 if (op == WSDISPLAY_SCROLL_RESET)
445 lines = 0;
446 else {
447 lines = (op & WSDISPLAY_SCROLL_LOW) ?
448 sc->sc_scroll_values.slowlines :
449 sc->sc_scroll_values.fastlines;
450 if (op & WSDISPLAY_SCROLL_BACKWARD)
451 lines = -(lines);
452 }
453
454 if (sc->sc_accessops->scroll) {
455 (*sc->sc_accessops->scroll)(sc->sc_accesscookie,
456 sc->sc_focus->scr_dconf->emulcookie, lines);
457 }
458 }
459 #endif
460
461 int
462 wsdisplay_delscreen(struct wsdisplay_softc *sc, int idx, int flags)
463 {
464 struct wsscreen *scr;
465 int s;
466 void *cookie;
467
468 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
469 return (EINVAL);
470 if ((scr = sc->sc_scr[idx]) == NULL)
471 return (ENXIO);
472
473 if (scr->scr_dconf == &wsdisplay_console_conf ||
474 scr->scr_syncops ||
475 ((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE)))
476 return(EBUSY);
477
478 wsdisplay_closescreen(sc, scr);
479
480 /*
481 * delete pointers, so neither device entries
482 * nor keyboard input can reference it anymore
483 */
484 s = spltty();
485 if (sc->sc_focus == scr) {
486 sc->sc_focus = 0;
487 #ifdef WSDISPLAY_COMPAT_RAWKBD
488 wsdisplay_update_rawkbd(sc, 0);
489 #endif
490 }
491 sc->sc_scr[idx] = 0;
492 splx(s);
493
494 /*
495 * Wake up processes waiting for the screen to
496 * be activated. Sleepers must check whether
497 * the screen still exists.
498 */
499 if (scr->scr_flags & SCR_WAITACTIVE)
500 wakeup(scr);
501
502 /* save a reference to the graphics screen */
503 cookie = scr->scr_dconf->emulcookie;
504
505 wsscreen_detach(scr);
506
507 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
508 cookie);
509
510 aprint_verbose_dev(sc->sc_dev, "screen %d deleted\n", idx);
511 return (0);
512 }
513
514 /*
515 * Autoconfiguration functions.
516 */
517 int
518 wsdisplay_emul_match(device_t parent, struct cfdata *match, void *aux)
519 {
520 struct wsemuldisplaydev_attach_args *ap = aux;
521
522 if (match->wsemuldisplaydevcf_console !=
523 WSEMULDISPLAYDEVCF_CONSOLE_UNK) {
524 /*
525 * If console-ness of device specified, either match
526 * exactly (at high priority), or fail.
527 */
528 if (match->wsemuldisplaydevcf_console != 0 &&
529 ap->console != 0)
530 return (10);
531 else
532 return (0);
533 }
534
535 /* If console-ness unspecified, it wins. */
536 return (1);
537 }
538
539 void
540 wsdisplay_emul_attach(device_t parent, device_t self, void *aux)
541 {
542 struct wsdisplay_softc *sc = device_private(self);
543 struct wsemuldisplaydev_attach_args *ap = aux;
544
545 sc->sc_dev = self;
546
547 /* Don't allow more than one console to attach */
548 if (wsdisplay_console_attached && ap->console)
549 ap->console = 0;
550
551 wsdisplay_common_attach(sc, ap->console,
552 device_cfdata(self)->wsemuldisplaydevcf_kbdmux, ap->scrdata,
553 ap->accessops, ap->accesscookie);
554
555 if (ap->console) {
556 int maj;
557
558 /* locate the major number */
559 maj = cdevsw_lookup_major(&wsdisplay_cdevsw);
560
561 cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(device_unit(self),
562 0));
563 }
564 }
565
566 /* Print function (for parent devices). */
567 int
568 wsemuldisplaydevprint(void *aux, const char *pnp)
569 {
570 #if 0 /* -Wunused */
571 struct wsemuldisplaydev_attach_args *ap = aux;
572 #endif
573
574 if (pnp)
575 aprint_normal("wsdisplay at %s", pnp);
576 #if 0 /* don't bother; it's ugly */
577 aprint_normal(" console %d", ap->console);
578 #endif
579
580 return (UNCONF);
581 }
582
583 int
584 wsdisplay_noemul_match(device_t parent, struct cfdata *match, void *aux)
585 {
586 #if 0 /* -Wunused */
587 struct wsdisplaydev_attach_args *ap = aux;
588 #endif
589
590 /* Always match. */
591 return (1);
592 }
593
594 void
595 wsdisplay_noemul_attach(device_t parent, device_t self, void *aux)
596 {
597 struct wsdisplay_softc *sc = device_private(self);
598 struct wsdisplaydev_attach_args *ap = aux;
599
600 sc->sc_dev = self;
601
602 wsdisplay_common_attach(sc, 0,
603 device_cfdata(self)->wsemuldisplaydevcf_kbdmux, NULL,
604 ap->accessops, ap->accesscookie);
605 }
606
607 static pnp_status_t
608 wsdisplay_power(device_t dv, pnp_request_t req, void *opaque)
609 {
610 struct wsdisplay_softc *sc = device_private(dv);
611 pnp_capabilities_t *pcaps;
612 pnp_state_t *pstate;
613
614 switch (req) {
615 case PNP_REQUEST_GET_CAPABILITIES:
616 pcaps = opaque;
617 pcaps->state = PNP_STATE_D0 | PNP_STATE_D3;
618 break;
619 case PNP_REQUEST_GET_STATE:
620 pstate = opaque;
621 *pstate = PNP_STATE_D0; /* XXX */
622 break;
623 case PNP_REQUEST_SET_STATE:
624 pstate = opaque;
625 switch (*pstate) {
626 case PNP_STATE_D0:
627 wsdisplay_switchto(sc->sc_pmstate.screen);
628 break;
629 case PNP_STATE_D3:
630 if (sc->sc_focus != NULL)
631 sc->sc_pmstate.screen = sc->sc_focusidx;
632 else
633 sc->sc_pmstate.screen = 0;
634 wsdisplay_switchto(0);
635 break;
636 default:
637 return PNP_STATUS_UNSUPPORTED;
638 }
639 break;
640 default:
641 return PNP_STATUS_UNSUPPORTED;
642 }
643
644 return PNP_STATUS_SUCCESS;
645 }
646
647 /* Print function (for parent devices). */
648 int
649 wsdisplaydevprint(void *aux, const char *pnp)
650 {
651 #if 0 /* -Wunused */
652 struct wsdisplaydev_attach_args *ap = aux;
653 #endif
654
655 if (pnp)
656 aprint_normal("wsdisplay at %s", pnp);
657
658 return (UNCONF);
659 }
660
661 static void
662 wsdisplay_common_attach(struct wsdisplay_softc *sc, int console, int kbdmux,
663 const struct wsscreen_list *scrdata,
664 const struct wsdisplay_accessops *accessops,
665 void *accesscookie)
666 {
667 static int hookset;
668 int i, start=0;
669 #if NWSKBD > 0
670 struct wsevsrc *kme;
671 #if NWSMUX > 0
672 struct wsmux_softc *mux;
673
674 if (kbdmux >= 0)
675 mux = wsmux_getmux(kbdmux);
676 else
677 mux = wsmux_create("dmux", device_unit(sc->sc_dev));
678 /* XXX panic()ing isn't nice, but attach cannot fail */
679 if (mux == NULL)
680 panic("wsdisplay_common_attach: no memory");
681 sc->sc_input = &mux->sc_base;
682 mux->sc_base.me_dispdv = sc->sc_dev;
683 aprint_normal(" kbdmux %d", kbdmux);
684 #else
685 if (kbdmux >= 0)
686 aprint_normal(" (kbdmux ignored)");
687 #endif
688 #endif
689
690 sc->sc_isconsole = console;
691
692 if (console) {
693 KASSERT(wsdisplay_console_initted);
694 KASSERT(wsdisplay_console_device == NULL);
695
696 sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0);
697 wsdisplay_console_device = sc;
698
699 aprint_normal(": console (%s, %s emulation)",
700 wsdisplay_console_conf.scrdata->name,
701 wsdisplay_console_conf.wsemul->name);
702
703 #if NWSKBD > 0
704 kme = wskbd_set_console_display(sc->sc_dev, sc->sc_input);
705 if (kme != NULL)
706 aprint_normal(", using %s", kme->me_dv.dv_xname);
707 #if NWSMUX == 0
708 sc->sc_input = kme;
709 #endif
710 #endif
711
712 sc->sc_focusidx = 0;
713 sc->sc_focus = sc->sc_scr[0];
714 start = 1;
715
716 wsdisplay_console_attached = 1;
717 }
718 aprint_normal("\n");
719
720 #if NWSKBD > 0 && NWSMUX > 0
721 wsmux_set_display(mux, sc->sc_dev);
722 #endif
723
724 sc->sc_accessops = accessops;
725 sc->sc_accesscookie = accesscookie;
726 sc->sc_scrdata = scrdata;
727
728 #ifdef WSDISPLAY_SCROLLSUPPORT
729 sc->sc_scroll_values = wsdisplay_default_scroll_values;
730 #endif
731
732 /*
733 * Set up a number of virtual screens if wanted. The
734 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code
735 * is for special cases like installation kernels.
736 */
737 for (i = start; i < wsdisplay_defaultscreens; i++) {
738 if (wsdisplay_addscreen(sc, i, 0, 0))
739 break;
740 }
741
742 if (i > start)
743 wsdisplay_addscreen_print(sc, start, i-start);
744
745 if (pnp_register(sc->sc_dev, wsdisplay_power) != PNP_STATUS_SUCCESS)
746 aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n");
747
748 if (hookset == 0)
749 shutdownhook_establish(wsdisplay_shutdownhook, NULL);
750 hookset = 1;
751 }
752
753 void
754 wsdisplay_cnattach(const struct wsscreen_descr *type, void *cookie,
755 int ccol, int crow, long defattr)
756 {
757 const struct wsemul_ops *wsemul;
758
759 KASSERT(wsdisplay_console_initted < 2);
760 KASSERT(type->nrows > 0);
761 KASSERT(type->ncols > 0);
762 KASSERT(crow < type->nrows);
763 KASSERT(ccol < type->ncols);
764
765 wsdisplay_console_conf.emulops = type->textops;
766 wsdisplay_console_conf.emulcookie = cookie;
767 wsdisplay_console_conf.scrdata = type;
768
769 wsemul = wsemul_pick(0); /* default */
770 wsdisplay_console_conf.wsemul = wsemul;
771 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
772 ccol, crow,
773 defattr);
774
775 cn_tab = &wsdisplay_cons;
776 wsdisplay_console_initted = 2;
777 }
778
779 void
780 wsdisplay_preattach(const struct wsscreen_descr *type, void *cookie,
781 int ccol, int crow, long defattr)
782 {
783 const struct wsemul_ops *wsemul;
784
785 KASSERT(!wsdisplay_console_initted);
786 KASSERT(type->nrows > 0);
787 KASSERT(type->ncols > 0);
788 KASSERT(crow < type->nrows);
789 KASSERT(ccol < type->ncols);
790
791 wsdisplay_console_conf.emulops = type->textops;
792 wsdisplay_console_conf.emulcookie = cookie;
793 wsdisplay_console_conf.scrdata = type;
794
795 wsemul = wsemul_pick(0); /* default */
796 wsdisplay_console_conf.wsemul = wsemul;
797 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
798 ccol, crow,
799 defattr);
800
801 cn_tab = &wsdisplay_cons;
802 wsdisplay_console_initted = 1;
803 }
804
805 /*
806 * Tty and cdevsw functions.
807 */
808 int
809 wsdisplayopen(dev_t dev, int flag, int mode, struct lwp *l)
810 {
811 device_t dv;
812 struct wsdisplay_softc *sc;
813 struct tty *tp;
814 int newopen, error;
815 struct wsscreen *scr;
816
817 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
818 if (dv == NULL) /* make sure it was attached */
819 return (ENXIO);
820
821 sc = device_private(dv);
822
823 if (ISWSDISPLAYSTAT(dev)) {
824 wsevent_init(&sc->evar, l->l_proc);
825 return (0);
826 }
827
828 if (ISWSDISPLAYCTL(dev))
829 return (0);
830
831 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN)
832 return (ENXIO);
833 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
834 return (ENXIO);
835
836 if (WSSCREEN_HAS_TTY(scr)) {
837 tp = scr->scr_tty;
838 tp->t_oproc = wsdisplaystart;
839 tp->t_param = wsdisplayparam;
840 tp->t_dev = dev;
841 newopen = (tp->t_state & TS_ISOPEN) == 0;
842
843 if (kauth_authorize_device_tty(l->l_cred,
844 KAUTH_DEVICE_TTY_OPEN, tp))
845 return (EBUSY);
846
847 if (newopen) {
848 ttychars(tp);
849 tp->t_iflag = TTYDEF_IFLAG;
850 tp->t_oflag = TTYDEF_OFLAG;
851 tp->t_cflag = TTYDEF_CFLAG;
852 tp->t_lflag = TTYDEF_LFLAG;
853 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
854 wsdisplayparam(tp, &tp->t_termios);
855 ttsetwater(tp);
856 }
857 tp->t_state |= TS_CARR_ON;
858
859 error = ((*tp->t_linesw->l_open)(dev, tp));
860 if (error)
861 return (error);
862
863 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) {
864 /* set window sizes as appropriate, and reset
865 the emulation */
866 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows;
867 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols;
868
869 /* wsdisplay_set_emulation() */
870 }
871 }
872
873 scr->scr_flags |= SCR_OPEN;
874 return (0);
875 }
876
877 int
878 wsdisplayclose(dev_t dev, int flag, int mode, struct lwp *l)
879 {
880 device_t dv;
881 struct wsdisplay_softc *sc;
882 struct tty *tp;
883 struct wsscreen *scr;
884
885 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
886 sc = device_private(dv);
887
888 if (ISWSDISPLAYSTAT(dev)) {
889 wsevent_fini(&sc->evar);
890 return (0);
891 }
892
893 if (ISWSDISPLAYCTL(dev))
894 return (0);
895
896 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
897 return (0);
898
899 if (WSSCREEN_HAS_TTY(scr)) {
900 if (scr->scr_hold_screen) {
901 int s;
902
903 /* XXX RESET KEYBOARD LEDS, etc. */
904 s = spltty(); /* avoid conflict with keyboard */
905 wsdisplay_kbdholdscreen(dv, 0);
906 splx(s);
907 }
908 tp = scr->scr_tty;
909 (*tp->t_linesw->l_close)(tp, flag);
910 ttyclose(tp);
911 }
912
913 if (scr->scr_syncops)
914 (*scr->scr_syncops->destroy)(scr->scr_synccookie);
915
916 if (WSSCREEN_HAS_EMULATOR(scr)) {
917 scr->scr_flags &= ~SCR_GRAPHICS;
918 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
919 WSEMUL_RESET);
920 if (wsdisplay_clearonclose)
921 (*scr->scr_dconf->wsemul->reset)
922 (scr->scr_dconf->wsemulcookie,
923 WSEMUL_CLEARSCREEN);
924 }
925
926 #ifdef WSDISPLAY_COMPAT_RAWKBD
927 if (scr->scr_rawkbd) {
928 int kbmode = WSKBD_TRANSLATED;
929 (void)wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE,
930 (void *)&kbmode, 0, l);
931 }
932 #endif
933
934 scr->scr_flags &= ~SCR_OPEN;
935
936 return (0);
937 }
938
939 int
940 wsdisplayread(dev_t dev, struct uio *uio, int flag)
941 {
942 device_t dv;
943 struct wsdisplay_softc *sc;
944 struct tty *tp;
945 struct wsscreen *scr;
946 int error;
947
948 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
949 sc = device_private(dv);
950
951 if (ISWSDISPLAYSTAT(dev)) {
952 error = wsevent_read(&sc->evar, uio, flag);
953 return (error);
954 }
955
956 if (ISWSDISPLAYCTL(dev))
957 return (0);
958
959 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
960 return (ENXIO);
961
962 if (!WSSCREEN_HAS_TTY(scr))
963 return (ENODEV);
964
965 tp = scr->scr_tty;
966 return ((*tp->t_linesw->l_read)(tp, uio, flag));
967 }
968
969 int
970 wsdisplaywrite(dev_t dev, struct uio *uio, int flag)
971 {
972 device_t dv;
973 struct wsdisplay_softc *sc;
974 struct tty *tp;
975 struct wsscreen *scr;
976
977 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
978 sc = device_private(dv);
979
980 if (ISWSDISPLAYSTAT(dev)) {
981 return (0);
982 }
983
984 if (ISWSDISPLAYCTL(dev))
985 return (0);
986
987 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
988 return (ENXIO);
989
990 if (!WSSCREEN_HAS_TTY(scr))
991 return (ENODEV);
992
993 tp = scr->scr_tty;
994 return ((*tp->t_linesw->l_write)(tp, uio, flag));
995 }
996
997 int
998 wsdisplaypoll(dev_t dev, int events, struct lwp *l)
999 {
1000 device_t dv;
1001 struct wsdisplay_softc *sc;
1002 struct tty *tp;
1003 struct wsscreen *scr;
1004
1005 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1006 sc = device_private(dv);
1007
1008 if (ISWSDISPLAYSTAT(dev))
1009 return (wsevent_poll(&sc->evar, events, l));
1010
1011 if (ISWSDISPLAYCTL(dev))
1012 return (0);
1013
1014 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1015 return (POLLHUP);
1016
1017 if (!WSSCREEN_HAS_TTY(scr))
1018 return (POLLERR);
1019
1020 tp = scr->scr_tty;
1021 return ((*tp->t_linesw->l_poll)(tp, events, l));
1022 }
1023
1024 int
1025 wsdisplaykqfilter(dev_t dev, struct knote *kn)
1026 {
1027 device_t dv;
1028 struct wsdisplay_softc *sc;
1029 struct wsscreen *scr;
1030
1031 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1032 sc = device_private(dv);
1033
1034 if (ISWSDISPLAYCTL(dev))
1035 return (1);
1036
1037 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1038 return (1);
1039
1040
1041 if (WSSCREEN_HAS_TTY(scr))
1042 return (ttykqfilter(dev, kn));
1043 else
1044 return (1);
1045 }
1046
1047 struct tty *
1048 wsdisplaytty(dev_t dev)
1049 {
1050 device_t dv;
1051 struct wsdisplay_softc *sc;
1052 struct wsscreen *scr;
1053
1054 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1055 sc = device_private(dv);
1056
1057 if (ISWSDISPLAYSTAT(dev))
1058 panic("wsdisplaytty() on status device");
1059
1060 if (ISWSDISPLAYCTL(dev))
1061 panic("wsdisplaytty() on ctl device");
1062
1063 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1064 return NULL;
1065
1066 return (scr->scr_tty);
1067 }
1068
1069 int
1070 wsdisplayioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1071 {
1072 device_t dv;
1073 struct wsdisplay_softc *sc;
1074 struct tty *tp;
1075 int error;
1076 struct wsscreen *scr;
1077
1078 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1079 sc = device_private(dv);
1080
1081 #ifdef WSDISPLAY_COMPAT_USL
1082 error = wsdisplay_usl_ioctl1(dv, cmd, data, flag, l);
1083 if (error != EPASSTHROUGH)
1084 return (error);
1085 #endif
1086
1087 if (ISWSDISPLAYSTAT(dev))
1088 return (wsdisplay_stat_ioctl(sc, cmd, data, flag, l));
1089
1090 if (ISWSDISPLAYCTL(dev))
1091 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, l));
1092
1093 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1094 return (ENXIO);
1095
1096 if (WSSCREEN_HAS_TTY(scr)) {
1097 tp = scr->scr_tty;
1098
1099 /* printf("disc\n"); */
1100 /* do the line discipline ioctls first */
1101 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
1102 if (error != EPASSTHROUGH)
1103 return (error);
1104
1105 /* printf("tty\n"); */
1106 /* then the tty ioctls */
1107 error = ttioctl(tp, cmd, data, flag, l);
1108 if (error != EPASSTHROUGH)
1109 return (error);
1110 }
1111
1112 #ifdef WSDISPLAY_COMPAT_USL
1113 error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, l);
1114 if (error != EPASSTHROUGH)
1115 return (error);
1116 #endif
1117
1118 return (wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, l));
1119 }
1120
1121 int
1122 wsdisplay_param(device_t dv, u_long cmd, struct wsdisplay_param *dp)
1123 {
1124 struct wsdisplay_softc *sc = device_private(dv);
1125 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1126 sc->sc_focus->scr_dconf->emulcookie,
1127 cmd, (void *)dp, 0, NULL));
1128 }
1129
1130 int
1131 wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr,
1132 u_long cmd, void *data, int flag, struct lwp *l)
1133 {
1134 int error;
1135 char namebuf[16];
1136 struct wsdisplay_font fd;
1137 #ifdef WSDISPLAY_SCROLLSUPPORT
1138 struct wsdisplay_scroll_data *ksdp, *usdp;
1139 #endif
1140
1141 #if NWSKBD > 0
1142 struct wsevsrc *inp;
1143
1144 #ifdef WSDISPLAY_COMPAT_RAWKBD
1145 switch (cmd) {
1146 case WSKBDIO_SETMODE:
1147 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW);
1148 return (wsdisplay_update_rawkbd(sc, scr));
1149 case WSKBDIO_GETMODE:
1150 *(int *)data = (scr->scr_rawkbd ?
1151 WSKBD_RAW : WSKBD_TRANSLATED);
1152 return (0);
1153 }
1154 #endif
1155 inp = sc->sc_input;
1156 if (inp == NULL)
1157 return (ENXIO);
1158 error = wsevsrc_display_ioctl(inp, cmd, data, flag, l);
1159 if (error != EPASSTHROUGH)
1160 return (error);
1161 #endif /* NWSKBD > 0 */
1162
1163 switch (cmd) {
1164 case WSDISPLAYIO_GMODE:
1165 if (scr->scr_flags & SCR_GRAPHICS) {
1166 if (scr->scr_flags & SCR_DUMBFB)
1167 *(u_int *)data = WSDISPLAYIO_MODE_DUMBFB;
1168 else
1169 *(u_int *)data = WSDISPLAYIO_MODE_MAPPED;
1170 } else
1171 *(u_int *)data = WSDISPLAYIO_MODE_EMUL;
1172 return (0);
1173
1174 case WSDISPLAYIO_SMODE:
1175 #define d (*(int *)data)
1176 if (d != WSDISPLAYIO_MODE_EMUL &&
1177 d != WSDISPLAYIO_MODE_MAPPED &&
1178 d != WSDISPLAYIO_MODE_DUMBFB)
1179 return (EINVAL);
1180
1181 if (WSSCREEN_HAS_EMULATOR(scr)) {
1182 scr->scr_flags &= ~SCR_GRAPHICS;
1183 if (d == WSDISPLAYIO_MODE_MAPPED ||
1184 d == WSDISPLAYIO_MODE_DUMBFB)
1185 scr->scr_flags |= SCR_GRAPHICS |
1186 ((d == WSDISPLAYIO_MODE_DUMBFB) ? SCR_DUMBFB : 0);
1187 } else if (d == WSDISPLAYIO_MODE_EMUL)
1188 return (EINVAL);
1189
1190 (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1191 scr->scr_dconf->emulcookie, cmd, data, flag, l);
1192
1193 return (0);
1194 #undef d
1195
1196 #ifdef WSDISPLAY_SCROLLSUPPORT
1197 #define SETSCROLLLINES(dstp, srcp, dfltp) \
1198 do { \
1199 (dstp)->fastlines = ((srcp)->which & \
1200 WSDISPLAY_SCROLL_DOFASTLINES) ? \
1201 (srcp)->fastlines : (dfltp)->fastlines; \
1202 (dstp)->slowlines = ((srcp)->which & \
1203 WSDISPLAY_SCROLL_DOSLOWLINES) ? \
1204 (srcp)->slowlines : (dfltp)->slowlines; \
1205 (dstp)->which = WSDISPLAY_SCROLL_DOALL; \
1206 } while (0)
1207
1208
1209 case WSDISPLAYIO_DSSCROLL:
1210 usdp = (struct wsdisplay_scroll_data *)data;
1211 ksdp = &sc->sc_scroll_values;
1212 SETSCROLLLINES(ksdp, usdp, ksdp);
1213 return (0);
1214
1215 case WSDISPLAYIO_DGSCROLL:
1216 usdp = (struct wsdisplay_scroll_data *)data;
1217 ksdp = &sc->sc_scroll_values;
1218 SETSCROLLLINES(usdp, ksdp, ksdp);
1219 return (0);
1220 #else
1221 case WSDISPLAYIO_DSSCROLL:
1222 case WSDISPLAYIO_DGSCROLL:
1223 return ENODEV;
1224 #endif
1225
1226 case WSDISPLAYIO_SFONT:
1227 #define d ((struct wsdisplay_usefontdata *)data)
1228 if (!sc->sc_accessops->load_font)
1229 return (EINVAL);
1230 if (d->name) {
1231 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0);
1232 if (error)
1233 return (error);
1234 fd.name = namebuf;
1235 } else
1236 fd.name = 0;
1237 fd.data = 0;
1238 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie,
1239 scr->scr_dconf->emulcookie, &fd);
1240 if (!error && WSSCREEN_HAS_EMULATOR(scr))
1241 (*scr->scr_dconf->wsemul->reset)
1242 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT);
1243 return (error);
1244 #undef d
1245
1246 #ifdef WSDISPLAY_CUSTOM_OUTPUT
1247 case WSDISPLAYIO_GMSGATTRS:
1248 #define d ((struct wsdisplay_msgattrs *)data)
1249 (*scr->scr_dconf->wsemul->getmsgattrs)
1250 (scr->scr_dconf->wsemulcookie, d);
1251 return (0);
1252 #undef d
1253
1254 case WSDISPLAYIO_SMSGATTRS: {
1255 #define d ((struct wsdisplay_msgattrs *)data)
1256 int i;
1257 for (i = 0; i < WSDISPLAY_MAXSCREEN; i++)
1258 if (sc->sc_scr[i] != NULL)
1259 (*sc->sc_scr[i]->scr_dconf->wsemul->setmsgattrs)
1260 (sc->sc_scr[i]->scr_dconf->wsemulcookie,
1261 sc->sc_scr[i]->scr_dconf->scrdata,
1262 d);
1263 }
1264 return (0);
1265 #undef d
1266 #else
1267 case WSDISPLAYIO_GMSGATTRS:
1268 case WSDISPLAYIO_SMSGATTRS:
1269 return (ENODEV);
1270 #endif
1271 }
1272
1273 /* check ioctls for display */
1274 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1275 scr->scr_dconf->emulcookie, cmd, data, flag, l));
1276 }
1277
1278 int
1279 wsdisplay_stat_ioctl(struct wsdisplay_softc *sc, u_long cmd, void *data,
1280 int flag, struct lwp *l)
1281 {
1282 switch (cmd) {
1283 case WSDISPLAYIO_GETACTIVESCREEN:
1284 *(int*)data = wsdisplay_getactivescreen(sc);
1285 return (0);
1286 }
1287
1288 return (EPASSTHROUGH);
1289 }
1290
1291 int
1292 wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, void *data,
1293 int flag, struct lwp *l)
1294 {
1295 int error;
1296 char *type, typebuf[16], *emul, emulbuf[16];
1297 void *tbuf;
1298 u_int fontsz;
1299 #if defined(COMPAT_14) && NWSKBD > 0
1300 struct wsmux_device wsmuxdata;
1301 #endif
1302 #if NWSKBD > 0
1303 struct wsevsrc *inp;
1304 #endif
1305
1306 switch (cmd) {
1307 case WSDISPLAYIO_ADDSCREEN:
1308 #define d ((struct wsdisplay_addscreendata *)data)
1309 if (d->screentype) {
1310 error = copyinstr(d->screentype, typebuf,
1311 sizeof(typebuf), 0);
1312 if (error)
1313 return (error);
1314 type = typebuf;
1315 } else
1316 type = 0;
1317 if (d->emul) {
1318 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf),0);
1319 if (error)
1320 return (error);
1321 emul = emulbuf;
1322 } else
1323 emul = 0;
1324
1325 if ((error = wsdisplay_addscreen(sc, d->idx, type, emul)) == 0)
1326 wsdisplay_addscreen_print(sc, d->idx, 0);
1327 return (error);
1328 #undef d
1329 case WSDISPLAYIO_DELSCREEN:
1330 #define d ((struct wsdisplay_delscreendata *)data)
1331 return (wsdisplay_delscreen(sc, d->idx, d->flags));
1332 #undef d
1333 case WSDISPLAYIO_LDFONT:
1334 #define d ((struct wsdisplay_font *)data)
1335 if (!sc->sc_accessops->load_font)
1336 return (EINVAL);
1337 if (d->name) {
1338 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0);
1339 if (error)
1340 return (error);
1341 d->name = typebuf;
1342 } else
1343 d->name = "loaded"; /* ??? */
1344 fontsz = d->fontheight * d->stride * d->numchars;
1345 if (fontsz > WSDISPLAY_MAXFONTSZ)
1346 return (EINVAL);
1347
1348 tbuf = malloc(fontsz, M_DEVBUF, M_WAITOK);
1349 error = copyin(d->data, tbuf, fontsz);
1350 if (error) {
1351 free(tbuf, M_DEVBUF);
1352 return (error);
1353 }
1354 d->data = tbuf;
1355 error =
1356 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d);
1357 free(tbuf, M_DEVBUF);
1358 #undef d
1359 return (error);
1360
1361 #if NWSKBD > 0
1362 #ifdef COMPAT_14
1363 case _O_WSDISPLAYIO_SETKEYBOARD:
1364 #define d ((struct wsdisplay_kbddata *)data)
1365 inp = sc->sc_input;
1366 if (inp == NULL)
1367 return (ENXIO);
1368 switch (d->op) {
1369 case _O_WSDISPLAY_KBD_ADD:
1370 if (d->idx == -1) {
1371 d->idx = wskbd_pickfree();
1372 if (d->idx == -1)
1373 return (ENXIO);
1374 }
1375 wsmuxdata.type = WSMUX_KBD;
1376 wsmuxdata.idx = d->idx;
1377 return (wsevsrc_ioctl(inp, WSMUX_ADD_DEVICE,
1378 &wsmuxdata, flag, l));
1379 case _O_WSDISPLAY_KBD_DEL:
1380 wsmuxdata.type = WSMUX_KBD;
1381 wsmuxdata.idx = d->idx;
1382 return (wsevsrc_ioctl(inp, WSMUX_REMOVE_DEVICE,
1383 &wsmuxdata, flag, l));
1384 default:
1385 return (EINVAL);
1386 }
1387 #undef d
1388 #endif
1389
1390 case WSMUXIO_ADD_DEVICE:
1391 #define d ((struct wsmux_device *)data)
1392 if (d->idx == -1 && d->type == WSMUX_KBD)
1393 d->idx = wskbd_pickfree();
1394 #undef d
1395 /* fall into */
1396 case WSMUXIO_INJECTEVENT:
1397 case WSMUXIO_REMOVE_DEVICE:
1398 case WSMUXIO_LIST_DEVICES:
1399 inp = sc->sc_input;
1400 if (inp == NULL)
1401 return (ENXIO);
1402 return (wsevsrc_ioctl(inp, cmd, data, flag, l));
1403 #endif /* NWSKBD > 0 */
1404
1405 }
1406 return (EPASSTHROUGH);
1407 }
1408
1409 int
1410 wsdisplay_stat_inject(device_t dv, u_int type, int value)
1411 {
1412 struct wsdisplay_softc *sc = device_private(dv);
1413 struct wseventvar *evar;
1414 struct wscons_event event;
1415
1416 evar = &sc->evar;
1417
1418 if (evar == NULL)
1419 return (0);
1420
1421 if (evar->q == NULL)
1422 return (1);
1423
1424 event.type = type;
1425 event.value = value;
1426 if (wsevent_inject(evar, &event, 1) != 0) {
1427 log(LOG_WARNING, "wsdisplay: event queue overflow\n");
1428 return (1);
1429 }
1430
1431 return (0);
1432 }
1433
1434 paddr_t
1435 wsdisplaymmap(dev_t dev, off_t offset, int prot)
1436 {
1437 device_t dv;
1438 struct wsdisplay_softc *sc;
1439 struct wsscreen *scr;
1440
1441 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1442 sc = device_private(dv);
1443
1444 if (ISWSDISPLAYSTAT(dev))
1445 return (-1);
1446
1447 if (ISWSDISPLAYCTL(dev))
1448 return (-1);
1449
1450 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1451 return (-1);
1452
1453 if (!(scr->scr_flags & SCR_GRAPHICS))
1454 return (-1);
1455
1456 /* pass mmap to display */
1457 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie,
1458 scr->scr_dconf->emulcookie, offset, prot));
1459 }
1460
1461 void
1462 wsdisplaystart(struct tty *tp)
1463 {
1464 device_t dv;
1465 struct wsdisplay_softc *sc;
1466 struct wsscreen *scr;
1467 int s, n;
1468 u_char *tbuf;
1469
1470 s = spltty();
1471 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
1472 splx(s);
1473 return;
1474 }
1475 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(tp->t_dev));
1476 sc = device_private(dv);
1477 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]) == NULL) {
1478 splx(s);
1479 return;
1480 }
1481
1482 if (scr->scr_hold_screen) {
1483 tp->t_state |= TS_TIMEOUT;
1484 splx(s);
1485 return;
1486 }
1487 tp->t_state |= TS_BUSY;
1488 splx(s);
1489
1490 /*
1491 * Drain output from ring buffer.
1492 * The output will normally be in one contiguous chunk, but when the
1493 * ring wraps, it will be in two pieces.. one at the end of the ring,
1494 * the other at the start. For performance, rather than loop here,
1495 * we output one chunk, see if there's another one, and if so, output
1496 * it too.
1497 */
1498
1499 n = ndqb(&tp->t_outq, 0);
1500 tbuf = tp->t_outq.c_cf;
1501
1502 if (!(scr->scr_flags & SCR_GRAPHICS)) {
1503 KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1504 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
1505 tbuf, n, 0);
1506 }
1507 ndflush(&tp->t_outq, n);
1508
1509 if ((n = ndqb(&tp->t_outq, 0)) > 0) {
1510 tbuf = tp->t_outq.c_cf;
1511
1512 if (!(scr->scr_flags & SCR_GRAPHICS)) {
1513 KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1514 (*scr->scr_dconf->wsemul->output)
1515 (scr->scr_dconf->wsemulcookie, tbuf, n, 0);
1516 }
1517 ndflush(&tp->t_outq, n);
1518 }
1519
1520 s = spltty();
1521 tp->t_state &= ~TS_BUSY;
1522 /* Come back if there's more to do */
1523 if (tp->t_outq.c_cc) {
1524 tp->t_state |= TS_TIMEOUT;
1525 callout_schedule(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1);
1526 }
1527 if (tp->t_outq.c_cc <= tp->t_lowat) {
1528 if (tp->t_state&TS_ASLEEP) {
1529 tp->t_state &= ~TS_ASLEEP;
1530 wakeup(&tp->t_outq);
1531 }
1532 selwakeup(&tp->t_wsel);
1533 }
1534 splx(s);
1535 }
1536
1537 void
1538 wsdisplaystop(struct tty *tp, int flag)
1539 {
1540 int s;
1541
1542 s = spltty();
1543 if (ISSET(tp->t_state, TS_BUSY))
1544 if (!ISSET(tp->t_state, TS_TTSTOP))
1545 SET(tp->t_state, TS_FLUSH);
1546 splx(s);
1547 }
1548
1549 /* Set line parameters. */
1550 int
1551 wsdisplayparam(struct tty *tp, struct termios *t)
1552 {
1553
1554 tp->t_ispeed = t->c_ispeed;
1555 tp->t_ospeed = t->c_ospeed;
1556 tp->t_cflag = t->c_cflag;
1557 return 0;
1558 }
1559
1560 /*
1561 * Callbacks for the emulation code.
1562 */
1563 void
1564 wsdisplay_emulbell(void *v)
1565 {
1566 struct wsscreen *scr = v;
1567
1568 if (scr == NULL) /* console, before real attach */
1569 return;
1570
1571 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */
1572 return;
1573
1574 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL,
1575 FWRITE, NULL);
1576 }
1577
1578 void
1579 wsdisplay_emulinput(void *v, const u_char *data, u_int count)
1580 {
1581 struct wsscreen *scr = v;
1582 struct tty *tp;
1583
1584 if (v == NULL) /* console, before real attach */
1585 return;
1586
1587 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */
1588 return;
1589 if (!WSSCREEN_HAS_TTY(scr))
1590 return;
1591
1592 tp = scr->scr_tty;
1593 while (count-- > 0)
1594 (*tp->t_linesw->l_rint)(*data++, tp);
1595 }
1596
1597 /*
1598 * Calls from the keyboard interface.
1599 */
1600 void
1601 wsdisplay_kbdinput(device_t dv, keysym_t ks)
1602 {
1603 struct wsdisplay_softc *sc = device_private(dv);
1604 struct wsscreen *scr;
1605 const char *dp;
1606 int count;
1607 struct tty *tp;
1608
1609 KASSERT(sc != NULL);
1610
1611 scr = sc->sc_focus;
1612
1613 if (!scr || !WSSCREEN_HAS_TTY(scr))
1614 return;
1615
1616 tp = scr->scr_tty;
1617
1618 if (KS_GROUP(ks) == KS_GROUP_Ascii)
1619 (*tp->t_linesw->l_rint)(KS_VALUE(ks), tp);
1620 else if (WSSCREEN_HAS_EMULATOR(scr)) {
1621 count = (*scr->scr_dconf->wsemul->translate)
1622 (scr->scr_dconf->wsemulcookie, ks, &dp);
1623 while (count-- > 0)
1624 (*tp->t_linesw->l_rint)(*dp++, tp);
1625 }
1626 }
1627
1628 #if defined(WSDISPLAY_COMPAT_RAWKBD)
1629 int
1630 wsdisplay_update_rawkbd(struct wsdisplay_softc *sc, struct wsscreen *scr)
1631 {
1632 #if NWSKBD > 0
1633 int s, raw, data, error;
1634 struct wsevsrc *inp;
1635
1636 s = spltty();
1637
1638 raw = (scr ? scr->scr_rawkbd : 0);
1639
1640 if (scr != sc->sc_focus ||
1641 sc->sc_rawkbd == raw) {
1642 splx(s);
1643 return (0);
1644 }
1645
1646 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED;
1647 inp = sc->sc_input;
1648 if (inp == NULL) {
1649 splx(s);
1650 return (ENXIO);
1651 }
1652 error = wsevsrc_display_ioctl(inp, WSKBDIO_SETMODE, &data, 0, 0);
1653 if (!error)
1654 sc->sc_rawkbd = raw;
1655 splx(s);
1656 return (error);
1657 #else
1658 return (0);
1659 #endif
1660 }
1661 #endif
1662
1663 static void
1664 wsdisplay_switch3_cb(void *arg, int error, int waitok)
1665 {
1666 device_t dv = arg;
1667
1668 wsdisplay_switch3(dv, error, waitok);
1669 }
1670
1671 static int
1672 wsdisplay_switch3(device_t dv, int error, int waitok)
1673 {
1674 struct wsdisplay_softc *sc = device_private(dv);
1675 int no;
1676 struct wsscreen *scr;
1677
1678 if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1679 aprint_error_dev(dv, "wsdisplay_switch3: not switching\n");
1680 return (EINVAL);
1681 }
1682
1683 no = sc->sc_screenwanted;
1684 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1685 panic("wsdisplay_switch3: invalid screen %d", no);
1686 scr = sc->sc_scr[no];
1687 if (!scr) {
1688 aprint_error_dev(dv,
1689 "wsdisplay_switch3: screen %d disappeared\n", no);
1690 error = ENXIO;
1691 }
1692
1693 if (error) {
1694 /* try to recover, avoid recursion */
1695
1696 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) {
1697 aprint_error_dev(dv, "wsdisplay_switch3: giving up\n");
1698 sc->sc_focus = 0;
1699 #ifdef WSDISPLAY_COMPAT_RAWKBD
1700 wsdisplay_update_rawkbd(sc, 0);
1701 #endif
1702 sc->sc_flags &= ~SC_SWITCHPENDING;
1703 return (error);
1704 }
1705
1706 sc->sc_screenwanted = sc->sc_oldscreen;
1707 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
1708 return (wsdisplay_switch1(dv, 0, waitok));
1709 }
1710
1711 sc->sc_flags &= ~SC_SWITCHPENDING;
1712
1713 if (!error && (scr->scr_flags & SCR_WAITACTIVE))
1714 wakeup(scr);
1715 return (error);
1716 }
1717
1718 static void
1719 wsdisplay_switch2_cb(void *arg, int error, int waitok)
1720 {
1721 device_t dv = arg;
1722
1723 wsdisplay_switch2(dv, error, waitok);
1724 }
1725
1726 static int
1727 wsdisplay_switch2(device_t dv, int error, int waitok)
1728 {
1729 struct wsdisplay_softc *sc = device_private(dv);
1730 int no;
1731 struct wsscreen *scr;
1732
1733 if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1734 aprint_error_dev(dv, "wsdisplay_switch2: not switching\n");
1735 return (EINVAL);
1736 }
1737
1738 no = sc->sc_screenwanted;
1739 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1740 panic("wsdisplay_switch2: invalid screen %d", no);
1741 scr = sc->sc_scr[no];
1742 if (!scr) {
1743 aprint_error_dev(dv,
1744 "wsdisplay_switch2: screen %d disappeared\n", no);
1745 error = ENXIO;
1746 }
1747
1748 if (error) {
1749 /* try to recover, avoid recursion */
1750
1751 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) {
1752 aprint_error_dev(dv, "wsdisplay_switch2: giving up\n");
1753 sc->sc_focus = 0;
1754 sc->sc_flags &= ~SC_SWITCHPENDING;
1755 return (error);
1756 }
1757
1758 sc->sc_screenwanted = sc->sc_oldscreen;
1759 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
1760 return (wsdisplay_switch1(dv, 0, waitok));
1761 }
1762
1763 sc->sc_focusidx = no;
1764 sc->sc_focus = scr;
1765
1766 #ifdef WSDISPLAY_COMPAT_RAWKBD
1767 (void) wsdisplay_update_rawkbd(sc, scr);
1768 #endif
1769 /* keyboard map??? */
1770
1771 if (scr->scr_syncops) {
1772 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok,
1773 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsdisplay_switch3_cb, dv);
1774 if (error == EAGAIN) {
1775 /* switch will be done asynchronously */
1776 return (0);
1777 }
1778 }
1779
1780 return (wsdisplay_switch3(dv, error, waitok));
1781 }
1782
1783 static void
1784 wsdisplay_switch1_cb(void *arg, int error, int waitok)
1785 {
1786 device_t dv = arg;
1787
1788 wsdisplay_switch1(dv, error, waitok);
1789 }
1790
1791 static int
1792 wsdisplay_switch1(device_t dv, int error, int waitok)
1793 {
1794 struct wsdisplay_softc *sc = device_private(dv);
1795 int no;
1796 struct wsscreen *scr;
1797
1798 if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1799 aprint_error_dev(dv, "wsdisplay_switch1: not switching\n");
1800 return (EINVAL);
1801 }
1802
1803 no = sc->sc_screenwanted;
1804 if (no == WSDISPLAY_NULLSCREEN) {
1805 sc->sc_flags &= ~SC_SWITCHPENDING;
1806 if (!error) {
1807 sc->sc_focus = 0;
1808 }
1809 wakeup(sc);
1810 return (error);
1811 }
1812 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1813 panic("wsdisplay_switch1: invalid screen %d", no);
1814 scr = sc->sc_scr[no];
1815 if (!scr) {
1816 aprint_error_dev(dv, "wsdisplay_switch1: screen %d disappeared\n", no);
1817 error = ENXIO;
1818 }
1819
1820 if (error) {
1821 sc->sc_flags &= ~SC_SWITCHPENDING;
1822 return (error);
1823 }
1824
1825 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
1826 scr->scr_dconf->emulcookie,
1827 waitok,
1828 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsdisplay_switch2_cb, dv);
1829 if (error == EAGAIN) {
1830 /* switch will be done asynchronously */
1831 return (0);
1832 }
1833
1834 return (wsdisplay_switch2(dv, error, waitok));
1835 }
1836
1837 int
1838 wsdisplay_switch(device_t dv, int no, int waitok)
1839 {
1840 struct wsdisplay_softc *sc = device_private(dv);
1841 int s, res = 0;
1842 struct wsscreen *scr;
1843
1844 if (no != WSDISPLAY_NULLSCREEN) {
1845 if ((no < 0 || no >= WSDISPLAY_MAXSCREEN))
1846 return (EINVAL);
1847 if (sc->sc_scr[no] == NULL)
1848 return (ENXIO);
1849 }
1850
1851 wsdisplay_stat_inject(dv, WSCONS_EVENT_SCREEN_SWITCH, no);
1852
1853 s = spltty();
1854
1855 if ((sc->sc_focus && no == sc->sc_focusidx) ||
1856 (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) {
1857 splx(s);
1858 return (0);
1859 }
1860
1861 if (sc->sc_flags & SC_SWITCHPENDING) {
1862 splx(s);
1863 return (EBUSY);
1864 }
1865
1866 sc->sc_flags |= SC_SWITCHPENDING;
1867 sc->sc_screenwanted = no;
1868
1869 splx(s);
1870
1871 scr = sc->sc_focus;
1872 if (!scr) {
1873 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
1874 return (wsdisplay_switch1(dv, 0, waitok));
1875 } else
1876 sc->sc_oldscreen = sc->sc_focusidx;
1877
1878 if (scr->scr_syncops) {
1879 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok,
1880 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsdisplay_switch1_cb, dv);
1881 if (res == EAGAIN) {
1882 /* switch will be done asynchronously */
1883 return (0);
1884 }
1885 } else if (scr->scr_flags & SCR_GRAPHICS) {
1886 /* no way to save state */
1887 res = EBUSY;
1888 }
1889
1890 return (wsdisplay_switch1(dv, res, waitok));
1891 }
1892
1893 void
1894 wsdisplay_reset(device_t dv, enum wsdisplay_resetops op)
1895 {
1896 struct wsdisplay_softc *sc = device_private(dv);
1897 struct wsscreen *scr;
1898
1899 KASSERT(sc != NULL);
1900 scr = sc->sc_focus;
1901
1902 if (!scr)
1903 return;
1904
1905 switch (op) {
1906 case WSDISPLAY_RESETEMUL:
1907 if (!WSSCREEN_HAS_EMULATOR(scr))
1908 break;
1909 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
1910 WSEMUL_RESET);
1911 break;
1912 case WSDISPLAY_RESETCLOSE:
1913 wsdisplay_closescreen(sc, scr);
1914 break;
1915 }
1916 }
1917
1918 /*
1919 * Interface for (external) VT switch / process synchronization code
1920 */
1921 int
1922 wsscreen_attach_sync(struct wsscreen *scr, const struct wscons_syncops *ops,
1923 void *cookie)
1924 {
1925 if (scr->scr_syncops) {
1926 /*
1927 * The screen is already claimed.
1928 * Check if the owner is still alive.
1929 */
1930 if ((*scr->scr_syncops->check)(scr->scr_synccookie))
1931 return (EBUSY);
1932 }
1933 scr->scr_syncops = ops;
1934 scr->scr_synccookie = cookie;
1935 return (0);
1936 }
1937
1938 int
1939 wsscreen_detach_sync(struct wsscreen *scr)
1940 {
1941 if (!scr->scr_syncops)
1942 return (EINVAL);
1943 scr->scr_syncops = 0;
1944 return (0);
1945 }
1946
1947 int
1948 wsscreen_lookup_sync(struct wsscreen *scr,
1949 const struct wscons_syncops *ops, /* used as ID */
1950 void **cookiep)
1951 {
1952 if (!scr->scr_syncops || ops != scr->scr_syncops)
1953 return (EINVAL);
1954 *cookiep = scr->scr_synccookie;
1955 return (0);
1956 }
1957
1958 /*
1959 * Interface to virtual screen stuff
1960 */
1961 int
1962 wsdisplay_maxscreenidx(struct wsdisplay_softc *sc)
1963 {
1964 return (WSDISPLAY_MAXSCREEN - 1);
1965 }
1966
1967 int
1968 wsdisplay_screenstate(struct wsdisplay_softc *sc, int idx)
1969 {
1970 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
1971 return (EINVAL);
1972 if (!sc->sc_scr[idx])
1973 return (ENXIO);
1974 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0);
1975 }
1976
1977 int
1978 wsdisplay_getactivescreen(struct wsdisplay_softc *sc)
1979 {
1980 return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN);
1981 }
1982
1983 int
1984 wsscreen_switchwait(struct wsdisplay_softc *sc, int no)
1985 {
1986 struct wsscreen *scr;
1987 int s, res = 0;
1988
1989 if (no == WSDISPLAY_NULLSCREEN) {
1990 s = spltty();
1991 while (sc->sc_focus && res == 0) {
1992 res = tsleep(sc, PCATCH, "wswait", 0);
1993 }
1994 splx(s);
1995 return (res);
1996 }
1997
1998 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1999 return (ENXIO);
2000 scr = sc->sc_scr[no];
2001 if (!scr)
2002 return (ENXIO);
2003
2004 s = spltty();
2005 if (scr != sc->sc_focus) {
2006 scr->scr_flags |= SCR_WAITACTIVE;
2007 res = tsleep(scr, PCATCH, "wswait", 0);
2008 if (scr != sc->sc_scr[no])
2009 res = ENXIO; /* disappeared in the meantime */
2010 else
2011 scr->scr_flags &= ~SCR_WAITACTIVE;
2012 }
2013 splx(s);
2014 return (res);
2015 }
2016
2017 void
2018 wsdisplay_kbdholdscreen(device_t dv, int hold)
2019 {
2020 struct wsdisplay_softc *sc = device_private(dv);
2021 struct wsscreen *scr;
2022
2023 scr = sc->sc_focus;
2024
2025 if (hold)
2026 scr->scr_hold_screen = 1;
2027 else {
2028 scr->scr_hold_screen = 0;
2029 callout_schedule(&scr->scr_tty->t_rstrt_ch, 0);
2030 }
2031 }
2032
2033 #if NWSKBD > 0
2034 void
2035 wsdisplay_set_console_kbd(struct wsevsrc *src)
2036 {
2037 if (wsdisplay_console_device == NULL) {
2038 src->me_dispdv = NULL;
2039 return;
2040 }
2041 #if NWSMUX > 0
2042 if (wsmux_attach_sc((struct wsmux_softc *)
2043 wsdisplay_console_device->sc_input, src)) {
2044 src->me_dispdv = NULL;
2045 return;
2046 }
2047 #else
2048 wsdisplay_console_device->sc_input = src;
2049 #endif
2050 src->me_dispdv = wsdisplay_console_device->sc_dev;
2051 }
2052 #endif /* NWSKBD > 0 */
2053
2054 /*
2055 * Console interface.
2056 */
2057 void
2058 wsdisplay_cnputc(dev_t dev, int i)
2059 {
2060 struct wsscreen_internal *dc;
2061 u_char c = i;
2062
2063 if (!wsdisplay_console_initted)
2064 return;
2065
2066 if ((wsdisplay_console_device != NULL) &&
2067 (wsdisplay_console_device->sc_scr[0] != NULL) &&
2068 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS))
2069 return;
2070
2071 dc = &wsdisplay_console_conf;
2072 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1);
2073 }
2074
2075 static int
2076 wsdisplay_getc_dummy(dev_t dev)
2077 {
2078 /* panic? */
2079 return (0);
2080 }
2081
2082 static void
2083 wsdisplay_pollc(dev_t dev, int on)
2084 {
2085
2086 wsdisplay_cons_pollmode = on;
2087
2088 /* notify to fb drivers */
2089 if (wsdisplay_console_device != NULL &&
2090 wsdisplay_console_device->sc_accessops->pollc != NULL)
2091 (*wsdisplay_console_device->sc_accessops->pollc)
2092 (wsdisplay_console_device->sc_accesscookie, on);
2093
2094 /* notify to kbd drivers */
2095 if (wsdisplay_cons_kbd_pollc)
2096 (*wsdisplay_cons_kbd_pollc)(NODEV, on);
2097 }
2098
2099 void
2100 wsdisplay_set_cons_kbd(int (*get)(dev_t), void (*poll)(dev_t, int),
2101 void (*bell)(dev_t, u_int, u_int, u_int))
2102 {
2103 wsdisplay_cons.cn_getc = get;
2104 wsdisplay_cons.cn_bell = bell;
2105 wsdisplay_cons_kbd_pollc = poll;
2106 }
2107
2108 void
2109 wsdisplay_unset_cons_kbd(void)
2110 {
2111 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy;
2112 wsdisplay_cons.cn_bell = NULL;
2113 wsdisplay_cons_kbd_pollc = 0;
2114 }
2115
2116 static void
2117 wsdisplay_switchto(int no)
2118 {
2119 struct wsdisplay_softc *sc;
2120 struct wsscreen *scr;
2121
2122 if (wsdisplay_console_device != NULL) {
2123 sc = wsdisplay_console_device;
2124 if ((scr = sc->sc_scr[no]) == NULL)
2125 return;
2126 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
2127 scr->scr_dconf->emulcookie,
2128 0, NULL, NULL);
2129 }
2130 }
2131
2132 /*
2133 * Switch the console display to it's first screen.
2134 */
2135 void
2136 wsdisplay_switchtoconsole(void)
2137 {
2138 wsdisplay_switchto(0);
2139 }
2140
2141 /*
2142 * Switch the console at shutdown.
2143 */
2144 static void
2145 wsdisplay_shutdownhook(void *arg)
2146 {
2147
2148 wsdisplay_switchtoconsole();
2149 }
2150