1 /* $NetBSD: wsdisplay.c,v 1.126 2009/01/22 20:40:20 drochner Exp $ */
4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
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.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: wsdisplay.c,v 1.126 2009/01/22 20:40:20 drochner Exp $");
36 #include "opt_wsdisplay_compat.h"
37 #include "opt_wsmsgattrs.h"
40 #include "wsdisplay.h"
42 #include <sys/param.h>
44 #include <sys/device.h>
45 #include <sys/ioctl.h>
47 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/syslog.h>
51 #include <sys/systm.h>
53 #include <sys/signalvar.h>
54 #include <sys/errno.h>
55 #include <sys/fcntl.h>
56 #include <sys/vnode.h>
57 #include <sys/kauth.h>
59 #include <dev/wscons/wsconsio.h>
60 #include <dev/wscons/wseventvar.h>
61 #include <dev/wscons/wsmuxvar.h>
62 #include <dev/wscons/wsdisplayvar.h>
63 #include <dev/wscons/wsksymvar.h>
64 #include <dev/wscons/wsksymdef.h>
65 #include <dev/wscons/wsemulvar.h>
66 #include <dev/wscons/wscons_callbacks.h>
69 struct wsscreen_internal
{
70 const struct wsdisplay_emulops
*emulops
;
73 const struct wsscreen_descr
*scrdata
;
75 const struct wsemul_ops
*wsemul
;
80 struct wsscreen_internal
*scr_dconf
;
83 int scr_hold_screen
; /* hold tty output */
86 #define SCR_OPEN 1 /* is it open? */
87 #define SCR_WAITACTIVE 2 /* someone waiting on activation */
88 #define SCR_GRAPHICS 4 /* graphics mode, no text (emulation) output */
89 #define SCR_DUMBFB 8 /* in use as a dumb fb (iff SCR_GRAPHICS) */
90 const struct wscons_syncops
*scr_syncops
;
93 #ifdef WSDISPLAY_COMPAT_RAWKBD
97 struct wsdisplay_softc
*sc
;
100 /* XXX this is to support a hack in emulinput, see comment below */
101 int scr_in_ttyoutput
;
105 struct wsscreen
*wsscreen_attach(struct wsdisplay_softc
*, int,
107 const struct wsscreen_descr
*, void *,
109 void wsscreen_detach(struct wsscreen
*);
110 int wsdisplay_addscreen(struct wsdisplay_softc
*, int, const char *, const char *);
111 static void wsdisplay_addscreen_print(struct wsdisplay_softc
*, int, int);
112 static void wsdisplay_closescreen(struct wsdisplay_softc
*, struct wsscreen
*);
113 int wsdisplay_delscreen(struct wsdisplay_softc
*, int, int);
115 #define WSDISPLAY_MAXSCREEN 8
117 struct wsdisplay_softc
{
120 const struct wsdisplay_accessops
*sc_accessops
;
121 void *sc_accesscookie
;
123 const struct wsscreen_list
*sc_scrdata
;
124 #ifdef WSDISPLAY_SCROLLSUPPORT
125 struct wsdisplay_scroll_data sc_scroll_values
;
128 struct wsscreen
*sc_scr
[WSDISPLAY_MAXSCREEN
];
129 int sc_focusidx
; /* available only if sc_focus isn't null */
130 struct wsscreen
*sc_focus
;
132 struct wseventvar evar
;
137 #define SC_SWITCHPENDING 1
138 #define SC_SWITCHERROR 2
139 #define SC_XATTACHED 4 /* X server active */
140 kmutex_t sc_flagsmtx
; /* for flags, might also be used for focus */
141 kcondvar_t sc_flagscv
;
143 int sc_screenwanted
, sc_oldscreen
; /* valid with SC_SWITCHPENDING */
146 struct wsevsrc
*sc_input
;
147 #ifdef WSDISPLAY_COMPAT_RAWKBD
150 #endif /* NWSKBD > 0 */
153 #ifdef WSDISPLAY_SCROLLSUPPORT
155 struct wsdisplay_scroll_data wsdisplay_default_scroll_values
= {
156 WSDISPLAY_SCROLL_DOALL
,
162 extern struct cfdriver wsdisplay_cd
;
164 /* Autoconfiguration definitions. */
165 static int wsdisplay_emul_match(device_t
, cfdata_t
, void *);
166 static void wsdisplay_emul_attach(device_t
, device_t
, void *);
167 static int wsdisplay_noemul_match(device_t
, cfdata_t
, void *);
168 static void wsdisplay_noemul_attach(device_t
, device_t
, void *);
169 static bool wsdisplay_suspend(device_t
, pmf_qual_t
);
171 CFATTACH_DECL_NEW(wsdisplay_emul
, sizeof (struct wsdisplay_softc
),
172 wsdisplay_emul_match
, wsdisplay_emul_attach
, NULL
, NULL
);
174 CFATTACH_DECL_NEW(wsdisplay_noemul
, sizeof (struct wsdisplay_softc
),
175 wsdisplay_noemul_match
, wsdisplay_noemul_attach
, NULL
, NULL
);
177 dev_type_open(wsdisplayopen
);
178 dev_type_close(wsdisplayclose
);
179 dev_type_read(wsdisplayread
);
180 dev_type_write(wsdisplaywrite
);
181 dev_type_ioctl(wsdisplayioctl
);
182 dev_type_stop(wsdisplaystop
);
183 dev_type_tty(wsdisplaytty
);
184 dev_type_poll(wsdisplaypoll
);
185 dev_type_mmap(wsdisplaymmap
);
186 dev_type_kqfilter(wsdisplaykqfilter
);
188 const struct cdevsw wsdisplay_cdevsw
= {
189 wsdisplayopen
, wsdisplayclose
, wsdisplayread
, wsdisplaywrite
,
190 wsdisplayioctl
, wsdisplaystop
, wsdisplaytty
, wsdisplaypoll
,
191 wsdisplaymmap
, wsdisplaykqfilter
, D_TTY
194 static void wsdisplaystart(struct tty
*);
195 static int wsdisplayparam(struct tty
*, struct termios
*);
198 #define WSDISPLAYUNIT(dev) (minor(dev) >> 8)
199 #define WSDISPLAYSCREEN(dev) (minor(dev) & 0xff)
200 #define ISWSDISPLAYSTAT(dev) (WSDISPLAYSCREEN(dev) == 254)
201 #define ISWSDISPLAYCTL(dev) (WSDISPLAYSCREEN(dev) == 255)
202 #define WSDISPLAYMINOR(unit, screen) (((unit) << 8) | (screen))
204 #define WSSCREEN_HAS_EMULATOR(scr) ((scr)->scr_dconf->wsemul != NULL)
205 #define WSSCREEN_HAS_TTY(scr) ((scr)->scr_tty != NULL)
207 static void wsdisplay_common_attach(struct wsdisplay_softc
*sc
,
208 int console
, int kbdmux
, const struct wsscreen_list
*,
209 const struct wsdisplay_accessops
*accessops
,
212 #ifdef WSDISPLAY_COMPAT_RAWKBD
213 int wsdisplay_update_rawkbd(struct wsdisplay_softc
*,
217 static int wsdisplay_console_initted
;
218 static int wsdisplay_console_attached
;
219 static struct wsdisplay_softc
*wsdisplay_console_device
;
220 static struct wsscreen_internal wsdisplay_console_conf
;
222 static int wsdisplay_getc_dummy(dev_t
);
223 static void wsdisplay_pollc(dev_t
, int);
225 static int wsdisplay_cons_pollmode
;
226 static void (*wsdisplay_cons_kbd_pollc
)(dev_t
, int);
228 static struct consdev wsdisplay_cons
= {
229 NULL
, NULL
, wsdisplay_getc_dummy
, wsdisplay_cnputc
,
230 wsdisplay_pollc
, NULL
, NULL
, NULL
, NODEV
, CN_NORMAL
233 #ifndef WSDISPLAY_DEFAULTSCREENS
234 # define WSDISPLAY_DEFAULTSCREENS 0
236 int wsdisplay_defaultscreens
= WSDISPLAY_DEFAULTSCREENS
;
238 static int wsdisplay_switch1(device_t
, int, int);
239 static void wsdisplay_switch1_cb(void *, int, int);
240 static int wsdisplay_switch2(device_t
, int, int);
241 static void wsdisplay_switch2_cb(void *, int, int);
242 static int wsdisplay_switch3(device_t
, int, int);
243 static void wsdisplay_switch3_cb(void *, int, int);
245 int wsdisplay_clearonclose
;
248 wsscreen_attach(struct wsdisplay_softc
*sc
, int console
, const char *emul
,
249 const struct wsscreen_descr
*type
, void *cookie
, int ccol
,
250 int crow
, long defattr
)
252 struct wsscreen_internal
*dconf
;
253 struct wsscreen
*scr
;
255 scr
= malloc(sizeof(struct wsscreen
), M_DEVBUF
, M_WAITOK
);
260 dconf
= &wsdisplay_console_conf
;
262 * If there's an emulation, tell it about the callback argument.
263 * The other stuff is already there.
265 if (dconf
->wsemul
!= NULL
)
266 (*dconf
->wsemul
->attach
)(1, 0, 0, 0, 0, scr
, 0);
267 } else { /* not console */
268 dconf
= malloc(sizeof(struct wsscreen_internal
),
270 dconf
->emulops
= type
->textops
;
271 dconf
->emulcookie
= cookie
;
272 if (dconf
->emulops
) {
273 dconf
->wsemul
= wsemul_pick(emul
);
274 if (dconf
->wsemul
== NULL
) {
275 free(dconf
, M_DEVBUF
);
279 dconf
->wsemulcookie
=
280 (*dconf
->wsemul
->attach
)(0, type
, cookie
,
281 ccol
, crow
, scr
, defattr
);
283 dconf
->wsemul
= NULL
;
284 dconf
->scrdata
= type
;
287 scr
->scr_dconf
= dconf
;
289 scr
->scr_tty
= ttymalloc();
290 tty_attach(scr
->scr_tty
);
291 scr
->scr_hold_screen
= 0;
292 if (WSSCREEN_HAS_EMULATOR(scr
))
295 scr
->scr_flags
= SCR_GRAPHICS
;
297 scr
->scr_syncops
= 0;
299 #ifdef WSDISPLAY_COMPAT_RAWKBD
306 wsscreen_detach(struct wsscreen
*scr
)
308 u_int ccol
, crow
; /* XXX */
310 if (WSSCREEN_HAS_TTY(scr
)) {
311 tty_detach(scr
->scr_tty
);
312 ttyfree(scr
->scr_tty
);
314 if (WSSCREEN_HAS_EMULATOR(scr
))
315 (*scr
->scr_dconf
->wsemul
->detach
)(scr
->scr_dconf
->wsemulcookie
,
317 free(scr
->scr_dconf
, M_DEVBUF
);
321 const struct wsscreen_descr
*
322 wsdisplay_screentype_pick(const struct wsscreen_list
*scrdata
, const char *name
)
325 const struct wsscreen_descr
*scr
;
327 KASSERT(scrdata
->nscreens
> 0);
330 return (scrdata
->screens
[0]);
332 for (i
= 0; i
< scrdata
->nscreens
; i
++) {
333 scr
= scrdata
->screens
[i
];
334 if (!strcmp(name
, scr
->name
))
342 * print info about attached screen
345 wsdisplay_addscreen_print(struct wsdisplay_softc
*sc
, int idx
, int count
)
347 aprint_verbose_dev(sc
->sc_dev
, "screen %d", idx
);
349 aprint_verbose("-%d", idx
+ (count
-1));
350 aprint_verbose(" added (%s", sc
->sc_scr
[idx
]->scr_dconf
->scrdata
->name
);
351 if (WSSCREEN_HAS_EMULATOR(sc
->sc_scr
[idx
])) {
352 aprint_verbose(", %s emulation",
353 sc
->sc_scr
[idx
]->scr_dconf
->wsemul
->name
);
355 aprint_verbose(")\n");
359 wsdisplay_addscreen(struct wsdisplay_softc
*sc
, int idx
,
360 const char *screentype
, const char *emul
)
362 const struct wsscreen_descr
*scrdesc
;
367 struct wsscreen
*scr
;
370 if (idx
< 0 || idx
>= WSDISPLAY_MAXSCREEN
)
372 if (sc
->sc_scr
[idx
] != NULL
)
375 scrdesc
= wsdisplay_screentype_pick(sc
->sc_scrdata
, screentype
);
378 error
= (*sc
->sc_accessops
->alloc_screen
)(sc
->sc_accesscookie
,
379 scrdesc
, &cookie
, &ccol
, &crow
, &defattr
);
383 scr
= wsscreen_attach(sc
, 0, emul
, scrdesc
,
384 cookie
, ccol
, crow
, defattr
);
386 (*sc
->sc_accessops
->free_screen
)(sc
->sc_accesscookie
,
391 sc
->sc_scr
[idx
] = scr
;
393 /* if no screen has focus yet, activate the first we get */
396 (*sc
->sc_accessops
->show_screen
)(sc
->sc_accesscookie
,
397 scr
->scr_dconf
->emulcookie
,
399 sc
->sc_focusidx
= idx
;
407 wsdisplay_closescreen(struct wsdisplay_softc
*sc
, struct wsscreen
*scr
)
412 if (WSSCREEN_HAS_TTY(scr
)) {
413 struct tty
*tp
= scr
->scr_tty
;
414 (*tp
->t_linesw
->l_modem
)(tp
, 0);
417 /* locate the major number */
418 maj
= cdevsw_lookup_major(&wsdisplay_cdevsw
);
419 /* locate the screen index */
420 for (idx
= 0; idx
< WSDISPLAY_MAXSCREEN
; idx
++)
421 if (scr
== sc
->sc_scr
[idx
])
424 if (idx
== WSDISPLAY_MAXSCREEN
)
425 panic("wsdisplay_forceclose: bad screen");
428 /* nuke the vnodes */
429 mn
= WSDISPLAYMINOR(device_unit(sc
->sc_dev
), idx
);
430 vdevgone(maj
, mn
, mn
, VCHR
);
433 #ifdef WSDISPLAY_SCROLLSUPPORT
435 wsdisplay_scroll(void *arg
, int op
)
438 struct wsdisplay_softc
*sc
= device_private(dv
);
439 struct wsscreen
*scr
;
447 if (op
== WSDISPLAY_SCROLL_RESET
)
450 lines
= (op
& WSDISPLAY_SCROLL_LOW
) ?
451 sc
->sc_scroll_values
.slowlines
:
452 sc
->sc_scroll_values
.fastlines
;
453 if (op
& WSDISPLAY_SCROLL_BACKWARD
)
457 if (sc
->sc_accessops
->scroll
) {
458 (*sc
->sc_accessops
->scroll
)(sc
->sc_accesscookie
,
459 sc
->sc_focus
->scr_dconf
->emulcookie
, lines
);
465 wsdisplay_delscreen(struct wsdisplay_softc
*sc
, int idx
, int flags
)
467 struct wsscreen
*scr
;
471 if (idx
< 0 || idx
>= WSDISPLAY_MAXSCREEN
)
473 if ((scr
= sc
->sc_scr
[idx
]) == NULL
)
476 if (scr
->scr_dconf
== &wsdisplay_console_conf
||
478 ((scr
->scr_flags
& SCR_OPEN
) && !(flags
& WSDISPLAY_DELSCR_FORCE
)))
481 wsdisplay_closescreen(sc
, scr
);
484 * delete pointers, so neither device entries
485 * nor keyboard input can reference it anymore
488 if (sc
->sc_focus
== scr
) {
490 #ifdef WSDISPLAY_COMPAT_RAWKBD
491 wsdisplay_update_rawkbd(sc
, 0);
498 * Wake up processes waiting for the screen to
499 * be activated. Sleepers must check whether
500 * the screen still exists.
502 if (scr
->scr_flags
& SCR_WAITACTIVE
)
505 /* save a reference to the graphics screen */
506 cookie
= scr
->scr_dconf
->emulcookie
;
508 wsscreen_detach(scr
);
510 (*sc
->sc_accessops
->free_screen
)(sc
->sc_accesscookie
,
513 aprint_verbose_dev(sc
->sc_dev
, "screen %d deleted\n", idx
);
518 * Autoconfiguration functions.
521 wsdisplay_emul_match(device_t parent
, cfdata_t match
, void *aux
)
523 struct wsemuldisplaydev_attach_args
*ap
= aux
;
525 if (match
->wsemuldisplaydevcf_console
!=
526 WSEMULDISPLAYDEVCF_CONSOLE_UNK
) {
528 * If console-ness of device specified, either match
529 * exactly (at high priority), or fail.
531 if (match
->wsemuldisplaydevcf_console
!= 0 &&
538 /* If console-ness unspecified, it wins. */
543 wsdisplay_emul_attach(device_t parent
, device_t self
, void *aux
)
545 struct wsdisplay_softc
*sc
= device_private(self
);
546 struct wsemuldisplaydev_attach_args
*ap
= aux
;
550 /* Don't allow more than one console to attach */
551 if (wsdisplay_console_attached
&& ap
->console
)
554 wsdisplay_common_attach(sc
, ap
->console
,
555 device_cfdata(self
)->wsemuldisplaydevcf_kbdmux
, ap
->scrdata
,
556 ap
->accessops
, ap
->accesscookie
);
561 /* locate the major number */
562 maj
= cdevsw_lookup_major(&wsdisplay_cdevsw
);
564 cn_tab
->cn_dev
= makedev(maj
, WSDISPLAYMINOR(device_unit(self
),
569 /* Print function (for parent devices). */
571 wsemuldisplaydevprint(void *aux
, const char *pnp
)
574 struct wsemuldisplaydev_attach_args
*ap
= aux
;
578 aprint_normal("wsdisplay at %s", pnp
);
579 #if 0 /* don't bother; it's ugly */
580 aprint_normal(" console %d", ap
->console
);
587 wsdisplay_noemul_match(device_t parent
, cfdata_t match
, void *aux
)
590 struct wsdisplaydev_attach_args
*ap
= aux
;
598 wsdisplay_noemul_attach(device_t parent
, device_t self
, void *aux
)
600 struct wsdisplay_softc
*sc
= device_private(self
);
601 struct wsdisplaydev_attach_args
*ap
= aux
;
605 wsdisplay_common_attach(sc
, 0,
606 device_cfdata(self
)->wsemuldisplaydevcf_kbdmux
, NULL
,
607 ap
->accessops
, ap
->accesscookie
);
611 wsdisplay_swdone_cb(void *arg
, int error
, int waitok
)
613 struct wsdisplay_softc
*sc
= arg
;
615 mutex_enter(&sc
->sc_flagsmtx
);
616 KASSERT(sc
->sc_flags
& SC_SWITCHPENDING
);
618 sc
->sc_flags
|= SC_SWITCHERROR
;
619 sc
->sc_flags
&= ~SC_SWITCHPENDING
;
620 cv_signal(&sc
->sc_flagscv
);
621 mutex_exit(&sc
->sc_flagsmtx
);
625 wsdisplay_dosync(struct wsdisplay_softc
*sc
, int attach
)
627 struct wsscreen
*scr
;
628 int (*op
)(void *, int, void (*)(void *, int, int), void *);
632 if (!scr
|| !scr
->scr_syncops
)
633 return 0; /* XXX check SCR_GRAPHICS? */
635 sc
->sc_flags
|= SC_SWITCHPENDING
;
636 sc
->sc_flags
&= ~SC_SWITCHERROR
;
638 op
= scr
->scr_syncops
->attach
;
640 op
= scr
->scr_syncops
->detach
;
641 res
= (*op
)(scr
->scr_synccookie
, 1, wsdisplay_swdone_cb
, sc
);
643 /* wait for callback */
644 mutex_enter(&sc
->sc_flagsmtx
);
645 while (sc
->sc_flags
& SC_SWITCHPENDING
)
646 cv_wait_sig(&sc
->sc_flagscv
, &sc
->sc_flagsmtx
);
647 mutex_exit(&sc
->sc_flagsmtx
);
648 if (sc
->sc_flags
& SC_SWITCHERROR
)
649 return (EIO
); /* XXX pass real error */
651 sc
->sc_flags
&= ~SC_SWITCHPENDING
;
656 sc
->sc_flags
|= SC_XATTACHED
;
658 sc
->sc_flags
&= ~SC_XATTACHED
;
663 wsdisplay_handlex(int resume
)
668 for (i
= 0; i
< wsdisplay_cd
.cd_ndevs
; i
++) {
669 dv
= device_lookup(&wsdisplay_cd
, i
);
672 res
= wsdisplay_dosync(device_private(dv
), resume
);
680 wsdisplay_suspend(device_t dv
, pmf_qual_t qual
)
682 struct wsdisplay_softc
*sc
= device_private(dv
);
684 struct wsscreen
*scr
= sc
->sc_focus
;
685 if (sc
->sc_flags
& SC_XATTACHED
) {
686 KASSERT(scr
&& scr
->scr_syncops
);
691 * XXX X servers should have been detached earlier.
692 * pmf currently ignores our return value and suspends the system
693 * after device suspend failures. We try to avoid bigger damage
694 * and try to detach the X server here. This is not safe because
695 * other parts of the system which the X server deals with
696 * might already be suspended.
698 if (sc
->sc_flags
& SC_XATTACHED
) {
699 printf("%s: emergency X server detach\n", device_xname(dv
));
700 wsdisplay_dosync(sc
, 0);
703 return (!(sc
->sc_flags
& SC_XATTACHED
));
706 /* Print function (for parent devices). */
708 wsdisplaydevprint(void *aux
, const char *pnp
)
711 struct wsdisplaydev_attach_args
*ap
= aux
;
715 aprint_normal("wsdisplay at %s", pnp
);
721 wsdisplay_common_attach(struct wsdisplay_softc
*sc
, int console
, int kbdmux
,
722 const struct wsscreen_list
*scrdata
,
723 const struct wsdisplay_accessops
*accessops
,
730 struct wsmux_softc
*mux
;
733 mux
= wsmux_getmux(kbdmux
);
735 mux
= wsmux_create("dmux", device_unit(sc
->sc_dev
));
736 /* XXX panic()ing isn't nice, but attach cannot fail */
738 panic("wsdisplay_common_attach: no memory");
739 sc
->sc_input
= &mux
->sc_base
;
740 mux
->sc_base
.me_dispdv
= sc
->sc_dev
;
741 aprint_normal(" kbdmux %d", kbdmux
);
744 aprint_normal(" (kbdmux ignored)");
748 sc
->sc_isconsole
= console
;
751 KASSERT(wsdisplay_console_initted
);
752 KASSERT(wsdisplay_console_device
== NULL
);
754 sc
->sc_scr
[0] = wsscreen_attach(sc
, 1, 0, 0, 0, 0, 0, 0);
755 wsdisplay_console_device
= sc
;
757 aprint_normal(": console (%s, %s emulation)",
758 wsdisplay_console_conf
.scrdata
->name
,
759 wsdisplay_console_conf
.wsemul
->name
);
762 kme
= wskbd_set_console_display(sc
->sc_dev
, sc
->sc_input
);
764 aprint_normal(", using %s", device_xname(kme
->me_dv
));
771 sc
->sc_focus
= sc
->sc_scr
[0];
774 wsdisplay_console_attached
= 1;
778 #if NWSKBD > 0 && NWSMUX > 0
779 wsmux_set_display(mux
, sc
->sc_dev
);
782 mutex_init(&sc
->sc_flagsmtx
, MUTEX_DEFAULT
, IPL_NONE
);
783 cv_init(&sc
->sc_flagscv
, "wssw");
785 sc
->sc_accessops
= accessops
;
786 sc
->sc_accesscookie
= accesscookie
;
787 sc
->sc_scrdata
= scrdata
;
789 #ifdef WSDISPLAY_SCROLLSUPPORT
790 sc
->sc_scroll_values
= wsdisplay_default_scroll_values
;
794 * Set up a number of virtual screens if wanted. The
795 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code
796 * is for special cases like installation kernels.
798 for (i
= start
; i
< wsdisplay_defaultscreens
; i
++) {
799 if (wsdisplay_addscreen(sc
, i
, 0, 0))
804 wsdisplay_addscreen_print(sc
, start
, i
-start
);
806 if (!pmf_device_register(sc
->sc_dev
, wsdisplay_suspend
, NULL
))
807 aprint_error_dev(sc
->sc_dev
, "couldn't establish power handler\n");
811 wsdisplay_cnattach(const struct wsscreen_descr
*type
, void *cookie
,
812 int ccol
, int crow
, long defattr
)
814 const struct wsemul_ops
*wsemul
;
816 KASSERT(wsdisplay_console_initted
< 2);
817 KASSERT(type
->nrows
> 0);
818 KASSERT(type
->ncols
> 0);
819 KASSERT(crow
< type
->nrows
);
820 KASSERT(ccol
< type
->ncols
);
822 wsdisplay_console_conf
.emulops
= type
->textops
;
823 wsdisplay_console_conf
.emulcookie
= cookie
;
824 wsdisplay_console_conf
.scrdata
= type
;
826 wsemul
= wsemul_pick(0); /* default */
827 wsdisplay_console_conf
.wsemul
= wsemul
;
828 wsdisplay_console_conf
.wsemulcookie
= (*wsemul
->cnattach
)(type
, cookie
,
832 cn_tab
= &wsdisplay_cons
;
833 wsdisplay_console_initted
= 2;
837 wsdisplay_preattach(const struct wsscreen_descr
*type
, void *cookie
,
838 int ccol
, int crow
, long defattr
)
840 const struct wsemul_ops
*wsemul
;
842 KASSERT(!wsdisplay_console_initted
);
843 KASSERT(type
->nrows
> 0);
844 KASSERT(type
->ncols
> 0);
845 KASSERT(crow
< type
->nrows
);
846 KASSERT(ccol
< type
->ncols
);
848 wsdisplay_console_conf
.emulops
= type
->textops
;
849 wsdisplay_console_conf
.emulcookie
= cookie
;
850 wsdisplay_console_conf
.scrdata
= type
;
852 wsemul
= wsemul_pick(0); /* default */
853 wsdisplay_console_conf
.wsemul
= wsemul
;
854 wsdisplay_console_conf
.wsemulcookie
= (*wsemul
->cnattach
)(type
, cookie
,
858 cn_tab
= &wsdisplay_cons
;
859 wsdisplay_console_initted
= 1;
863 * Tty and cdevsw functions.
866 wsdisplayopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
868 struct wsdisplay_softc
*sc
;
871 struct wsscreen
*scr
;
873 sc
= device_lookup_private(&wsdisplay_cd
, WSDISPLAYUNIT(dev
));
874 if (sc
== NULL
) /* make sure it was attached */
877 if (ISWSDISPLAYSTAT(dev
)) {
878 wsevent_init(&sc
->evar
, l
->l_proc
);
882 if (ISWSDISPLAYCTL(dev
))
885 if (WSDISPLAYSCREEN(dev
) >= WSDISPLAY_MAXSCREEN
)
887 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(dev
)]) == NULL
)
890 if (WSSCREEN_HAS_TTY(scr
)) {
892 tp
->t_oproc
= wsdisplaystart
;
893 tp
->t_param
= wsdisplayparam
;
895 newopen
= (tp
->t_state
& TS_ISOPEN
) == 0;
897 if (kauth_authorize_device_tty(l
->l_cred
,
898 KAUTH_DEVICE_TTY_OPEN
, tp
))
903 tp
->t_iflag
= TTYDEF_IFLAG
;
904 tp
->t_oflag
= TTYDEF_OFLAG
;
905 tp
->t_cflag
= TTYDEF_CFLAG
;
906 tp
->t_lflag
= TTYDEF_LFLAG
;
907 tp
->t_ispeed
= tp
->t_ospeed
= TTYDEF_SPEED
;
908 wsdisplayparam(tp
, &tp
->t_termios
);
911 tp
->t_state
|= TS_CARR_ON
;
913 error
= ((*tp
->t_linesw
->l_open
)(dev
, tp
));
917 if (newopen
&& WSSCREEN_HAS_EMULATOR(scr
)) {
918 /* set window sizes as appropriate, and reset
920 tp
->t_winsize
.ws_row
= scr
->scr_dconf
->scrdata
->nrows
;
921 tp
->t_winsize
.ws_col
= scr
->scr_dconf
->scrdata
->ncols
;
923 /* wsdisplay_set_emulation() */
927 scr
->scr_flags
|= SCR_OPEN
;
932 wsdisplayclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
935 struct wsdisplay_softc
*sc
;
937 struct wsscreen
*scr
;
939 dv
= device_lookup(&wsdisplay_cd
, WSDISPLAYUNIT(dev
));
940 sc
= device_private(dv
);
942 if (ISWSDISPLAYSTAT(dev
)) {
943 wsevent_fini(&sc
->evar
);
947 if (ISWSDISPLAYCTL(dev
))
950 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(dev
)]) == NULL
)
953 if (WSSCREEN_HAS_TTY(scr
)) {
954 if (scr
->scr_hold_screen
) {
957 /* XXX RESET KEYBOARD LEDS, etc. */
958 s
= spltty(); /* avoid conflict with keyboard */
959 wsdisplay_kbdholdscreen(dv
, 0);
963 (*tp
->t_linesw
->l_close
)(tp
, flag
);
967 if (scr
->scr_syncops
)
968 (*scr
->scr_syncops
->destroy
)(scr
->scr_synccookie
);
970 if (WSSCREEN_HAS_EMULATOR(scr
)) {
971 scr
->scr_flags
&= ~SCR_GRAPHICS
;
972 (*scr
->scr_dconf
->wsemul
->reset
)(scr
->scr_dconf
->wsemulcookie
,
974 if (wsdisplay_clearonclose
)
975 (*scr
->scr_dconf
->wsemul
->reset
)
976 (scr
->scr_dconf
->wsemulcookie
,
980 #ifdef WSDISPLAY_COMPAT_RAWKBD
981 if (scr
->scr_rawkbd
) {
982 int kbmode
= WSKBD_TRANSLATED
;
983 (void)wsdisplay_internal_ioctl(sc
, scr
, WSKBDIO_SETMODE
,
984 (void *)&kbmode
, 0, l
);
988 scr
->scr_flags
&= ~SCR_OPEN
;
994 wsdisplayread(dev_t dev
, struct uio
*uio
, int flag
)
996 struct wsdisplay_softc
*sc
;
998 struct wsscreen
*scr
;
1001 sc
= device_lookup_private(&wsdisplay_cd
, WSDISPLAYUNIT(dev
));
1003 if (ISWSDISPLAYSTAT(dev
)) {
1004 error
= wsevent_read(&sc
->evar
, uio
, flag
);
1008 if (ISWSDISPLAYCTL(dev
))
1011 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(dev
)]) == NULL
)
1014 if (!WSSCREEN_HAS_TTY(scr
))
1018 return ((*tp
->t_linesw
->l_read
)(tp
, uio
, flag
));
1022 wsdisplaywrite(dev_t dev
, struct uio
*uio
, int flag
)
1024 struct wsdisplay_softc
*sc
;
1026 struct wsscreen
*scr
;
1028 sc
= device_lookup_private(&wsdisplay_cd
, WSDISPLAYUNIT(dev
));
1030 if (ISWSDISPLAYSTAT(dev
)) {
1034 if (ISWSDISPLAYCTL(dev
))
1037 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(dev
)]) == NULL
)
1040 if (!WSSCREEN_HAS_TTY(scr
))
1044 return ((*tp
->t_linesw
->l_write
)(tp
, uio
, flag
));
1048 wsdisplaypoll(dev_t dev
, int events
, struct lwp
*l
)
1050 struct wsdisplay_softc
*sc
;
1052 struct wsscreen
*scr
;
1054 sc
= device_lookup_private(&wsdisplay_cd
, WSDISPLAYUNIT(dev
));
1056 if (ISWSDISPLAYSTAT(dev
))
1057 return (wsevent_poll(&sc
->evar
, events
, l
));
1059 if (ISWSDISPLAYCTL(dev
))
1062 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(dev
)]) == NULL
)
1065 if (!WSSCREEN_HAS_TTY(scr
))
1069 return ((*tp
->t_linesw
->l_poll
)(tp
, events
, l
));
1073 wsdisplaykqfilter(dev_t dev
, struct knote
*kn
)
1075 struct wsdisplay_softc
*sc
;
1076 struct wsscreen
*scr
;
1078 sc
= device_lookup_private(&wsdisplay_cd
, WSDISPLAYUNIT(dev
));
1080 if (ISWSDISPLAYCTL(dev
))
1083 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(dev
)]) == NULL
)
1087 if (WSSCREEN_HAS_TTY(scr
))
1088 return (ttykqfilter(dev
, kn
));
1094 wsdisplaytty(dev_t dev
)
1096 struct wsdisplay_softc
*sc
;
1097 struct wsscreen
*scr
;
1099 sc
= device_lookup_private(&wsdisplay_cd
, WSDISPLAYUNIT(dev
));
1101 if (ISWSDISPLAYSTAT(dev
))
1102 panic("wsdisplaytty() on status device");
1104 if (ISWSDISPLAYCTL(dev
))
1105 panic("wsdisplaytty() on ctl device");
1107 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(dev
)]) == NULL
)
1110 return (scr
->scr_tty
);
1114 wsdisplayioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
1117 struct wsdisplay_softc
*sc
;
1120 struct wsscreen
*scr
;
1122 dv
= device_lookup(&wsdisplay_cd
, WSDISPLAYUNIT(dev
));
1123 sc
= device_private(dv
);
1125 #ifdef WSDISPLAY_COMPAT_USL
1126 error
= wsdisplay_usl_ioctl1(dv
, cmd
, data
, flag
, l
);
1127 if (error
!= EPASSTHROUGH
)
1131 if (ISWSDISPLAYSTAT(dev
))
1132 return (wsdisplay_stat_ioctl(sc
, cmd
, data
, flag
, l
));
1134 if (ISWSDISPLAYCTL(dev
))
1135 return (wsdisplay_cfg_ioctl(sc
, cmd
, data
, flag
, l
));
1137 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(dev
)]) == NULL
)
1140 if (WSSCREEN_HAS_TTY(scr
)) {
1143 /* printf("disc\n"); */
1144 /* do the line discipline ioctls first */
1145 error
= (*tp
->t_linesw
->l_ioctl
)(tp
, cmd
, data
, flag
, l
);
1146 if (error
!= EPASSTHROUGH
)
1149 /* printf("tty\n"); */
1150 /* then the tty ioctls */
1151 error
= ttioctl(tp
, cmd
, data
, flag
, l
);
1152 if (error
!= EPASSTHROUGH
)
1156 #ifdef WSDISPLAY_COMPAT_USL
1157 error
= wsdisplay_usl_ioctl2(sc
, scr
, cmd
, data
, flag
, l
);
1158 if (error
!= EPASSTHROUGH
)
1162 return (wsdisplay_internal_ioctl(sc
, scr
, cmd
, data
, flag
, l
));
1166 wsdisplay_param(device_t dv
, u_long cmd
, struct wsdisplay_param
*dp
)
1168 struct wsdisplay_softc
*sc
= device_private(dv
);
1169 return ((*sc
->sc_accessops
->ioctl
)(sc
->sc_accesscookie
,
1170 sc
->sc_focus
->scr_dconf
->emulcookie
,
1171 cmd
, (void *)dp
, 0, NULL
));
1175 wsdisplay_internal_ioctl(struct wsdisplay_softc
*sc
, struct wsscreen
*scr
,
1176 u_long cmd
, void *data
, int flag
, struct lwp
*l
)
1180 struct wsdisplay_font fd
;
1181 #ifdef WSDISPLAY_SCROLLSUPPORT
1182 struct wsdisplay_scroll_data
*ksdp
, *usdp
;
1186 struct wsevsrc
*inp
;
1188 #ifdef WSDISPLAY_COMPAT_RAWKBD
1190 case WSKBDIO_SETMODE
:
1191 scr
->scr_rawkbd
= (*(int *)data
== WSKBD_RAW
);
1192 return (wsdisplay_update_rawkbd(sc
, scr
));
1193 case WSKBDIO_GETMODE
:
1194 *(int *)data
= (scr
->scr_rawkbd
?
1195 WSKBD_RAW
: WSKBD_TRANSLATED
);
1202 error
= wsevsrc_display_ioctl(inp
, cmd
, data
, flag
, l
);
1203 if (error
!= EPASSTHROUGH
)
1205 #endif /* NWSKBD > 0 */
1208 case WSDISPLAYIO_GMODE
:
1209 if (scr
->scr_flags
& SCR_GRAPHICS
) {
1210 if (scr
->scr_flags
& SCR_DUMBFB
)
1211 *(u_int
*)data
= WSDISPLAYIO_MODE_DUMBFB
;
1213 *(u_int
*)data
= WSDISPLAYIO_MODE_MAPPED
;
1215 *(u_int
*)data
= WSDISPLAYIO_MODE_EMUL
;
1218 case WSDISPLAYIO_SMODE
:
1219 #define d (*(int *)data)
1220 if (d
!= WSDISPLAYIO_MODE_EMUL
&&
1221 d
!= WSDISPLAYIO_MODE_MAPPED
&&
1222 d
!= WSDISPLAYIO_MODE_DUMBFB
)
1225 if (WSSCREEN_HAS_EMULATOR(scr
)) {
1226 scr
->scr_flags
&= ~SCR_GRAPHICS
;
1227 if (d
== WSDISPLAYIO_MODE_MAPPED
||
1228 d
== WSDISPLAYIO_MODE_DUMBFB
)
1229 scr
->scr_flags
|= SCR_GRAPHICS
|
1230 ((d
== WSDISPLAYIO_MODE_DUMBFB
) ? SCR_DUMBFB
: 0);
1231 } else if (d
== WSDISPLAYIO_MODE_EMUL
)
1234 (void)(*sc
->sc_accessops
->ioctl
)(sc
->sc_accesscookie
,
1235 scr
->scr_dconf
->emulcookie
, cmd
, data
, flag
, l
);
1240 #ifdef WSDISPLAY_SCROLLSUPPORT
1241 #define SETSCROLLLINES(dstp, srcp, dfltp) \
1243 (dstp)->fastlines = ((srcp)->which & \
1244 WSDISPLAY_SCROLL_DOFASTLINES) ? \
1245 (srcp)->fastlines : (dfltp)->fastlines; \
1246 (dstp)->slowlines = ((srcp)->which & \
1247 WSDISPLAY_SCROLL_DOSLOWLINES) ? \
1248 (srcp)->slowlines : (dfltp)->slowlines; \
1249 (dstp)->which = WSDISPLAY_SCROLL_DOALL; \
1253 case WSDISPLAYIO_DSSCROLL
:
1254 usdp
= (struct wsdisplay_scroll_data
*)data
;
1255 ksdp
= &sc
->sc_scroll_values
;
1256 SETSCROLLLINES(ksdp
, usdp
, ksdp
);
1259 case WSDISPLAYIO_DGSCROLL
:
1260 usdp
= (struct wsdisplay_scroll_data
*)data
;
1261 ksdp
= &sc
->sc_scroll_values
;
1262 SETSCROLLLINES(usdp
, ksdp
, ksdp
);
1265 case WSDISPLAYIO_DSSCROLL
:
1266 case WSDISPLAYIO_DGSCROLL
:
1270 case WSDISPLAYIO_SFONT
:
1271 #define d ((struct wsdisplay_usefontdata *)data)
1272 if (!sc
->sc_accessops
->load_font
)
1275 error
= copyinstr(d
->name
, namebuf
, sizeof(namebuf
), 0);
1282 error
= (*sc
->sc_accessops
->load_font
)(sc
->sc_accesscookie
,
1283 scr
->scr_dconf
->emulcookie
, &fd
);
1284 if (!error
&& WSSCREEN_HAS_EMULATOR(scr
))
1285 (*scr
->scr_dconf
->wsemul
->reset
)
1286 (scr
->scr_dconf
->wsemulcookie
, WSEMUL_SYNCFONT
);
1290 #ifdef WSDISPLAY_CUSTOM_OUTPUT
1291 case WSDISPLAYIO_GMSGATTRS
:
1292 #define d ((struct wsdisplay_msgattrs *)data)
1293 (*scr
->scr_dconf
->wsemul
->getmsgattrs
)
1294 (scr
->scr_dconf
->wsemulcookie
, d
);
1298 case WSDISPLAYIO_SMSGATTRS
: {
1299 #define d ((struct wsdisplay_msgattrs *)data)
1301 for (i
= 0; i
< WSDISPLAY_MAXSCREEN
; i
++)
1302 if (sc
->sc_scr
[i
] != NULL
)
1303 (*sc
->sc_scr
[i
]->scr_dconf
->wsemul
->setmsgattrs
)
1304 (sc
->sc_scr
[i
]->scr_dconf
->wsemulcookie
,
1305 sc
->sc_scr
[i
]->scr_dconf
->scrdata
,
1311 case WSDISPLAYIO_GMSGATTRS
:
1312 case WSDISPLAYIO_SMSGATTRS
:
1315 case WSDISPLAYIO_SETVERSION
:
1316 return wsevent_setversion(&sc
->evar
, *(int *)data
);
1319 /* check ioctls for display */
1320 return ((*sc
->sc_accessops
->ioctl
)(sc
->sc_accesscookie
,
1321 scr
->scr_dconf
->emulcookie
, cmd
, data
, flag
, l
));
1325 wsdisplay_stat_ioctl(struct wsdisplay_softc
*sc
, u_long cmd
, void *data
,
1326 int flag
, struct lwp
*l
)
1329 case WSDISPLAYIO_GETACTIVESCREEN
:
1330 *(int*)data
= wsdisplay_getactivescreen(sc
);
1334 return (EPASSTHROUGH
);
1338 wsdisplay_cfg_ioctl(struct wsdisplay_softc
*sc
, u_long cmd
, void *data
,
1339 int flag
, struct lwp
*l
)
1342 char *type
, typebuf
[16], *emul
, emulbuf
[16];
1345 #if defined(COMPAT_14) && NWSKBD > 0
1346 struct wsmux_device wsmuxdata
;
1349 struct wsevsrc
*inp
;
1353 case WSDISPLAYIO_ADDSCREEN
:
1354 #define d ((struct wsdisplay_addscreendata *)data)
1355 if (d
->screentype
) {
1356 error
= copyinstr(d
->screentype
, typebuf
,
1357 sizeof(typebuf
), 0);
1364 error
= copyinstr(d
->emul
, emulbuf
, sizeof(emulbuf
),0);
1371 if ((error
= wsdisplay_addscreen(sc
, d
->idx
, type
, emul
)) == 0)
1372 wsdisplay_addscreen_print(sc
, d
->idx
, 0);
1375 case WSDISPLAYIO_DELSCREEN
:
1376 #define d ((struct wsdisplay_delscreendata *)data)
1377 return (wsdisplay_delscreen(sc
, d
->idx
, d
->flags
));
1379 case WSDISPLAYIO_LDFONT
:
1380 #define d ((struct wsdisplay_font *)data)
1381 if (!sc
->sc_accessops
->load_font
)
1384 error
= copyinstr(d
->name
, typebuf
, sizeof(typebuf
), 0);
1389 d
->name
= "loaded"; /* ??? */
1390 fontsz
= d
->fontheight
* d
->stride
* d
->numchars
;
1391 if (fontsz
> WSDISPLAY_MAXFONTSZ
)
1394 tbuf
= malloc(fontsz
, M_DEVBUF
, M_WAITOK
);
1395 error
= copyin(d
->data
, tbuf
, fontsz
);
1397 free(tbuf
, M_DEVBUF
);
1402 (*sc
->sc_accessops
->load_font
)(sc
->sc_accesscookie
, 0, d
);
1403 free(tbuf
, M_DEVBUF
);
1409 case _O_WSDISPLAYIO_SETKEYBOARD
:
1410 #define d ((struct wsdisplay_kbddata *)data)
1415 case _O_WSDISPLAY_KBD_ADD
:
1417 d
->idx
= wskbd_pickfree();
1421 wsmuxdata
.type
= WSMUX_KBD
;
1422 wsmuxdata
.idx
= d
->idx
;
1423 return (wsevsrc_ioctl(inp
, WSMUX_ADD_DEVICE
,
1424 &wsmuxdata
, flag
, l
));
1425 case _O_WSDISPLAY_KBD_DEL
:
1426 wsmuxdata
.type
= WSMUX_KBD
;
1427 wsmuxdata
.idx
= d
->idx
;
1428 return (wsevsrc_ioctl(inp
, WSMUX_REMOVE_DEVICE
,
1429 &wsmuxdata
, flag
, l
));
1436 case WSMUXIO_ADD_DEVICE
:
1437 #define d ((struct wsmux_device *)data)
1438 if (d
->idx
== -1 && d
->type
== WSMUX_KBD
)
1439 d
->idx
= wskbd_pickfree();
1442 case WSMUXIO_INJECTEVENT
:
1443 case WSMUXIO_REMOVE_DEVICE
:
1444 case WSMUXIO_LIST_DEVICES
:
1448 return (wsevsrc_ioctl(inp
, cmd
, data
, flag
, l
));
1449 #endif /* NWSKBD > 0 */
1452 return (EPASSTHROUGH
);
1456 wsdisplay_stat_inject(device_t dv
, u_int type
, int value
)
1458 struct wsdisplay_softc
*sc
= device_private(dv
);
1459 struct wseventvar
*evar
;
1460 struct wscons_event event
;
1467 if (evar
->q
== NULL
)
1471 event
.value
= value
;
1472 if (wsevent_inject(evar
, &event
, 1) != 0) {
1473 log(LOG_WARNING
, "wsdisplay: event queue overflow\n");
1481 wsdisplaymmap(dev_t dev
, off_t offset
, int prot
)
1483 struct wsdisplay_softc
*sc
;
1484 struct wsscreen
*scr
;
1486 sc
= device_lookup_private(&wsdisplay_cd
, WSDISPLAYUNIT(dev
));
1488 if (ISWSDISPLAYSTAT(dev
))
1491 if (ISWSDISPLAYCTL(dev
))
1494 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(dev
)]) == NULL
)
1497 if (!(scr
->scr_flags
& SCR_GRAPHICS
))
1500 /* pass mmap to display */
1501 return ((*sc
->sc_accessops
->mmap
)(sc
->sc_accesscookie
,
1502 scr
->scr_dconf
->emulcookie
, offset
, prot
));
1506 wsdisplaystart(struct tty
*tp
)
1508 struct wsdisplay_softc
*sc
;
1509 struct wsscreen
*scr
;
1514 if (tp
->t_state
& (TS_TIMEOUT
| TS_BUSY
| TS_TTSTOP
)) {
1518 sc
= device_lookup_private(&wsdisplay_cd
, WSDISPLAYUNIT(tp
->t_dev
));
1519 if ((scr
= sc
->sc_scr
[WSDISPLAYSCREEN(tp
->t_dev
)]) == NULL
) {
1524 if (scr
->scr_hold_screen
) {
1525 tp
->t_state
|= TS_TIMEOUT
;
1529 tp
->t_state
|= TS_BUSY
;
1533 scr
->scr_in_ttyoutput
= 1;
1537 * Drain output from ring buffer.
1538 * The output will normally be in one contiguous chunk, but when the
1539 * ring wraps, it will be in two pieces.. one at the end of the ring,
1540 * the other at the start. For performance, rather than loop here,
1541 * we output one chunk, see if there's another one, and if so, output
1545 n
= ndqb(&tp
->t_outq
, 0);
1546 tbuf
= tp
->t_outq
.c_cf
;
1548 if (!(scr
->scr_flags
& SCR_GRAPHICS
)) {
1549 KASSERT(WSSCREEN_HAS_EMULATOR(scr
));
1550 (*scr
->scr_dconf
->wsemul
->output
)(scr
->scr_dconf
->wsemulcookie
,
1553 ndflush(&tp
->t_outq
, n
);
1555 if ((n
= ndqb(&tp
->t_outq
, 0)) > 0) {
1556 tbuf
= tp
->t_outq
.c_cf
;
1558 if (!(scr
->scr_flags
& SCR_GRAPHICS
)) {
1559 KASSERT(WSSCREEN_HAS_EMULATOR(scr
));
1560 (*scr
->scr_dconf
->wsemul
->output
)
1561 (scr
->scr_dconf
->wsemulcookie
, tbuf
, n
, 0);
1563 ndflush(&tp
->t_outq
, n
);
1567 scr
->scr_in_ttyoutput
= 0;
1571 tp
->t_state
&= ~TS_BUSY
;
1572 /* Come back if there's more to do */
1574 tp
->t_state
|= TS_TIMEOUT
;
1575 callout_schedule(&tp
->t_rstrt_ch
, (hz
> 128) ? (hz
/ 128) : 1);
1581 wsdisplaystop(struct tty
*tp
, int flag
)
1586 if (ISSET(tp
->t_state
, TS_BUSY
))
1587 if (!ISSET(tp
->t_state
, TS_TTSTOP
))
1588 SET(tp
->t_state
, TS_FLUSH
);
1592 /* Set line parameters. */
1594 wsdisplayparam(struct tty
*tp
, struct termios
*t
)
1597 tp
->t_ispeed
= t
->c_ispeed
;
1598 tp
->t_ospeed
= t
->c_ospeed
;
1599 tp
->t_cflag
= t
->c_cflag
;
1604 * Callbacks for the emulation code.
1607 wsdisplay_emulbell(void *v
)
1609 struct wsscreen
*scr
= v
;
1611 if (scr
== NULL
) /* console, before real attach */
1614 if (scr
->scr_flags
& SCR_GRAPHICS
) /* can this happen? */
1617 (void) wsdisplay_internal_ioctl(scr
->sc
, scr
, WSKBDIO_BELL
, NULL
,
1622 wsdisplay_emulinput(void *v
, const u_char
*data
, u_int count
)
1624 struct wsscreen
*scr
= v
;
1626 int (*ifcn
)(int, struct tty
*);
1628 if (v
== NULL
) /* console, before real attach */
1631 if (scr
->scr_flags
& SCR_GRAPHICS
) /* XXX can't happen */
1633 if (!WSSCREEN_HAS_TTY(scr
))
1639 * XXX bad hack to work around locking problems in tty.c:
1640 * ttyinput() will try to lock again, causing deadlock.
1641 * We assume that wsdisplay_emulinput() can only be called
1642 * from within wsdisplaystart(), and thus the tty lock
1643 * is already held. Use an entry point which doesn't lock.
1645 KASSERT(scr
->scr_in_ttyoutput
);
1646 ifcn
= tp
->t_linesw
->l_rint
;
1647 if (ifcn
== ttyinput
)
1648 ifcn
= ttyinput_wlock
;
1651 (*ifcn
)(*data
++, tp
);
1655 * Calls from the keyboard interface.
1658 wsdisplay_kbdinput(device_t dv
, keysym_t ks
)
1660 struct wsdisplay_softc
*sc
= device_private(dv
);
1661 struct wsscreen
*scr
;
1666 KASSERT(sc
!= NULL
);
1670 if (!scr
|| !WSSCREEN_HAS_TTY(scr
))
1675 if (KS_GROUP(ks
) == KS_GROUP_Ascii
)
1676 (*tp
->t_linesw
->l_rint
)(KS_VALUE(ks
), tp
);
1677 else if (WSSCREEN_HAS_EMULATOR(scr
)) {
1678 count
= (*scr
->scr_dconf
->wsemul
->translate
)
1679 (scr
->scr_dconf
->wsemulcookie
, ks
, &dp
);
1681 (*tp
->t_linesw
->l_rint
)(*dp
++, tp
);
1685 #if defined(WSDISPLAY_COMPAT_RAWKBD)
1687 wsdisplay_update_rawkbd(struct wsdisplay_softc
*sc
, struct wsscreen
*scr
)
1690 int s
, raw
, data
, error
;
1691 struct wsevsrc
*inp
;
1695 raw
= (scr
? scr
->scr_rawkbd
: 0);
1697 if (scr
!= sc
->sc_focus
||
1698 sc
->sc_rawkbd
== raw
) {
1703 data
= raw
? WSKBD_RAW
: WSKBD_TRANSLATED
;
1709 error
= wsevsrc_display_ioctl(inp
, WSKBDIO_SETMODE
, &data
, 0, 0);
1711 sc
->sc_rawkbd
= raw
;
1721 wsdisplay_switch3_cb(void *arg
, int error
, int waitok
)
1725 wsdisplay_switch3(dv
, error
, waitok
);
1729 wsdisplay_switch3(device_t dv
, int error
, int waitok
)
1731 struct wsdisplay_softc
*sc
= device_private(dv
);
1733 struct wsscreen
*scr
;
1735 if (!(sc
->sc_flags
& SC_SWITCHPENDING
)) {
1736 aprint_error_dev(dv
, "wsdisplay_switch3: not switching\n");
1740 no
= sc
->sc_screenwanted
;
1741 if (no
< 0 || no
>= WSDISPLAY_MAXSCREEN
)
1742 panic("wsdisplay_switch3: invalid screen %d", no
);
1743 scr
= sc
->sc_scr
[no
];
1745 aprint_error_dev(dv
,
1746 "wsdisplay_switch3: screen %d disappeared\n", no
);
1751 /* try to recover, avoid recursion */
1753 if (sc
->sc_oldscreen
== WSDISPLAY_NULLSCREEN
) {
1754 aprint_error_dev(dv
, "wsdisplay_switch3: giving up\n");
1756 #ifdef WSDISPLAY_COMPAT_RAWKBD
1757 wsdisplay_update_rawkbd(sc
, 0);
1759 sc
->sc_flags
&= ~SC_SWITCHPENDING
;
1763 sc
->sc_screenwanted
= sc
->sc_oldscreen
;
1764 sc
->sc_oldscreen
= WSDISPLAY_NULLSCREEN
;
1765 return (wsdisplay_switch1(dv
, 0, waitok
));
1768 if (scr
->scr_syncops
&& !error
)
1769 sc
->sc_flags
|= SC_XATTACHED
;
1771 sc
->sc_flags
&= ~SC_SWITCHPENDING
;
1773 if (!error
&& (scr
->scr_flags
& SCR_WAITACTIVE
))
1779 wsdisplay_switch2_cb(void *arg
, int error
, int waitok
)
1783 wsdisplay_switch2(dv
, error
, waitok
);
1787 wsdisplay_switch2(device_t dv
, int error
, int waitok
)
1789 struct wsdisplay_softc
*sc
= device_private(dv
);
1791 struct wsscreen
*scr
;
1793 if (!(sc
->sc_flags
& SC_SWITCHPENDING
)) {
1794 aprint_error_dev(dv
, "wsdisplay_switch2: not switching\n");
1798 no
= sc
->sc_screenwanted
;
1799 if (no
< 0 || no
>= WSDISPLAY_MAXSCREEN
)
1800 panic("wsdisplay_switch2: invalid screen %d", no
);
1801 scr
= sc
->sc_scr
[no
];
1803 aprint_error_dev(dv
,
1804 "wsdisplay_switch2: screen %d disappeared\n", no
);
1809 /* try to recover, avoid recursion */
1811 if (sc
->sc_oldscreen
== WSDISPLAY_NULLSCREEN
) {
1812 aprint_error_dev(dv
, "wsdisplay_switch2: giving up\n");
1814 sc
->sc_flags
&= ~SC_SWITCHPENDING
;
1818 sc
->sc_screenwanted
= sc
->sc_oldscreen
;
1819 sc
->sc_oldscreen
= WSDISPLAY_NULLSCREEN
;
1820 return (wsdisplay_switch1(dv
, 0, waitok
));
1823 sc
->sc_focusidx
= no
;
1826 #ifdef WSDISPLAY_COMPAT_RAWKBD
1827 (void) wsdisplay_update_rawkbd(sc
, scr
);
1829 /* keyboard map??? */
1831 if (scr
->scr_syncops
&&
1832 !(sc
->sc_isconsole
&& wsdisplay_cons_pollmode
)) {
1833 error
= (*scr
->scr_syncops
->attach
)(scr
->scr_synccookie
, waitok
,
1834 wsdisplay_switch3_cb
, dv
);
1835 if (error
== EAGAIN
) {
1836 /* switch will be done asynchronously */
1841 return (wsdisplay_switch3(dv
, error
, waitok
));
1845 wsdisplay_switch1_cb(void *arg
, int error
, int waitok
)
1849 wsdisplay_switch1(dv
, error
, waitok
);
1853 wsdisplay_switch1(device_t dv
, int error
, int waitok
)
1855 struct wsdisplay_softc
*sc
= device_private(dv
);
1857 struct wsscreen
*scr
;
1859 if (!(sc
->sc_flags
& SC_SWITCHPENDING
)) {
1860 aprint_error_dev(dv
, "wsdisplay_switch1: not switching\n");
1864 no
= sc
->sc_screenwanted
;
1865 if (no
== WSDISPLAY_NULLSCREEN
) {
1866 sc
->sc_flags
&= ~SC_SWITCHPENDING
;
1868 sc
->sc_flags
&= ~SC_XATTACHED
;
1874 if (no
< 0 || no
>= WSDISPLAY_MAXSCREEN
)
1875 panic("wsdisplay_switch1: invalid screen %d", no
);
1876 scr
= sc
->sc_scr
[no
];
1878 aprint_error_dev(dv
, "wsdisplay_switch1: screen %d disappeared\n", no
);
1883 sc
->sc_flags
&= ~SC_SWITCHPENDING
;
1887 sc
->sc_flags
&= ~SC_XATTACHED
;
1889 error
= (*sc
->sc_accessops
->show_screen
)(sc
->sc_accesscookie
,
1890 scr
->scr_dconf
->emulcookie
,
1892 sc
->sc_isconsole
&& wsdisplay_cons_pollmode
? 0 : wsdisplay_switch2_cb
, dv
);
1893 if (error
== EAGAIN
) {
1894 /* switch will be done asynchronously */
1898 return (wsdisplay_switch2(dv
, error
, waitok
));
1902 wsdisplay_switch(device_t dv
, int no
, int waitok
)
1904 struct wsdisplay_softc
*sc
= device_private(dv
);
1906 struct wsscreen
*scr
;
1908 if (no
!= WSDISPLAY_NULLSCREEN
) {
1909 if ((no
< 0 || no
>= WSDISPLAY_MAXSCREEN
))
1911 if (sc
->sc_scr
[no
] == NULL
)
1915 wsdisplay_stat_inject(dv
, WSCONS_EVENT_SCREEN_SWITCH
, no
);
1919 if ((sc
->sc_focus
&& no
== sc
->sc_focusidx
) ||
1920 (sc
->sc_focus
== NULL
&& no
== WSDISPLAY_NULLSCREEN
)) {
1925 if (sc
->sc_flags
& SC_SWITCHPENDING
) {
1930 sc
->sc_flags
|= SC_SWITCHPENDING
;
1931 sc
->sc_screenwanted
= no
;
1937 sc
->sc_oldscreen
= WSDISPLAY_NULLSCREEN
;
1938 return (wsdisplay_switch1(dv
, 0, waitok
));
1940 sc
->sc_oldscreen
= sc
->sc_focusidx
;
1942 if (scr
->scr_syncops
) {
1943 if (!(sc
->sc_flags
& SC_XATTACHED
) ||
1944 (sc
->sc_isconsole
&& wsdisplay_cons_pollmode
)) {
1945 /* nothing to do here */
1946 return (wsdisplay_switch1(dv
, 0, waitok
));
1948 res
= (*scr
->scr_syncops
->detach
)(scr
->scr_synccookie
, waitok
,
1949 wsdisplay_switch1_cb
, dv
);
1950 if (res
== EAGAIN
) {
1951 /* switch will be done asynchronously */
1954 } else if (scr
->scr_flags
& SCR_GRAPHICS
) {
1955 /* no way to save state */
1959 return (wsdisplay_switch1(dv
, res
, waitok
));
1963 wsdisplay_reset(device_t dv
, enum wsdisplay_resetops op
)
1965 struct wsdisplay_softc
*sc
= device_private(dv
);
1966 struct wsscreen
*scr
;
1968 KASSERT(sc
!= NULL
);
1975 case WSDISPLAY_RESETEMUL
:
1976 if (!WSSCREEN_HAS_EMULATOR(scr
))
1978 (*scr
->scr_dconf
->wsemul
->reset
)(scr
->scr_dconf
->wsemulcookie
,
1981 case WSDISPLAY_RESETCLOSE
:
1982 wsdisplay_closescreen(sc
, scr
);
1988 * Interface for (external) VT switch / process synchronization code
1991 wsscreen_attach_sync(struct wsscreen
*scr
, const struct wscons_syncops
*ops
,
1994 if (scr
->scr_syncops
) {
1996 * The screen is already claimed.
1997 * Check if the owner is still alive.
1999 if ((*scr
->scr_syncops
->check
)(scr
->scr_synccookie
))
2002 scr
->scr_syncops
= ops
;
2003 scr
->scr_synccookie
= cookie
;
2004 if (scr
== scr
->sc
->sc_focus
)
2005 scr
->sc
->sc_flags
|= SC_XATTACHED
;
2010 wsscreen_detach_sync(struct wsscreen
*scr
)
2012 if (!scr
->scr_syncops
)
2014 scr
->scr_syncops
= 0;
2015 if (scr
== scr
->sc
->sc_focus
)
2016 scr
->sc
->sc_flags
&= ~SC_XATTACHED
;
2021 wsscreen_lookup_sync(struct wsscreen
*scr
,
2022 const struct wscons_syncops
*ops
, /* used as ID */
2025 if (!scr
->scr_syncops
|| ops
!= scr
->scr_syncops
)
2027 *cookiep
= scr
->scr_synccookie
;
2032 * Interface to virtual screen stuff
2035 wsdisplay_maxscreenidx(struct wsdisplay_softc
*sc
)
2037 return (WSDISPLAY_MAXSCREEN
- 1);
2041 wsdisplay_screenstate(struct wsdisplay_softc
*sc
, int idx
)
2043 if (idx
< 0 || idx
>= WSDISPLAY_MAXSCREEN
)
2045 if (!sc
->sc_scr
[idx
])
2047 return ((sc
->sc_scr
[idx
]->scr_flags
& SCR_OPEN
) ? EBUSY
: 0);
2051 wsdisplay_getactivescreen(struct wsdisplay_softc
*sc
)
2053 return (sc
->sc_focus
? sc
->sc_focusidx
: WSDISPLAY_NULLSCREEN
);
2057 wsscreen_switchwait(struct wsdisplay_softc
*sc
, int no
)
2059 struct wsscreen
*scr
;
2062 if (no
== WSDISPLAY_NULLSCREEN
) {
2064 while (sc
->sc_focus
&& res
== 0) {
2065 res
= tsleep(sc
, PCATCH
, "wswait", 0);
2071 if (no
< 0 || no
>= WSDISPLAY_MAXSCREEN
)
2073 scr
= sc
->sc_scr
[no
];
2078 if (scr
!= sc
->sc_focus
) {
2079 scr
->scr_flags
|= SCR_WAITACTIVE
;
2080 res
= tsleep(scr
, PCATCH
, "wswait", 0);
2081 if (scr
!= sc
->sc_scr
[no
])
2082 res
= ENXIO
; /* disappeared in the meantime */
2084 scr
->scr_flags
&= ~SCR_WAITACTIVE
;
2091 wsdisplay_kbdholdscreen(device_t dv
, int hold
)
2093 struct wsdisplay_softc
*sc
= device_private(dv
);
2094 struct wsscreen
*scr
;
2102 scr
->scr_hold_screen
= 1;
2104 scr
->scr_hold_screen
= 0;
2105 callout_schedule(&scr
->scr_tty
->t_rstrt_ch
, 0);
2111 wsdisplay_set_console_kbd(struct wsevsrc
*src
)
2113 if (wsdisplay_console_device
== NULL
) {
2114 src
->me_dispdv
= NULL
;
2118 if (wsmux_attach_sc((struct wsmux_softc
*)
2119 wsdisplay_console_device
->sc_input
, src
)) {
2120 src
->me_dispdv
= NULL
;
2124 wsdisplay_console_device
->sc_input
= src
;
2126 src
->me_dispdv
= wsdisplay_console_device
->sc_dev
;
2128 #endif /* NWSKBD > 0 */
2131 * Console interface.
2134 wsdisplay_cnputc(dev_t dev
, int i
)
2136 struct wsscreen_internal
*dc
;
2139 if (!wsdisplay_console_initted
)
2142 if ((wsdisplay_console_device
!= NULL
) &&
2143 (wsdisplay_console_device
->sc_scr
[0] != NULL
) &&
2144 (wsdisplay_console_device
->sc_scr
[0]->scr_flags
& SCR_GRAPHICS
))
2147 dc
= &wsdisplay_console_conf
;
2148 (*dc
->wsemul
->output
)(dc
->wsemulcookie
, &c
, 1, 1);
2152 wsdisplay_getc_dummy(dev_t dev
)
2159 wsdisplay_pollc(dev_t dev
, int on
)
2162 wsdisplay_cons_pollmode
= on
;
2164 /* notify to fb drivers */
2165 if (wsdisplay_console_device
!= NULL
&&
2166 wsdisplay_console_device
->sc_accessops
->pollc
!= NULL
)
2167 (*wsdisplay_console_device
->sc_accessops
->pollc
)
2168 (wsdisplay_console_device
->sc_accesscookie
, on
);
2170 /* notify to kbd drivers */
2171 if (wsdisplay_cons_kbd_pollc
)
2172 (*wsdisplay_cons_kbd_pollc
)(NODEV
, on
);
2176 wsdisplay_set_cons_kbd(int (*get
)(dev_t
), void (*poll
)(dev_t
, int),
2177 void (*bell
)(dev_t
, u_int
, u_int
, u_int
))
2179 wsdisplay_cons
.cn_getc
= get
;
2180 wsdisplay_cons
.cn_bell
= bell
;
2181 wsdisplay_cons_kbd_pollc
= poll
;
2185 wsdisplay_unset_cons_kbd(void)
2187 wsdisplay_cons
.cn_getc
= wsdisplay_getc_dummy
;
2188 wsdisplay_cons
.cn_bell
= NULL
;
2189 wsdisplay_cons_kbd_pollc
= 0;