2a08d54a9a
at the moment. This includes the addition of two new wsdisplay ioctls, WSDISPLAY_{G,S}BORDER, one to get the actual color and one to set it, respectively. Possible colors match those defined by ANSI (and listed in wsdisplayvar.h). It also adds two accessops to the underlying graphics device, getborder and setborder, which mach their ioctl counterparts. Two kernel options are added: WSDISPLAY_CUSTOM_BORDER, which enables the ioctls described above (to customize the border color from userland after boot), and WSDISPLAY_BORDER_COLOR, which sets the color at boot time. The former is enabled by default on the GENERIC kernel, but not on INSTALL (among others). The later is always commented out, leaving the usual black border as a default. wsconsctl is modified to allow accessing this value easily. For example, 'wsconsctl -d -w border=blue'.
2053 lines
47 KiB
C
2053 lines
47 KiB
C
/* $NetBSD: wsdisplay.c,v 1.81 2004/07/29 22:29:37 jmmv Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Christopher G. Demetriou
|
|
* for the NetBSD Project.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: wsdisplay.c,v 1.81 2004/07/29 22:29:37 jmmv Exp $");
|
|
|
|
#include "opt_wsdisplay_border.h"
|
|
#include "opt_wsdisplay_compat.h"
|
|
#include "opt_wsmsgattrs.h"
|
|
#include "opt_compat_netbsd.h"
|
|
#include "wskbd.h"
|
|
#include "wsmux.h"
|
|
#include "wsdisplay.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/device.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/syslog.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/tty.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/vnode.h>
|
|
|
|
#include <dev/wscons/wseventvar.h>
|
|
#include <dev/wscons/wsmuxvar.h>
|
|
#include <dev/wscons/wsconsio.h>
|
|
#include <dev/wscons/wsdisplayvar.h>
|
|
#include <dev/wscons/wsksymvar.h>
|
|
#include <dev/wscons/wsksymdef.h>
|
|
#include <dev/wscons/wsemulvar.h>
|
|
#include <dev/wscons/wscons_callbacks.h>
|
|
#include <dev/cons.h>
|
|
|
|
struct wsscreen_internal {
|
|
const struct wsdisplay_emulops *emulops;
|
|
void *emulcookie;
|
|
|
|
const struct wsscreen_descr *scrdata;
|
|
|
|
const struct wsemul_ops *wsemul;
|
|
void *wsemulcookie;
|
|
};
|
|
|
|
struct wsscreen {
|
|
struct wsscreen_internal *scr_dconf;
|
|
|
|
struct tty *scr_tty;
|
|
int scr_hold_screen; /* hold tty output */
|
|
|
|
int scr_flags;
|
|
#define SCR_OPEN 1 /* is it open? */
|
|
#define SCR_WAITACTIVE 2 /* someone waiting on activation */
|
|
#define SCR_GRAPHICS 4 /* graphics mode, no text (emulation) output */
|
|
#define SCR_DUMBFB 8 /* in use as a dumb fb (iff SCR_GRAPHICS) */
|
|
const struct wscons_syncops *scr_syncops;
|
|
void *scr_synccookie;
|
|
|
|
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
|
int scr_rawkbd;
|
|
#endif
|
|
|
|
struct wsdisplay_softc *sc;
|
|
};
|
|
|
|
struct wsscreen *wsscreen_attach(struct wsdisplay_softc *, int,
|
|
const char *,
|
|
const struct wsscreen_descr *, void *,
|
|
int, int, long);
|
|
void wsscreen_detach(struct wsscreen *);
|
|
int wsdisplay_addscreen(struct wsdisplay_softc *, int, const char *, const char *);
|
|
static void wsdisplay_shutdownhook(void *);
|
|
static void wsdisplay_addscreen_print(struct wsdisplay_softc *, int, int);
|
|
static void wsdisplay_closescreen(struct wsdisplay_softc *, struct wsscreen *);
|
|
int wsdisplay_delscreen(struct wsdisplay_softc *, int, int);
|
|
|
|
#define WSDISPLAY_MAXSCREEN 8
|
|
|
|
struct wsdisplay_softc {
|
|
struct device sc_dv;
|
|
|
|
const struct wsdisplay_accessops *sc_accessops;
|
|
void *sc_accesscookie;
|
|
|
|
const struct wsscreen_list *sc_scrdata;
|
|
#ifdef WSDISPLAY_SCROLLSUPPORT
|
|
struct wsdisplay_scroll_data sc_scroll_values;
|
|
#endif
|
|
|
|
struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN];
|
|
int sc_focusidx; /* available only if sc_focus isn't null */
|
|
struct wsscreen *sc_focus;
|
|
|
|
struct wseventvar evar;
|
|
|
|
int sc_isconsole;
|
|
|
|
int sc_flags;
|
|
#define SC_SWITCHPENDING 1
|
|
int sc_screenwanted, sc_oldscreen; /* valid with SC_SWITCHPENDING */
|
|
|
|
#if NWSKBD > 0
|
|
struct wsevsrc *sc_input;
|
|
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
|
int sc_rawkbd;
|
|
#endif
|
|
#endif /* NWSKBD > 0 */
|
|
};
|
|
|
|
#ifdef WSDISPLAY_SCROLLSUPPORT
|
|
|
|
struct wsdisplay_scroll_data wsdisplay_default_scroll_values = {
|
|
WSDISPLAY_SCROLL_DOALL,
|
|
25,
|
|
2,
|
|
};
|
|
#endif
|
|
|
|
extern struct cfdriver wsdisplay_cd;
|
|
|
|
/* Autoconfiguration definitions. */
|
|
static int wsdisplay_emul_match(struct device *, struct cfdata *, void *);
|
|
static void wsdisplay_emul_attach(struct device *, struct device *, void *);
|
|
static int wsdisplay_noemul_match(struct device *, struct cfdata *, void *);
|
|
static void wsdisplay_noemul_attach(struct device *, struct device *, void *);
|
|
|
|
CFATTACH_DECL(wsdisplay_emul, sizeof (struct wsdisplay_softc),
|
|
wsdisplay_emul_match, wsdisplay_emul_attach, NULL, NULL);
|
|
|
|
CFATTACH_DECL(wsdisplay_noemul, sizeof (struct wsdisplay_softc),
|
|
wsdisplay_noemul_match, wsdisplay_noemul_attach, NULL, NULL);
|
|
|
|
dev_type_open(wsdisplayopen);
|
|
dev_type_close(wsdisplayclose);
|
|
dev_type_read(wsdisplayread);
|
|
dev_type_write(wsdisplaywrite);
|
|
dev_type_ioctl(wsdisplayioctl);
|
|
dev_type_stop(wsdisplaystop);
|
|
dev_type_tty(wsdisplaytty);
|
|
dev_type_poll(wsdisplaypoll);
|
|
dev_type_mmap(wsdisplaymmap);
|
|
dev_type_kqfilter(wsdisplaykqfilter);
|
|
|
|
const struct cdevsw wsdisplay_cdevsw = {
|
|
wsdisplayopen, wsdisplayclose, wsdisplayread, wsdisplaywrite,
|
|
wsdisplayioctl, wsdisplaystop, wsdisplaytty, wsdisplaypoll,
|
|
wsdisplaymmap, wsdisplaykqfilter, D_TTY
|
|
};
|
|
|
|
static void wsdisplaystart(struct tty *);
|
|
static int wsdisplayparam(struct tty *, struct termios *);
|
|
|
|
|
|
/* Internal macros, functions, and variables. */
|
|
#define SET(t, f) (t) |= (f)
|
|
#define CLR(t, f) (t) &= ~(f)
|
|
#define ISSET(t, f) ((t) & (f))
|
|
|
|
#define WSDISPLAYUNIT(dev) (minor(dev) >> 8)
|
|
#define WSDISPLAYSCREEN(dev) (minor(dev) & 0xff)
|
|
#define ISWSDISPLAYSTAT(dev) (WSDISPLAYSCREEN(dev) == 254)
|
|
#define ISWSDISPLAYCTL(dev) (WSDISPLAYSCREEN(dev) == 255)
|
|
#define WSDISPLAYMINOR(unit, screen) (((unit) << 8) | (screen))
|
|
|
|
#define WSSCREEN_HAS_EMULATOR(scr) ((scr)->scr_dconf->wsemul != NULL)
|
|
#define WSSCREEN_HAS_TTY(scr) ((scr)->scr_tty != NULL)
|
|
|
|
static void wsdisplay_common_attach(struct wsdisplay_softc *sc,
|
|
int console, int kbdmux, const struct wsscreen_list *,
|
|
const struct wsdisplay_accessops *accessops,
|
|
void *accesscookie);
|
|
|
|
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
|
int wsdisplay_update_rawkbd(struct wsdisplay_softc *,
|
|
struct wsscreen *);
|
|
#endif
|
|
|
|
static int wsdisplay_console_initted;
|
|
static struct wsdisplay_softc *wsdisplay_console_device;
|
|
static struct wsscreen_internal wsdisplay_console_conf;
|
|
|
|
static int wsdisplay_getc_dummy(dev_t);
|
|
static void wsdisplay_pollc(dev_t, int);
|
|
|
|
static int wsdisplay_cons_pollmode;
|
|
static void (*wsdisplay_cons_kbd_pollc)(dev_t, int);
|
|
|
|
static struct consdev wsdisplay_cons = {
|
|
NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc,
|
|
wsdisplay_pollc, NULL, NULL, NULL, NODEV, CN_NORMAL
|
|
};
|
|
|
|
#ifndef WSDISPLAY_DEFAULTSCREENS
|
|
# define WSDISPLAY_DEFAULTSCREENS 0
|
|
#endif
|
|
int wsdisplay_defaultscreens = WSDISPLAY_DEFAULTSCREENS;
|
|
|
|
int wsdisplay_switch1(void *, int, int);
|
|
int wsdisplay_switch2(void *, int, int);
|
|
int wsdisplay_switch3(void *, int, int);
|
|
|
|
int wsdisplay_clearonclose;
|
|
|
|
struct wsscreen *
|
|
wsscreen_attach(struct wsdisplay_softc *sc, int console, const char *emul,
|
|
const struct wsscreen_descr *type, void *cookie, int ccol,
|
|
int crow, long defattr)
|
|
{
|
|
struct wsscreen_internal *dconf;
|
|
struct wsscreen *scr;
|
|
|
|
scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_WAITOK);
|
|
if (!scr)
|
|
return (NULL);
|
|
|
|
if (console) {
|
|
dconf = &wsdisplay_console_conf;
|
|
/*
|
|
* If there's an emulation, tell it about the callback argument.
|
|
* The other stuff is already there.
|
|
*/
|
|
if (dconf->wsemul != NULL)
|
|
(*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr, 0);
|
|
} else { /* not console */
|
|
dconf = malloc(sizeof(struct wsscreen_internal),
|
|
M_DEVBUF, M_NOWAIT);
|
|
dconf->emulops = type->textops;
|
|
dconf->emulcookie = cookie;
|
|
if (dconf->emulops) {
|
|
dconf->wsemul = wsemul_pick(emul);
|
|
if (dconf->wsemul == NULL) {
|
|
free(dconf, M_DEVBUF);
|
|
free(scr, M_DEVBUF);
|
|
return (NULL);
|
|
}
|
|
dconf->wsemulcookie =
|
|
(*dconf->wsemul->attach)(0, type, cookie,
|
|
ccol, crow, scr, defattr);
|
|
} else
|
|
dconf->wsemul = NULL;
|
|
dconf->scrdata = type;
|
|
}
|
|
|
|
scr->scr_dconf = dconf;
|
|
|
|
scr->scr_tty = ttymalloc();
|
|
tty_attach(scr->scr_tty);
|
|
scr->scr_hold_screen = 0;
|
|
if (WSSCREEN_HAS_EMULATOR(scr))
|
|
scr->scr_flags = 0;
|
|
else
|
|
scr->scr_flags = SCR_GRAPHICS;
|
|
|
|
scr->scr_syncops = 0;
|
|
scr->sc = sc;
|
|
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
|
scr->scr_rawkbd = 0;
|
|
#endif
|
|
return (scr);
|
|
}
|
|
|
|
void
|
|
wsscreen_detach(struct wsscreen *scr)
|
|
{
|
|
u_int ccol, crow; /* XXX */
|
|
|
|
if (WSSCREEN_HAS_TTY(scr)) {
|
|
tty_detach(scr->scr_tty);
|
|
ttyfree(scr->scr_tty);
|
|
}
|
|
if (WSSCREEN_HAS_EMULATOR(scr))
|
|
(*scr->scr_dconf->wsemul->detach)(scr->scr_dconf->wsemulcookie,
|
|
&ccol, &crow);
|
|
free(scr->scr_dconf, M_DEVBUF);
|
|
free(scr, M_DEVBUF);
|
|
}
|
|
|
|
const struct wsscreen_descr *
|
|
wsdisplay_screentype_pick(const struct wsscreen_list *scrdata, const char *name)
|
|
{
|
|
int i;
|
|
const struct wsscreen_descr *scr;
|
|
|
|
KASSERT(scrdata->nscreens > 0);
|
|
|
|
if (name == NULL)
|
|
return (scrdata->screens[0]);
|
|
|
|
for (i = 0; i < scrdata->nscreens; i++) {
|
|
scr = scrdata->screens[i];
|
|
if (!strcmp(name, scr->name))
|
|
return (scr);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* print info about attached screen
|
|
*/
|
|
static void
|
|
wsdisplay_addscreen_print(struct wsdisplay_softc *sc, int idx, int count)
|
|
{
|
|
printf("%s: screen %d", sc->sc_dv.dv_xname, idx);
|
|
if (count > 1)
|
|
printf("-%d", idx + (count-1));
|
|
printf(" added (%s", sc->sc_scr[idx]->scr_dconf->scrdata->name);
|
|
if (WSSCREEN_HAS_EMULATOR(sc->sc_scr[idx])) {
|
|
printf(", %s emulation",
|
|
sc->sc_scr[idx]->scr_dconf->wsemul->name);
|
|
}
|
|
printf(")\n");
|
|
}
|
|
|
|
int
|
|
wsdisplay_addscreen(struct wsdisplay_softc *sc, int idx,
|
|
const char *screentype, const char *emul)
|
|
{
|
|
const struct wsscreen_descr *scrdesc;
|
|
int error;
|
|
void *cookie;
|
|
int ccol, crow;
|
|
long defattr;
|
|
struct wsscreen *scr;
|
|
int s;
|
|
|
|
if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
|
|
return (EINVAL);
|
|
if (sc->sc_scr[idx] != NULL)
|
|
return (EBUSY);
|
|
|
|
scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype);
|
|
if (!scrdesc)
|
|
return (ENXIO);
|
|
error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie,
|
|
scrdesc, &cookie, &ccol, &crow, &defattr);
|
|
if (error)
|
|
return (error);
|
|
|
|
scr = wsscreen_attach(sc, 0, emul, scrdesc,
|
|
cookie, ccol, crow, defattr);
|
|
if (scr == NULL) {
|
|
(*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
|
|
cookie);
|
|
return (ENXIO);
|
|
}
|
|
|
|
sc->sc_scr[idx] = scr;
|
|
|
|
/* if no screen has focus yet, activate the first we get */
|
|
s = spltty();
|
|
if (!sc->sc_focus) {
|
|
(*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
|
|
scr->scr_dconf->emulcookie,
|
|
0, 0, 0);
|
|
sc->sc_focusidx = idx;
|
|
sc->sc_focus = scr;
|
|
}
|
|
splx(s);
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
wsdisplay_closescreen(struct wsdisplay_softc *sc, struct wsscreen *scr)
|
|
{
|
|
int maj, mn, idx;
|
|
|
|
/* hangup */
|
|
if (WSSCREEN_HAS_TTY(scr)) {
|
|
struct tty *tp = scr->scr_tty;
|
|
(*tp->t_linesw->l_modem)(tp, 0);
|
|
}
|
|
|
|
/* locate the major number */
|
|
maj = cdevsw_lookup_major(&wsdisplay_cdevsw);
|
|
/* locate the screen index */
|
|
for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++)
|
|
if (scr == sc->sc_scr[idx])
|
|
break;
|
|
#ifdef DIAGNOSTIC
|
|
if (idx == WSDISPLAY_MAXSCREEN)
|
|
panic("wsdisplay_forceclose: bad screen");
|
|
#endif
|
|
|
|
/* nuke the vnodes */
|
|
mn = WSDISPLAYMINOR(sc->sc_dv.dv_unit, idx);
|
|
vdevgone(maj, mn, mn, VCHR);
|
|
}
|
|
|
|
#ifdef WSDISPLAY_SCROLLSUPPORT
|
|
void
|
|
wsdisplay_scroll(void *arg, int op)
|
|
{
|
|
struct wsdisplay_softc *sc = arg;
|
|
int lines;
|
|
|
|
if (op == WSDISPLAY_SCROLL_RESET)
|
|
lines = 0;
|
|
else {
|
|
lines = (op & WSDISPLAY_SCROLL_LOW) ?
|
|
sc->sc_scroll_values.slowlines :
|
|
sc->sc_scroll_values.fastlines;
|
|
if (op & WSDISPLAY_SCROLL_BACKWARD)
|
|
lines = -(lines);
|
|
}
|
|
|
|
if (sc->sc_accessops->scroll) {
|
|
(*sc->sc_accessops->scroll)(sc->sc_accesscookie,
|
|
sc->sc_focus->scr_dconf->emulcookie, lines);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int
|
|
wsdisplay_delscreen(struct wsdisplay_softc *sc, int idx, int flags)
|
|
{
|
|
struct wsscreen *scr;
|
|
int s;
|
|
void *cookie;
|
|
|
|
if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
|
|
return (EINVAL);
|
|
if ((scr = sc->sc_scr[idx]) == NULL)
|
|
return (ENXIO);
|
|
|
|
if (scr->scr_dconf == &wsdisplay_console_conf ||
|
|
scr->scr_syncops ||
|
|
((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE)))
|
|
return(EBUSY);
|
|
|
|
wsdisplay_closescreen(sc, scr);
|
|
|
|
/*
|
|
* delete pointers, so neither device entries
|
|
* nor keyboard input can reference it anymore
|
|
*/
|
|
s = spltty();
|
|
if (sc->sc_focus == scr) {
|
|
sc->sc_focus = 0;
|
|
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
|
wsdisplay_update_rawkbd(sc, 0);
|
|
#endif
|
|
}
|
|
sc->sc_scr[idx] = 0;
|
|
splx(s);
|
|
|
|
/*
|
|
* Wake up processes waiting for the screen to
|
|
* be activated. Sleepers must check whether
|
|
* the screen still exists.
|
|
*/
|
|
if (scr->scr_flags & SCR_WAITACTIVE)
|
|
wakeup(scr);
|
|
|
|
/* save a reference to the graphics screen */
|
|
cookie = scr->scr_dconf->emulcookie;
|
|
|
|
wsscreen_detach(scr);
|
|
|
|
(*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
|
|
cookie);
|
|
|
|
printf("%s: screen %d deleted\n", sc->sc_dv.dv_xname, idx);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Autoconfiguration functions.
|
|
*/
|
|
int
|
|
wsdisplay_emul_match(struct device *parent, struct cfdata *match, void *aux)
|
|
{
|
|
struct wsemuldisplaydev_attach_args *ap = aux;
|
|
|
|
if (match->wsemuldisplaydevcf_console !=
|
|
WSEMULDISPLAYDEVCF_CONSOLE_UNK) {
|
|
/*
|
|
* If console-ness of device specified, either match
|
|
* exactly (at high priority), or fail.
|
|
*/
|
|
if (match->wsemuldisplaydevcf_console != 0 &&
|
|
ap->console != 0)
|
|
return (10);
|
|
else
|
|
return (0);
|
|
}
|
|
|
|
/* If console-ness unspecified, it wins. */
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
wsdisplay_emul_attach(struct device *parent, struct device *self, void *aux)
|
|
{
|
|
struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
|
|
struct wsemuldisplaydev_attach_args *ap = aux;
|
|
|
|
wsdisplay_common_attach(sc, ap->console,
|
|
sc->sc_dv.dv_cfdata->wsemuldisplaydevcf_kbdmux, ap->scrdata,
|
|
ap->accessops, ap->accesscookie);
|
|
|
|
if (ap->console) {
|
|
int maj;
|
|
|
|
/* locate the major number */
|
|
maj = cdevsw_lookup_major(&wsdisplay_cdevsw);
|
|
|
|
cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(self->dv_unit, 0));
|
|
}
|
|
}
|
|
|
|
/* Print function (for parent devices). */
|
|
int
|
|
wsemuldisplaydevprint(void *aux, const char *pnp)
|
|
{
|
|
#if 0 /* -Wunused */
|
|
struct wsemuldisplaydev_attach_args *ap = aux;
|
|
#endif
|
|
|
|
if (pnp)
|
|
aprint_normal("wsdisplay at %s", pnp);
|
|
#if 0 /* don't bother; it's ugly */
|
|
aprint_normal(" console %d", ap->console);
|
|
#endif
|
|
|
|
return (UNCONF);
|
|
}
|
|
|
|
int
|
|
wsdisplay_noemul_match(struct device *parent, struct cfdata *match, void *aux)
|
|
{
|
|
#if 0 /* -Wunused */
|
|
struct wsdisplaydev_attach_args *ap = aux;
|
|
#endif
|
|
|
|
/* Always match. */
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
wsdisplay_noemul_attach(struct device *parent, struct device *self, void *aux)
|
|
{
|
|
struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
|
|
struct wsdisplaydev_attach_args *ap = aux;
|
|
|
|
wsdisplay_common_attach(sc, 0,
|
|
sc->sc_dv.dv_cfdata->wsemuldisplaydevcf_kbdmux, NULL,
|
|
ap->accessops, ap->accesscookie);
|
|
}
|
|
|
|
/* Print function (for parent devices). */
|
|
int
|
|
wsdisplaydevprint(void *aux, const char *pnp)
|
|
{
|
|
#if 0 /* -Wunused */
|
|
struct wsdisplaydev_attach_args *ap = aux;
|
|
#endif
|
|
|
|
if (pnp)
|
|
aprint_normal("wsdisplay at %s", pnp);
|
|
|
|
return (UNCONF);
|
|
}
|
|
|
|
static void
|
|
wsdisplay_common_attach(struct wsdisplay_softc *sc, int console, int kbdmux,
|
|
const struct wsscreen_list *scrdata,
|
|
const struct wsdisplay_accessops *accessops,
|
|
void *accesscookie)
|
|
{
|
|
static int hookset;
|
|
int i, start=0;
|
|
#if NWSKBD > 0
|
|
struct wsevsrc *kme;
|
|
#if NWSMUX > 0
|
|
struct wsmux_softc *mux;
|
|
|
|
if (kbdmux >= 0)
|
|
mux = wsmux_getmux(kbdmux);
|
|
else
|
|
mux = wsmux_create("dmux", sc->sc_dv.dv_unit);
|
|
/* XXX panic()ing isn't nice, but attach cannot fail */
|
|
if (mux == NULL)
|
|
panic("wsdisplay_common_attach: no memory");
|
|
sc->sc_input = &mux->sc_base;
|
|
mux->sc_base.me_dispdv = &sc->sc_dv;
|
|
printf(" kbdmux %d", kbdmux);
|
|
#else
|
|
if (kbdmux >= 0)
|
|
printf(" (kbdmux ignored)");
|
|
#endif
|
|
#endif
|
|
|
|
sc->sc_isconsole = console;
|
|
|
|
if (console) {
|
|
KASSERT(wsdisplay_console_initted);
|
|
KASSERT(wsdisplay_console_device == NULL);
|
|
|
|
sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0);
|
|
wsdisplay_console_device = sc;
|
|
|
|
printf(": console (%s, %s emulation)",
|
|
wsdisplay_console_conf.scrdata->name,
|
|
wsdisplay_console_conf.wsemul->name);
|
|
|
|
#if NWSKBD > 0
|
|
kme = wskbd_set_console_display(&sc->sc_dv, sc->sc_input);
|
|
if (kme != NULL)
|
|
printf(", using %s", kme->me_dv.dv_xname);
|
|
#if NWSMUX == 0
|
|
sc->sc_input = kme;
|
|
#endif
|
|
#endif
|
|
|
|
sc->sc_focusidx = 0;
|
|
sc->sc_focus = sc->sc_scr[0];
|
|
start = 1;
|
|
}
|
|
printf("\n");
|
|
|
|
#if NWSKBD > 0 && NWSMUX > 0
|
|
wsmux_set_display(mux, &sc->sc_dv);
|
|
#endif
|
|
|
|
sc->sc_accessops = accessops;
|
|
sc->sc_accesscookie = accesscookie;
|
|
sc->sc_scrdata = scrdata;
|
|
|
|
#ifdef WSDISPLAY_SCROLLSUPPORT
|
|
sc->sc_scroll_values = wsdisplay_default_scroll_values;
|
|
#endif
|
|
|
|
/*
|
|
* Set up a number of virtual screens if wanted. The
|
|
* WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code
|
|
* is for special cases like installation kernels.
|
|
*/
|
|
for (i = start; i < wsdisplay_defaultscreens; i++) {
|
|
if (wsdisplay_addscreen(sc, i, 0, 0))
|
|
break;
|
|
}
|
|
|
|
if (i > start)
|
|
wsdisplay_addscreen_print(sc, start, i-start);
|
|
|
|
if (hookset == 0)
|
|
shutdownhook_establish(wsdisplay_shutdownhook, NULL);
|
|
hookset = 1;
|
|
}
|
|
|
|
void
|
|
wsdisplay_cnattach(const struct wsscreen_descr *type, void *cookie,
|
|
int ccol, int crow, long defattr)
|
|
{
|
|
const struct wsemul_ops *wsemul;
|
|
|
|
KASSERT(!wsdisplay_console_initted);
|
|
KASSERT(type->nrows > 0);
|
|
KASSERT(type->ncols > 0);
|
|
KASSERT(crow < type->nrows);
|
|
KASSERT(ccol < type->ncols);
|
|
|
|
wsdisplay_console_conf.emulops = type->textops;
|
|
wsdisplay_console_conf.emulcookie = cookie;
|
|
wsdisplay_console_conf.scrdata = type;
|
|
|
|
wsemul = wsemul_pick(0); /* default */
|
|
wsdisplay_console_conf.wsemul = wsemul;
|
|
wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
|
|
ccol, crow,
|
|
defattr);
|
|
|
|
cn_tab = &wsdisplay_cons;
|
|
wsdisplay_console_initted = 1;
|
|
}
|
|
|
|
/*
|
|
* Tty and cdevsw functions.
|
|
*/
|
|
int
|
|
wsdisplayopen(dev_t dev, int flag, int mode, struct proc *p)
|
|
{
|
|
struct wsdisplay_softc *sc;
|
|
struct tty *tp;
|
|
int newopen, error;
|
|
struct wsscreen *scr;
|
|
|
|
sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
|
|
if (sc == NULL) /* make sure it was attached */
|
|
return (ENXIO);
|
|
|
|
if (ISWSDISPLAYSTAT(dev)) {
|
|
wsevent_init(&sc->evar);
|
|
sc->evar.io = p;
|
|
return (0);
|
|
}
|
|
|
|
if (ISWSDISPLAYCTL(dev))
|
|
return (0);
|
|
|
|
if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN)
|
|
return (ENXIO);
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
|
|
return (ENXIO);
|
|
|
|
if (WSSCREEN_HAS_TTY(scr)) {
|
|
tp = scr->scr_tty;
|
|
tp->t_oproc = wsdisplaystart;
|
|
tp->t_param = wsdisplayparam;
|
|
tp->t_dev = dev;
|
|
newopen = (tp->t_state & TS_ISOPEN) == 0;
|
|
if (newopen) {
|
|
ttychars(tp);
|
|
tp->t_iflag = TTYDEF_IFLAG;
|
|
tp->t_oflag = TTYDEF_OFLAG;
|
|
tp->t_cflag = TTYDEF_CFLAG;
|
|
tp->t_lflag = TTYDEF_LFLAG;
|
|
tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
|
|
wsdisplayparam(tp, &tp->t_termios);
|
|
ttsetwater(tp);
|
|
} else if ((tp->t_state & TS_XCLUDE) != 0 &&
|
|
p->p_ucred->cr_uid != 0)
|
|
return EBUSY;
|
|
tp->t_state |= TS_CARR_ON;
|
|
|
|
error = ((*tp->t_linesw->l_open)(dev, tp));
|
|
if (error)
|
|
return (error);
|
|
|
|
if (newopen && WSSCREEN_HAS_EMULATOR(scr)) {
|
|
/* set window sizes as appropriate, and reset
|
|
the emulation */
|
|
tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows;
|
|
tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols;
|
|
|
|
/* wsdisplay_set_emulation() */
|
|
}
|
|
}
|
|
|
|
scr->scr_flags |= SCR_OPEN;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
wsdisplayclose(dev_t dev, int flag, int mode, struct proc *p)
|
|
{
|
|
struct wsdisplay_softc *sc;
|
|
struct tty *tp;
|
|
struct wsscreen *scr;
|
|
|
|
sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
|
|
|
|
if (ISWSDISPLAYSTAT(dev)) {
|
|
wsevent_fini(&sc->evar);
|
|
return (0);
|
|
}
|
|
|
|
if (ISWSDISPLAYCTL(dev))
|
|
return (0);
|
|
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
|
|
return (0);
|
|
|
|
if (WSSCREEN_HAS_TTY(scr)) {
|
|
if (scr->scr_hold_screen) {
|
|
int s;
|
|
|
|
/* XXX RESET KEYBOARD LEDS, etc. */
|
|
s = spltty(); /* avoid conflict with keyboard */
|
|
wsdisplay_kbdholdscreen((struct device *)sc, 0);
|
|
splx(s);
|
|
}
|
|
tp = scr->scr_tty;
|
|
(*tp->t_linesw->l_close)(tp, flag);
|
|
ttyclose(tp);
|
|
}
|
|
|
|
if (scr->scr_syncops)
|
|
(*scr->scr_syncops->destroy)(scr->scr_synccookie);
|
|
|
|
if (WSSCREEN_HAS_EMULATOR(scr)) {
|
|
scr->scr_flags &= ~SCR_GRAPHICS;
|
|
(*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
|
|
WSEMUL_RESET);
|
|
if (wsdisplay_clearonclose)
|
|
(*scr->scr_dconf->wsemul->reset)
|
|
(scr->scr_dconf->wsemulcookie,
|
|
WSEMUL_CLEARSCREEN);
|
|
}
|
|
|
|
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
|
if (scr->scr_rawkbd) {
|
|
int kbmode = WSKBD_TRANSLATED;
|
|
(void)wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE,
|
|
(caddr_t)&kbmode, 0, p);
|
|
}
|
|
#endif
|
|
|
|
scr->scr_flags &= ~SCR_OPEN;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
wsdisplayread(dev_t dev, struct uio *uio, int flag)
|
|
{
|
|
struct wsdisplay_softc *sc;
|
|
struct tty *tp;
|
|
struct wsscreen *scr;
|
|
int error;
|
|
|
|
sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
|
|
|
|
if (ISWSDISPLAYSTAT(dev)) {
|
|
error = wsevent_read(&sc->evar, uio, flag);
|
|
return (error);
|
|
}
|
|
|
|
if (ISWSDISPLAYCTL(dev))
|
|
return (0);
|
|
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
|
|
return (ENXIO);
|
|
|
|
if (!WSSCREEN_HAS_TTY(scr))
|
|
return (ENODEV);
|
|
|
|
tp = scr->scr_tty;
|
|
return ((*tp->t_linesw->l_read)(tp, uio, flag));
|
|
}
|
|
|
|
int
|
|
wsdisplaywrite(dev_t dev, struct uio *uio, int flag)
|
|
{
|
|
struct wsdisplay_softc *sc;
|
|
struct tty *tp;
|
|
struct wsscreen *scr;
|
|
|
|
sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
|
|
|
|
if (ISWSDISPLAYSTAT(dev)) {
|
|
return (0);
|
|
}
|
|
|
|
if (ISWSDISPLAYCTL(dev))
|
|
return (0);
|
|
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
|
|
return (ENXIO);
|
|
|
|
if (!WSSCREEN_HAS_TTY(scr))
|
|
return (ENODEV);
|
|
|
|
tp = scr->scr_tty;
|
|
return ((*tp->t_linesw->l_write)(tp, uio, flag));
|
|
}
|
|
|
|
int
|
|
wsdisplaypoll(dev_t dev, int events, struct proc *p)
|
|
{
|
|
struct wsdisplay_softc *sc;
|
|
struct tty *tp;
|
|
struct wsscreen *scr;
|
|
|
|
sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
|
|
|
|
if (ISWSDISPLAYSTAT(dev))
|
|
return (wsevent_poll(&sc->evar, events, p));
|
|
|
|
if (ISWSDISPLAYCTL(dev))
|
|
return (0);
|
|
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
|
|
return (ENXIO);
|
|
|
|
if (!WSSCREEN_HAS_TTY(scr))
|
|
return (ENODEV);
|
|
|
|
tp = scr->scr_tty;
|
|
return ((*tp->t_linesw->l_poll)(tp, events, p));
|
|
}
|
|
|
|
int
|
|
wsdisplaykqfilter(dev, kn)
|
|
dev_t dev;
|
|
struct knote *kn;
|
|
{
|
|
struct wsdisplay_softc *sc =
|
|
device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
|
|
struct wsscreen *scr;
|
|
|
|
if (ISWSDISPLAYCTL(dev))
|
|
return (1);
|
|
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
|
|
return (1);
|
|
|
|
|
|
if (WSSCREEN_HAS_TTY(scr))
|
|
return (ttykqfilter(dev, kn));
|
|
else
|
|
return (1);
|
|
}
|
|
|
|
struct tty *
|
|
wsdisplaytty(dev_t dev)
|
|
{
|
|
struct wsdisplay_softc *sc;
|
|
struct wsscreen *scr;
|
|
|
|
sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
|
|
|
|
if (ISWSDISPLAYSTAT(dev))
|
|
panic("wsdisplaytty() on status device");
|
|
|
|
if (ISWSDISPLAYCTL(dev))
|
|
panic("wsdisplaytty() on ctl device");
|
|
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
|
|
return NULL;
|
|
|
|
return (scr->scr_tty);
|
|
}
|
|
|
|
int
|
|
wsdisplayioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
|
|
{
|
|
struct wsdisplay_softc *sc;
|
|
struct tty *tp;
|
|
int error;
|
|
struct wsscreen *scr;
|
|
|
|
sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
|
|
|
|
#ifdef WSDISPLAY_COMPAT_USL
|
|
error = wsdisplay_usl_ioctl1(sc, cmd, data, flag, p);
|
|
if (error != EPASSTHROUGH)
|
|
return (error);
|
|
#endif
|
|
|
|
if (ISWSDISPLAYSTAT(dev))
|
|
return (wsdisplay_stat_ioctl(sc, cmd, data, flag, p));
|
|
|
|
if (ISWSDISPLAYCTL(dev))
|
|
return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p));
|
|
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
|
|
return (ENXIO);
|
|
|
|
if (WSSCREEN_HAS_TTY(scr)) {
|
|
tp = scr->scr_tty;
|
|
|
|
/* printf("disc\n"); */
|
|
/* do the line discipline ioctls first */
|
|
error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
|
|
if (error != EPASSTHROUGH)
|
|
return (error);
|
|
|
|
/* printf("tty\n"); */
|
|
/* then the tty ioctls */
|
|
error = ttioctl(tp, cmd, data, flag, p);
|
|
if (error != EPASSTHROUGH)
|
|
return (error);
|
|
}
|
|
|
|
#ifdef WSDISPLAY_COMPAT_USL
|
|
error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p);
|
|
if (error != EPASSTHROUGH)
|
|
return (error);
|
|
#endif
|
|
|
|
return (wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p));
|
|
}
|
|
|
|
int
|
|
wsdisplay_param(struct device *dev, u_long cmd, struct wsdisplay_param *dp)
|
|
{
|
|
struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
|
|
return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd,
|
|
(caddr_t)dp, 0, NULL));
|
|
}
|
|
|
|
int
|
|
wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr,
|
|
u_long cmd, caddr_t data, int flag, struct proc *p)
|
|
{
|
|
int error;
|
|
char namebuf[16];
|
|
struct wsdisplay_font fd;
|
|
#ifdef WSDISPLAY_SCROLLSUPPORT
|
|
struct wsdisplay_scroll_data *ksdp, *usdp;
|
|
#endif
|
|
|
|
#if NWSKBD > 0
|
|
struct wsevsrc *inp;
|
|
|
|
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
|
switch (cmd) {
|
|
case WSKBDIO_SETMODE:
|
|
scr->scr_rawkbd = (*(int *)data == WSKBD_RAW);
|
|
return (wsdisplay_update_rawkbd(sc, scr));
|
|
case WSKBDIO_GETMODE:
|
|
*(int *)data = (scr->scr_rawkbd ?
|
|
WSKBD_RAW : WSKBD_TRANSLATED);
|
|
return (0);
|
|
}
|
|
#endif
|
|
inp = sc->sc_input;
|
|
if (inp == NULL)
|
|
return (ENXIO);
|
|
error = wsevsrc_display_ioctl(inp, cmd, data, flag, p);
|
|
if (error != EPASSTHROUGH)
|
|
return (error);
|
|
#endif /* NWSKBD > 0 */
|
|
|
|
switch (cmd) {
|
|
case WSDISPLAYIO_GMODE:
|
|
if (scr->scr_flags & SCR_GRAPHICS) {
|
|
if (scr->scr_flags & SCR_DUMBFB)
|
|
*(u_int *)data = WSDISPLAYIO_MODE_DUMBFB;
|
|
else
|
|
*(u_int *)data = WSDISPLAYIO_MODE_MAPPED;
|
|
} else
|
|
*(u_int *)data = WSDISPLAYIO_MODE_EMUL;
|
|
return (0);
|
|
|
|
case WSDISPLAYIO_SMODE:
|
|
#define d (*(int *)data)
|
|
if (d != WSDISPLAYIO_MODE_EMUL &&
|
|
d != WSDISPLAYIO_MODE_MAPPED &&
|
|
d != WSDISPLAYIO_MODE_DUMBFB)
|
|
return (EINVAL);
|
|
|
|
if (WSSCREEN_HAS_EMULATOR(scr)) {
|
|
scr->scr_flags &= ~SCR_GRAPHICS;
|
|
if (d == WSDISPLAYIO_MODE_MAPPED ||
|
|
d == WSDISPLAYIO_MODE_DUMBFB)
|
|
scr->scr_flags |= SCR_GRAPHICS |
|
|
((d == WSDISPLAYIO_MODE_DUMBFB) ? SCR_DUMBFB : 0);
|
|
} else if (d == WSDISPLAYIO_MODE_EMUL)
|
|
return (EINVAL);
|
|
|
|
(void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
|
|
flag, p);
|
|
|
|
return (0);
|
|
#undef d
|
|
|
|
#ifdef WSDISPLAY_SCROLLSUPPORT
|
|
#define SETSCROLLLINES(dstp, srcp, dfltp) \
|
|
do { \
|
|
(dstp)->fastlines = ((srcp)->which & \
|
|
WSDISPLAY_SCROLL_DOFASTLINES) ? \
|
|
(srcp)->fastlines : (dfltp)->fastlines; \
|
|
(dstp)->slowlines = ((srcp)->which & \
|
|
WSDISPLAY_SCROLL_DOSLOWLINES) ? \
|
|
(srcp)->slowlines : (dfltp)->slowlines; \
|
|
(dstp)->which = WSDISPLAY_SCROLL_DOALL; \
|
|
} while (0)
|
|
|
|
|
|
case WSDISPLAYIO_DSSCROLL:
|
|
usdp = (struct wsdisplay_scroll_data *)data;
|
|
ksdp = &sc->sc_scroll_values;
|
|
SETSCROLLLINES(ksdp, usdp, ksdp);
|
|
return (0);
|
|
|
|
case WSDISPLAYIO_DGSCROLL:
|
|
usdp = (struct wsdisplay_scroll_data *)data;
|
|
ksdp = &sc->sc_scroll_values;
|
|
SETSCROLLLINES(usdp, ksdp, ksdp);
|
|
return (0);
|
|
#else
|
|
case WSDISPLAYIO_DSSCROLL:
|
|
case WSDISPLAYIO_DGSCROLL:
|
|
return ENODEV;
|
|
#endif
|
|
|
|
case WSDISPLAYIO_SFONT:
|
|
#define d ((struct wsdisplay_usefontdata *)data)
|
|
if (!sc->sc_accessops->load_font)
|
|
return (EINVAL);
|
|
if (d->name) {
|
|
error = copyinstr(d->name, namebuf, sizeof(namebuf), 0);
|
|
if (error)
|
|
return (error);
|
|
fd.name = namebuf;
|
|
} else
|
|
fd.name = 0;
|
|
fd.data = 0;
|
|
error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie,
|
|
scr->scr_dconf->emulcookie, &fd);
|
|
if (!error && WSSCREEN_HAS_EMULATOR(scr))
|
|
(*scr->scr_dconf->wsemul->reset)
|
|
(scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT);
|
|
return (error);
|
|
#undef d
|
|
|
|
#if defined(WSDISPLAY_CHARFUNCS)
|
|
case WSDISPLAYIO_GETWSCHAR:
|
|
#define d ((struct wsdisplay_char *)data)
|
|
if (!sc->sc_accessops->getwschar)
|
|
return (EINVAL);
|
|
return ((*sc->sc_accessops->getwschar)
|
|
(scr->scr_dconf->emulcookie, d));
|
|
#undef d
|
|
|
|
case WSDISPLAYIO_PUTWSCHAR:
|
|
#define d ((struct wsdisplay_char *)data)
|
|
if (!sc->sc_accessops->putwschar)
|
|
return (EINVAL);
|
|
return ((*sc->sc_accessops->putwschar)
|
|
(scr->scr_dconf->emulcookie, d));
|
|
#undef d
|
|
#else
|
|
case WSDISPLAYIO_PUTWSCHAR:
|
|
case WSDISPLAYIO_GETWSCHAR:
|
|
return ENODEV;
|
|
#endif /* WSDISPLAY_CHARFUNCS */
|
|
|
|
#ifdef WSDISPLAY_CUSTOM_OUTPUT
|
|
case WSDISPLAYIO_GMSGATTRS:
|
|
#define d ((struct wsdisplay_msgattrs *)data)
|
|
(*scr->scr_dconf->wsemul->getmsgattrs)
|
|
(scr->scr_dconf->wsemulcookie, d);
|
|
return (0);
|
|
#undef d
|
|
|
|
case WSDISPLAYIO_SMSGATTRS: {
|
|
#define d ((struct wsdisplay_msgattrs *)data)
|
|
int i;
|
|
for (i = 0; i < WSDISPLAY_MAXSCREEN; i++)
|
|
if (sc->sc_scr[i] != NULL)
|
|
(*sc->sc_scr[i]->scr_dconf->wsemul->setmsgattrs)
|
|
(sc->sc_scr[i]->scr_dconf->wsemulcookie,
|
|
sc->sc_scr[i]->scr_dconf->scrdata,
|
|
d);
|
|
}
|
|
return (0);
|
|
#undef d
|
|
#else
|
|
case WSDISPLAYIO_GMSGATTRS:
|
|
case WSDISPLAYIO_SMSGATTRS:
|
|
return (ENODEV);
|
|
#endif
|
|
|
|
#ifdef WSDISPLAY_CUSTOM_BORDER
|
|
case WSDISPLAYIO_GBORDER:
|
|
if (!sc->sc_accessops->getborder)
|
|
return (EINVAL);
|
|
*(u_int *)data = (*sc->sc_accessops->getborder)
|
|
(scr->scr_dconf->emulcookie);
|
|
return (0);
|
|
case WSDISPLAYIO_SBORDER:
|
|
if (!sc->sc_accessops->setborder)
|
|
return (EINVAL);
|
|
return (*sc->sc_accessops->setborder)
|
|
(scr->scr_dconf->emulcookie, (*(u_int *)data));
|
|
#else /* WSDISPLAY_CUSTOM_BORDER */
|
|
case WSDISPLAYIO_GBORDER:
|
|
case WSDISPLAYIO_SBORDER:
|
|
return (ENODEV);
|
|
#endif /* WSDISPLAY_CUSTOM_BORDER */
|
|
|
|
}
|
|
|
|
/* check ioctls for display */
|
|
return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
|
|
flag, p));
|
|
}
|
|
|
|
int
|
|
wsdisplay_stat_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data,
|
|
int flag, struct proc *p)
|
|
{
|
|
switch (cmd) {
|
|
case WSDISPLAYIO_GETACTIVESCREEN:
|
|
*(int*)data = wsdisplay_getactivescreen(sc);
|
|
return (0);
|
|
}
|
|
|
|
return (EPASSTHROUGH);
|
|
}
|
|
|
|
int
|
|
wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data,
|
|
int flag, struct proc *p)
|
|
{
|
|
int error;
|
|
char *type, typebuf[16], *emul, emulbuf[16];
|
|
void *buf;
|
|
u_int fontsz;
|
|
#if defined(COMPAT_14) && NWSKBD > 0
|
|
struct wsmux_device wsmuxdata;
|
|
#endif
|
|
#if NWSKBD > 0
|
|
struct wsevsrc *inp;
|
|
#endif
|
|
|
|
switch (cmd) {
|
|
case WSDISPLAYIO_ADDSCREEN:
|
|
#define d ((struct wsdisplay_addscreendata *)data)
|
|
if (d->screentype) {
|
|
error = copyinstr(d->screentype, typebuf,
|
|
sizeof(typebuf), 0);
|
|
if (error)
|
|
return (error);
|
|
type = typebuf;
|
|
} else
|
|
type = 0;
|
|
if (d->emul) {
|
|
error = copyinstr(d->emul, emulbuf, sizeof(emulbuf),0);
|
|
if (error)
|
|
return (error);
|
|
emul = emulbuf;
|
|
} else
|
|
emul = 0;
|
|
|
|
if ((error = wsdisplay_addscreen(sc, d->idx, type, emul)) == 0)
|
|
wsdisplay_addscreen_print(sc, d->idx, 0);
|
|
return (error);
|
|
#undef d
|
|
case WSDISPLAYIO_DELSCREEN:
|
|
#define d ((struct wsdisplay_delscreendata *)data)
|
|
return (wsdisplay_delscreen(sc, d->idx, d->flags));
|
|
#undef d
|
|
case WSDISPLAYIO_LDFONT:
|
|
#define d ((struct wsdisplay_font *)data)
|
|
if (!sc->sc_accessops->load_font)
|
|
return (EINVAL);
|
|
if (d->name) {
|
|
error = copyinstr(d->name, typebuf, sizeof(typebuf), 0);
|
|
if (error)
|
|
return (error);
|
|
d->name = typebuf;
|
|
} else
|
|
d->name = "loaded"; /* ??? */
|
|
fontsz = d->fontheight * d->stride * d->numchars;
|
|
if (fontsz > WSDISPLAY_MAXFONTSZ)
|
|
return (EINVAL);
|
|
|
|
buf = malloc(fontsz, M_DEVBUF, M_WAITOK);
|
|
error = copyin(d->data, buf, fontsz);
|
|
if (error) {
|
|
free(buf, M_DEVBUF);
|
|
return (error);
|
|
}
|
|
d->data = buf;
|
|
error =
|
|
(*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d);
|
|
free(buf, M_DEVBUF);
|
|
#undef d
|
|
return (error);
|
|
|
|
#if NWSKBD > 0
|
|
#ifdef COMPAT_14
|
|
case _O_WSDISPLAYIO_SETKEYBOARD:
|
|
#define d ((struct wsdisplay_kbddata *)data)
|
|
inp = sc->sc_input;
|
|
if (inp == NULL)
|
|
return (ENXIO);
|
|
switch (d->op) {
|
|
case _O_WSDISPLAY_KBD_ADD:
|
|
if (d->idx == -1) {
|
|
d->idx = wskbd_pickfree();
|
|
if (d->idx == -1)
|
|
return (ENXIO);
|
|
}
|
|
wsmuxdata.type = WSMUX_KBD;
|
|
wsmuxdata.idx = d->idx;
|
|
return (wsevsrc_ioctl(inp, WSMUX_ADD_DEVICE,
|
|
&wsmuxdata, flag, p));
|
|
case _O_WSDISPLAY_KBD_DEL:
|
|
wsmuxdata.type = WSMUX_KBD;
|
|
wsmuxdata.idx = d->idx;
|
|
return (wsevsrc_ioctl(inp, WSMUX_REMOVE_DEVICE,
|
|
&wsmuxdata, flag, p));
|
|
default:
|
|
return (EINVAL);
|
|
}
|
|
#undef d
|
|
#endif
|
|
|
|
case WSMUXIO_ADD_DEVICE:
|
|
#define d ((struct wsmux_device *)data)
|
|
if (d->idx == -1 && d->type == WSMUX_KBD)
|
|
d->idx = wskbd_pickfree();
|
|
#undef d
|
|
/* fall into */
|
|
case WSMUXIO_INJECTEVENT:
|
|
case WSMUXIO_REMOVE_DEVICE:
|
|
case WSMUXIO_LIST_DEVICES:
|
|
inp = sc->sc_input;
|
|
if (inp == NULL)
|
|
return (ENXIO);
|
|
return (wsevsrc_ioctl(inp, cmd, data, flag, p));
|
|
#endif /* NWSKBD > 0 */
|
|
|
|
}
|
|
return (EPASSTHROUGH);
|
|
}
|
|
|
|
int
|
|
wsdisplay_stat_inject(struct device *dev, u_int type, int value)
|
|
{
|
|
struct wsdisplay_softc *sc = (struct wsdisplay_softc *) dev;
|
|
struct wseventvar *evar;
|
|
struct wscons_event *ev;
|
|
struct timeval thistime;
|
|
int put;
|
|
|
|
evar = &sc->evar;
|
|
|
|
if (evar == NULL)
|
|
return (0);
|
|
|
|
if (evar->q == NULL)
|
|
return (1);
|
|
|
|
put = evar->put;
|
|
ev = &evar->q[put];
|
|
put = (put + 1) % WSEVENT_QSIZE;
|
|
if (put == evar->get) {
|
|
log(LOG_WARNING, "wsdisplay: event queue overflow\n");
|
|
return (1);
|
|
}
|
|
ev->type = type;
|
|
ev->value = value;
|
|
microtime(&thistime);
|
|
TIMEVAL_TO_TIMESPEC(&thistime, &ev->time);
|
|
evar->put = put;
|
|
WSEVENT_WAKEUP(evar);
|
|
|
|
return (0);
|
|
}
|
|
|
|
paddr_t
|
|
wsdisplaymmap(dev_t dev, off_t offset, int prot)
|
|
{
|
|
struct wsdisplay_softc *sc =
|
|
device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
|
|
struct wsscreen *scr;
|
|
|
|
if (ISWSDISPLAYSTAT(dev))
|
|
return (-1);
|
|
|
|
if (ISWSDISPLAYCTL(dev))
|
|
return (-1);
|
|
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
|
|
return (-1);
|
|
|
|
if (!(scr->scr_flags & SCR_GRAPHICS))
|
|
return (-1);
|
|
|
|
/* pass mmap to display */
|
|
return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot));
|
|
}
|
|
|
|
void
|
|
wsdisplaystart(struct tty *tp)
|
|
{
|
|
struct wsdisplay_softc *sc;
|
|
struct wsscreen *scr;
|
|
int s, n;
|
|
u_char *buf;
|
|
|
|
s = spltty();
|
|
if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
|
|
splx(s);
|
|
return;
|
|
}
|
|
sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(tp->t_dev));
|
|
if ((scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]) == NULL) {
|
|
splx(s);
|
|
return;
|
|
}
|
|
|
|
if (scr->scr_hold_screen) {
|
|
tp->t_state |= TS_TIMEOUT;
|
|
splx(s);
|
|
return;
|
|
}
|
|
tp->t_state |= TS_BUSY;
|
|
splx(s);
|
|
|
|
/*
|
|
* Drain output from ring buffer.
|
|
* The output will normally be in one contiguous chunk, but when the
|
|
* ring wraps, it will be in two pieces.. one at the end of the ring,
|
|
* the other at the start. For performance, rather than loop here,
|
|
* we output one chunk, see if there's another one, and if so, output
|
|
* it too.
|
|
*/
|
|
|
|
n = ndqb(&tp->t_outq, 0);
|
|
buf = tp->t_outq.c_cf;
|
|
|
|
if (!(scr->scr_flags & SCR_GRAPHICS)) {
|
|
KASSERT(WSSCREEN_HAS_EMULATOR(scr));
|
|
(*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
|
|
buf, n, 0);
|
|
}
|
|
ndflush(&tp->t_outq, n);
|
|
|
|
if ((n = ndqb(&tp->t_outq, 0)) > 0) {
|
|
buf = tp->t_outq.c_cf;
|
|
|
|
if (!(scr->scr_flags & SCR_GRAPHICS)) {
|
|
KASSERT(WSSCREEN_HAS_EMULATOR(scr));
|
|
(*scr->scr_dconf->wsemul->output)
|
|
(scr->scr_dconf->wsemulcookie, buf, n, 0);
|
|
}
|
|
ndflush(&tp->t_outq, n);
|
|
}
|
|
|
|
s = spltty();
|
|
tp->t_state &= ~TS_BUSY;
|
|
/* Come back if there's more to do */
|
|
if (tp->t_outq.c_cc) {
|
|
tp->t_state |= TS_TIMEOUT;
|
|
callout_reset(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1,
|
|
ttrstrt, tp);
|
|
}
|
|
if (tp->t_outq.c_cc <= tp->t_lowat) {
|
|
if (tp->t_state&TS_ASLEEP) {
|
|
tp->t_state &= ~TS_ASLEEP;
|
|
wakeup(&tp->t_outq);
|
|
}
|
|
selwakeup(&tp->t_wsel);
|
|
}
|
|
splx(s);
|
|
}
|
|
|
|
void
|
|
wsdisplaystop(struct tty *tp, int flag)
|
|
{
|
|
int s;
|
|
|
|
s = spltty();
|
|
if (ISSET(tp->t_state, TS_BUSY))
|
|
if (!ISSET(tp->t_state, TS_TTSTOP))
|
|
SET(tp->t_state, TS_FLUSH);
|
|
splx(s);
|
|
}
|
|
|
|
/* Set line parameters. */
|
|
int
|
|
wsdisplayparam(struct tty *tp, struct termios *t)
|
|
{
|
|
|
|
tp->t_ispeed = t->c_ispeed;
|
|
tp->t_ospeed = t->c_ospeed;
|
|
tp->t_cflag = t->c_cflag;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Callbacks for the emulation code.
|
|
*/
|
|
void
|
|
wsdisplay_emulbell(void *v)
|
|
{
|
|
struct wsscreen *scr = v;
|
|
|
|
if (scr == NULL) /* console, before real attach */
|
|
return;
|
|
|
|
if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */
|
|
return;
|
|
|
|
(void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL,
|
|
FWRITE, NULL);
|
|
}
|
|
|
|
void
|
|
wsdisplay_emulinput(void *v, const u_char *data, u_int count)
|
|
{
|
|
struct wsscreen *scr = v;
|
|
struct tty *tp;
|
|
|
|
if (v == NULL) /* console, before real attach */
|
|
return;
|
|
|
|
if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */
|
|
return;
|
|
if (!WSSCREEN_HAS_TTY(scr))
|
|
return;
|
|
|
|
tp = scr->scr_tty;
|
|
while (count-- > 0)
|
|
(*tp->t_linesw->l_rint)(*data++, tp);
|
|
}
|
|
|
|
/*
|
|
* Calls from the keyboard interface.
|
|
*/
|
|
void
|
|
wsdisplay_kbdinput(struct device *dev, keysym_t ks)
|
|
{
|
|
struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
|
|
struct wsscreen *scr;
|
|
char *dp;
|
|
int count;
|
|
struct tty *tp;
|
|
|
|
KASSERT(sc != NULL);
|
|
|
|
scr = sc->sc_focus;
|
|
|
|
if (!scr || !WSSCREEN_HAS_TTY(scr))
|
|
return;
|
|
|
|
tp = scr->scr_tty;
|
|
|
|
if (KS_GROUP(ks) == KS_GROUP_Ascii)
|
|
(*tp->t_linesw->l_rint)(KS_VALUE(ks), tp);
|
|
else if (WSSCREEN_HAS_EMULATOR(scr)) {
|
|
count = (*scr->scr_dconf->wsemul->translate)
|
|
(scr->scr_dconf->wsemulcookie, ks, &dp);
|
|
while (count-- > 0)
|
|
(*tp->t_linesw->l_rint)(*dp++, tp);
|
|
}
|
|
}
|
|
|
|
#if defined(WSDISPLAY_COMPAT_RAWKBD)
|
|
int
|
|
wsdisplay_update_rawkbd(struct wsdisplay_softc *sc, struct wsscreen *scr)
|
|
{
|
|
#if NWSKBD > 0
|
|
int s, raw, data, error;
|
|
struct wsevsrc *inp;
|
|
|
|
s = spltty();
|
|
|
|
raw = (scr ? scr->scr_rawkbd : 0);
|
|
|
|
if (scr != sc->sc_focus ||
|
|
sc->sc_rawkbd == raw) {
|
|
splx(s);
|
|
return (0);
|
|
}
|
|
|
|
data = raw ? WSKBD_RAW : WSKBD_TRANSLATED;
|
|
inp = sc->sc_input;
|
|
if (inp == NULL)
|
|
return (ENXIO);
|
|
error = wsevsrc_display_ioctl(inp, WSKBDIO_SETMODE, &data, 0, 0);
|
|
if (!error)
|
|
sc->sc_rawkbd = raw;
|
|
splx(s);
|
|
return (error);
|
|
#else
|
|
return (0);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
int
|
|
wsdisplay_switch3(void *arg, int error, int waitok)
|
|
{
|
|
struct wsdisplay_softc *sc = arg;
|
|
int no;
|
|
struct wsscreen *scr;
|
|
|
|
if (!(sc->sc_flags & SC_SWITCHPENDING)) {
|
|
printf("wsdisplay_switch3: not switching\n");
|
|
return (EINVAL);
|
|
}
|
|
|
|
no = sc->sc_screenwanted;
|
|
if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
|
|
panic("wsdisplay_switch3: invalid screen %d", no);
|
|
scr = sc->sc_scr[no];
|
|
if (!scr) {
|
|
printf("wsdisplay_switch3: screen %d disappeared\n", no);
|
|
error = ENXIO;
|
|
}
|
|
|
|
if (error) {
|
|
/* try to recover, avoid recursion */
|
|
|
|
if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) {
|
|
printf("wsdisplay_switch3: giving up\n");
|
|
sc->sc_focus = 0;
|
|
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
|
wsdisplay_update_rawkbd(sc, 0);
|
|
#endif
|
|
sc->sc_flags &= ~SC_SWITCHPENDING;
|
|
return (error);
|
|
}
|
|
|
|
sc->sc_screenwanted = sc->sc_oldscreen;
|
|
sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
|
|
return (wsdisplay_switch1(arg, 0, waitok));
|
|
}
|
|
|
|
sc->sc_flags &= ~SC_SWITCHPENDING;
|
|
|
|
if (!error && (scr->scr_flags & SCR_WAITACTIVE))
|
|
wakeup(scr);
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
wsdisplay_switch2(void *arg, int error, int waitok)
|
|
{
|
|
struct wsdisplay_softc *sc = arg;
|
|
int no;
|
|
struct wsscreen *scr;
|
|
|
|
if (!(sc->sc_flags & SC_SWITCHPENDING)) {
|
|
printf("wsdisplay_switch2: not switching\n");
|
|
return (EINVAL);
|
|
}
|
|
|
|
no = sc->sc_screenwanted;
|
|
if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
|
|
panic("wsdisplay_switch2: invalid screen %d", no);
|
|
scr = sc->sc_scr[no];
|
|
if (!scr) {
|
|
printf("wsdisplay_switch2: screen %d disappeared\n", no);
|
|
error = ENXIO;
|
|
}
|
|
|
|
if (error) {
|
|
/* try to recover, avoid recursion */
|
|
|
|
if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) {
|
|
printf("wsdisplay_switch2: giving up\n");
|
|
sc->sc_focus = 0;
|
|
sc->sc_flags &= ~SC_SWITCHPENDING;
|
|
return (error);
|
|
}
|
|
|
|
sc->sc_screenwanted = sc->sc_oldscreen;
|
|
sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
|
|
return (wsdisplay_switch1(arg, 0, waitok));
|
|
}
|
|
|
|
sc->sc_focusidx = no;
|
|
sc->sc_focus = scr;
|
|
|
|
#ifdef WSDISPLAY_COMPAT_RAWKBD
|
|
(void) wsdisplay_update_rawkbd(sc, scr);
|
|
#endif
|
|
/* keyboard map??? */
|
|
|
|
#define wsswitch_cb3 ((void (*)(void *, int, int))wsdisplay_switch3)
|
|
if (scr->scr_syncops) {
|
|
error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok,
|
|
sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb3, sc);
|
|
if (error == EAGAIN) {
|
|
/* switch will be done asynchronously */
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
return (wsdisplay_switch3(sc, error, waitok));
|
|
}
|
|
|
|
int
|
|
wsdisplay_switch1(void *arg, int error, int waitok)
|
|
{
|
|
struct wsdisplay_softc *sc = arg;
|
|
int no;
|
|
struct wsscreen *scr;
|
|
|
|
if (!(sc->sc_flags & SC_SWITCHPENDING)) {
|
|
printf("wsdisplay_switch1: not switching\n");
|
|
return (EINVAL);
|
|
}
|
|
|
|
no = sc->sc_screenwanted;
|
|
if (no == WSDISPLAY_NULLSCREEN) {
|
|
sc->sc_flags &= ~SC_SWITCHPENDING;
|
|
if (!error) {
|
|
sc->sc_focus = 0;
|
|
}
|
|
wakeup(sc);
|
|
return (error);
|
|
}
|
|
if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
|
|
panic("wsdisplay_switch1: invalid screen %d", no);
|
|
scr = sc->sc_scr[no];
|
|
if (!scr) {
|
|
printf("wsdisplay_switch1: screen %d disappeared\n", no);
|
|
error = ENXIO;
|
|
}
|
|
|
|
if (error) {
|
|
sc->sc_flags &= ~SC_SWITCHPENDING;
|
|
return (error);
|
|
}
|
|
|
|
#define wsswitch_cb2 ((void (*)(void *, int, int))wsdisplay_switch2)
|
|
error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
|
|
scr->scr_dconf->emulcookie,
|
|
waitok,
|
|
sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc);
|
|
if (error == EAGAIN) {
|
|
/* switch will be done asynchronously */
|
|
return (0);
|
|
}
|
|
|
|
return (wsdisplay_switch2(sc, error, waitok));
|
|
}
|
|
|
|
int
|
|
wsdisplay_switch(struct device *dev, int no, int waitok)
|
|
{
|
|
struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
|
|
int s, res = 0;
|
|
struct wsscreen *scr;
|
|
|
|
if (no != WSDISPLAY_NULLSCREEN) {
|
|
if ((no < 0 || no >= WSDISPLAY_MAXSCREEN))
|
|
return (EINVAL);
|
|
if (sc->sc_scr[no] == NULL)
|
|
return (ENXIO);
|
|
}
|
|
|
|
wsdisplay_stat_inject(dev, WSCONS_EVENT_SCREEN_SWITCH, no);
|
|
|
|
s = spltty();
|
|
|
|
if ((sc->sc_focus && no == sc->sc_focusidx) ||
|
|
(sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) {
|
|
splx(s);
|
|
return (0);
|
|
}
|
|
|
|
if (sc->sc_flags & SC_SWITCHPENDING) {
|
|
splx(s);
|
|
return (EBUSY);
|
|
}
|
|
|
|
sc->sc_flags |= SC_SWITCHPENDING;
|
|
sc->sc_screenwanted = no;
|
|
|
|
splx(s);
|
|
|
|
scr = sc->sc_focus;
|
|
if (!scr) {
|
|
sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
|
|
return (wsdisplay_switch1(sc, 0, waitok));
|
|
} else
|
|
sc->sc_oldscreen = sc->sc_focusidx;
|
|
|
|
#define wsswitch_cb1 ((void (*)(void *, int, int))wsdisplay_switch1)
|
|
if (scr->scr_syncops) {
|
|
res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok,
|
|
sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb1, sc);
|
|
if (res == EAGAIN) {
|
|
/* switch will be done asynchronously */
|
|
return (0);
|
|
}
|
|
} else if (scr->scr_flags & SCR_GRAPHICS) {
|
|
/* no way to save state */
|
|
res = EBUSY;
|
|
}
|
|
|
|
return (wsdisplay_switch1(sc, res, waitok));
|
|
}
|
|
|
|
void
|
|
wsdisplay_reset(struct device *dev, enum wsdisplay_resetops op)
|
|
{
|
|
struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
|
|
struct wsscreen *scr;
|
|
|
|
KASSERT(sc != NULL);
|
|
scr = sc->sc_focus;
|
|
|
|
if (!scr)
|
|
return;
|
|
|
|
switch (op) {
|
|
case WSDISPLAY_RESETEMUL:
|
|
if (!WSSCREEN_HAS_EMULATOR(scr))
|
|
break;
|
|
(*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
|
|
WSEMUL_RESET);
|
|
break;
|
|
case WSDISPLAY_RESETCLOSE:
|
|
wsdisplay_closescreen(sc, scr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Interface for (external) VT switch / process synchronization code
|
|
*/
|
|
int
|
|
wsscreen_attach_sync(struct wsscreen *scr, const struct wscons_syncops *ops,
|
|
void *cookie)
|
|
{
|
|
if (scr->scr_syncops) {
|
|
/*
|
|
* The screen is already claimed.
|
|
* Check if the owner is still alive.
|
|
*/
|
|
if ((*scr->scr_syncops->check)(scr->scr_synccookie))
|
|
return (EBUSY);
|
|
}
|
|
scr->scr_syncops = ops;
|
|
scr->scr_synccookie = cookie;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
wsscreen_detach_sync(struct wsscreen *scr)
|
|
{
|
|
if (!scr->scr_syncops)
|
|
return (EINVAL);
|
|
scr->scr_syncops = 0;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
wsscreen_lookup_sync(struct wsscreen *scr,
|
|
const struct wscons_syncops *ops, /* used as ID */
|
|
void **cookiep)
|
|
{
|
|
if (!scr->scr_syncops || ops != scr->scr_syncops)
|
|
return (EINVAL);
|
|
*cookiep = scr->scr_synccookie;
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Interface to virtual screen stuff
|
|
*/
|
|
int
|
|
wsdisplay_maxscreenidx(struct wsdisplay_softc *sc)
|
|
{
|
|
return (WSDISPLAY_MAXSCREEN - 1);
|
|
}
|
|
|
|
int
|
|
wsdisplay_screenstate(struct wsdisplay_softc *sc, int idx)
|
|
{
|
|
if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
|
|
return (EINVAL);
|
|
if (!sc->sc_scr[idx])
|
|
return (ENXIO);
|
|
return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0);
|
|
}
|
|
|
|
int
|
|
wsdisplay_getactivescreen(struct wsdisplay_softc *sc)
|
|
{
|
|
return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN);
|
|
}
|
|
|
|
int
|
|
wsscreen_switchwait(struct wsdisplay_softc *sc, int no)
|
|
{
|
|
struct wsscreen *scr;
|
|
int s, res = 0;
|
|
|
|
if (no == WSDISPLAY_NULLSCREEN) {
|
|
s = spltty();
|
|
while (sc->sc_focus && res == 0) {
|
|
res = tsleep(sc, PCATCH, "wswait", 0);
|
|
}
|
|
splx(s);
|
|
return (res);
|
|
}
|
|
|
|
if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
|
|
return (ENXIO);
|
|
scr = sc->sc_scr[no];
|
|
if (!scr)
|
|
return (ENXIO);
|
|
|
|
s = spltty();
|
|
if (scr != sc->sc_focus) {
|
|
scr->scr_flags |= SCR_WAITACTIVE;
|
|
res = tsleep(scr, PCATCH, "wswait", 0);
|
|
if (scr != sc->sc_scr[no])
|
|
res = ENXIO; /* disappeared in the meantime */
|
|
else
|
|
scr->scr_flags &= ~SCR_WAITACTIVE;
|
|
}
|
|
splx(s);
|
|
return (res);
|
|
}
|
|
|
|
void
|
|
wsdisplay_kbdholdscreen(struct device *dev, int hold)
|
|
{
|
|
struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
|
|
struct wsscreen *scr;
|
|
|
|
scr = sc->sc_focus;
|
|
|
|
if (hold)
|
|
scr->scr_hold_screen = 1;
|
|
else {
|
|
scr->scr_hold_screen = 0;
|
|
callout_reset(&scr->scr_tty->t_rstrt_ch, 0,
|
|
ttrstrt, scr->scr_tty); /* "immediate" */
|
|
}
|
|
}
|
|
|
|
#if NWSKBD > 0
|
|
void
|
|
wsdisplay_set_console_kbd(struct wsevsrc *src)
|
|
{
|
|
if (wsdisplay_console_device == NULL) {
|
|
src->me_dispdv = NULL;
|
|
return;
|
|
}
|
|
#if NWSMUX > 0
|
|
if (wsmux_attach_sc((struct wsmux_softc *)
|
|
wsdisplay_console_device->sc_input, src)) {
|
|
src->me_dispdv = NULL;
|
|
return;
|
|
}
|
|
#else
|
|
wsdisplay_console_device->sc_input = src;
|
|
#endif
|
|
src->me_dispdv = &wsdisplay_console_device->sc_dv;
|
|
}
|
|
#endif /* NWSKBD > 0 */
|
|
|
|
/*
|
|
* Console interface.
|
|
*/
|
|
void
|
|
wsdisplay_cnputc(dev_t dev, int i)
|
|
{
|
|
struct wsscreen_internal *dc;
|
|
u_char c = i;
|
|
|
|
if (!wsdisplay_console_initted)
|
|
return;
|
|
|
|
if ((wsdisplay_console_device != NULL) &&
|
|
(wsdisplay_console_device->sc_scr[0] != NULL) &&
|
|
(wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS))
|
|
return;
|
|
|
|
dc = &wsdisplay_console_conf;
|
|
(*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1);
|
|
}
|
|
|
|
static int
|
|
wsdisplay_getc_dummy(dev_t dev)
|
|
{
|
|
/* panic? */
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
wsdisplay_pollc(dev_t dev, int on)
|
|
{
|
|
|
|
wsdisplay_cons_pollmode = on;
|
|
|
|
/* notify to fb drivers */
|
|
if (wsdisplay_console_device != NULL &&
|
|
wsdisplay_console_device->sc_accessops->pollc != NULL)
|
|
(*wsdisplay_console_device->sc_accessops->pollc)
|
|
(wsdisplay_console_device->sc_accesscookie, on);
|
|
|
|
/* notify to kbd drivers */
|
|
if (wsdisplay_cons_kbd_pollc)
|
|
(*wsdisplay_cons_kbd_pollc)(NODEV, on);
|
|
}
|
|
|
|
void
|
|
wsdisplay_set_cons_kbd(int (*get)(dev_t), void (*poll)(dev_t, int),
|
|
void (*bell)(dev_t, u_int, u_int, u_int))
|
|
{
|
|
wsdisplay_cons.cn_getc = get;
|
|
wsdisplay_cons.cn_bell = bell;
|
|
wsdisplay_cons_kbd_pollc = poll;
|
|
}
|
|
|
|
void
|
|
wsdisplay_unset_cons_kbd(void)
|
|
{
|
|
wsdisplay_cons.cn_getc = wsdisplay_getc_dummy;
|
|
wsdisplay_cons.cn_bell = NULL;
|
|
wsdisplay_cons_kbd_pollc = 0;
|
|
}
|
|
|
|
/*
|
|
* Switch the console display to it's first screen.
|
|
*/
|
|
void
|
|
wsdisplay_switchtoconsole(void)
|
|
{
|
|
struct wsdisplay_softc *sc;
|
|
struct wsscreen *scr;
|
|
|
|
if (wsdisplay_console_device != NULL) {
|
|
sc = wsdisplay_console_device;
|
|
if ((scr = sc->sc_scr[0]) == NULL)
|
|
return;
|
|
(*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
|
|
scr->scr_dconf->emulcookie,
|
|
0, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Switch the console at shutdown.
|
|
*/
|
|
static void
|
|
wsdisplay_shutdownhook(void *arg)
|
|
{
|
|
|
|
wsdisplay_switchtoconsole();
|
|
}
|