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