wsdisplay.c revision 1.3 1 /* $NetBSD: wsdisplay.c,v 1.3 1998/04/07 13:43:17 hannken 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 static const char _copyright[] __attribute__ ((unused)) =
34 "Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.";
35 static const char _rcsid[] __attribute__ ((unused)) =
36 "$NetBSD: wsdisplay.c,v 1.3 1998/04/07 13:43:17 hannken Exp $";
37
38 #include <sys/param.h>
39 #include <sys/conf.h>
40 #include <sys/device.h>
41 #include <sys/ioctl.h>
42 #include <sys/kernel.h>
43 #include <sys/proc.h>
44 #include <sys/malloc.h>
45 #include <sys/syslog.h>
46 #include <sys/systm.h>
47 #include <sys/tty.h>
48 #include <sys/signalvar.h>
49 #include <sys/errno.h>
50 #include <sys/fcntl.h>
51
52 #include <dev/wscons/wsconsio.h>
53 #include <dev/wscons/wsdisplayvar.h>
54 #include <dev/wscons/wsemulvar.h>
55 #include <dev/wscons/wscons_callbacks.h>
56 #include <dev/cons.h>
57
58 struct wsdisplay_conf {
59 const struct wsdisplay_emulops *emulops;
60 void *emulcookie;
61
62 const struct wsscreen_descr *scrdata;
63
64 const struct wsemul_ops *wsemul;
65 void *wsemulcookie;
66 };
67
68 struct wsscreen {
69 struct wsdisplay_conf *scr_dconf;
70
71 struct tty *scr_tty;
72 int scr_open; /* is it open? */
73 int scr_graphics; /* graphics mode? */
74 int scr_hold_screen; /* hold tty output */
75
76 struct wsdisplay_softc *sc;
77 };
78
79 struct wsscreen *wsscreen_attach __P((struct wsdisplay_softc *, int,
80 const char *,
81 const struct wsscreen_descr *, void *,
82 int, int));
83
84 #define WSDISPLAY_MAXSCREEN 8
85
86 struct wsdisplay_softc {
87 struct device sc_dv;
88
89 const struct wsdisplay_accessops *sc_accessops;
90 void *sc_accesscookie;
91
92 struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN];
93 struct wsscreen *sc_focus;
94
95 int sc_isconsole;
96 struct device *sc_kbddv;
97 };
98
99 extern struct cfdriver wsdisplay_cd;
100
101 /* Autoconfiguration definitions. */
102 #ifdef __BROKEN_INDIRECT_CONFIG
103 static int wsdisplay_emul_match __P((struct device *, void *, void *));
104 #else
105 static int wsdisplay_emul_match __P((struct device *, struct cfdata *,
106 void *));
107 #endif
108 static void wsdisplay_emul_attach __P((struct device *, struct device *,
109 void *));
110 #ifdef __BROKEN_INDIRECT_CONFIG
111 static int wsdisplay_noemul_match __P((struct device *, void *, void *));
112 #else
113 static int wsdisplay_noemul_match __P((struct device *, struct cfdata *,
114 void *));
115 #endif
116 static void wsdisplay_noemul_attach __P((struct device *, struct device *,
117 void *));
118
119 struct cfattach wsdisplay_emul_ca = {
120 sizeof (struct wsdisplay_softc),
121 wsdisplay_emul_match,
122 wsdisplay_emul_attach,
123 };
124
125 struct cfattach wsdisplay_noemul_ca = {
126 sizeof (struct wsdisplay_softc),
127 wsdisplay_noemul_match,
128 wsdisplay_noemul_attach,
129 };
130
131 /* Exported tty- and cdevsw-related functions. */
132 cdev_decl(wsdisplay);
133
134 static void wsdisplaystart __P((struct tty *));
135 static int wsdisplayparam __P((struct tty *, struct termios *));
136
137
138 /* Internal macros, functions, and variables. */
139 #define SET(t, f) (t) |= (f)
140 #define CLR(t, f) (t) &= ~(f)
141 #define ISSET(t, f) ((t) & (f))
142
143 #define WSDISPLAYUNIT(dev) (minor(dev) >> 8)
144 #define WSDISPLAYSCREEN(dev) (minor(dev) & 0xff)
145 #define WSDISPLAYBURST (OBUFSIZ - 1)
146
147 #define WSSCREEN_HAS_EMULATOR(scr) ((scr)->scr_dconf->emulops != NULL)
148 #define WSSCREEN_GRAPHICS_MODE(scr) \
149 (WSSCREEN_HAS_EMULATOR(scr) && (scr)->scr_graphics != 0)
150
151 static void wsdisplay_common_attach __P((struct wsdisplay_softc *sc,
152 int console, struct wsscreen_list *,
153 const struct wsdisplay_accessops *accessops,
154 void *accesscookie));
155
156 static int wsdisplay_internal_ioctl __P((struct wsdisplay_softc *sc,
157 struct wsscreen *,
158 u_long cmd, caddr_t data,
159 int flag, struct proc *p));
160
161 static int wsdisplay_console_initted;
162 static struct wsdisplay_softc *wsdisplay_console_device;
163 static struct wsdisplay_conf wsdisplay_console_conf;
164
165 static int wsdisplay_getc_dummy __P((dev_t));
166 static void wsdisplay_pollc_dummy __P((dev_t, int));
167
168 static struct consdev wsdisplay_cons = {
169 NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc,
170 wsdisplay_pollc_dummy, NODEV, CN_NORMAL
171 };
172
173 struct wsscreen *wsscreen_attach(sc, console, emul, type, cookie, ccol, crow)
174 struct wsdisplay_softc *sc;
175 int console;
176 const char *emul;
177 const struct wsscreen_descr *type;
178 void *cookie;
179 int ccol, crow;
180 {
181 struct wsdisplay_conf *dconf;
182 struct wsscreen *scr;
183
184 scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_WAITOK);
185 if (!scr)
186 return (NULL);
187
188 if (console) {
189 dconf = &wsdisplay_console_conf;
190 /*
191 * If there's an emulation, tell it about the callback argument.
192 * The other stuff is already there.
193 */
194 if (dconf->wsemul != NULL)
195 (*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr);
196 } else { /* not console */
197 dconf = malloc(sizeof(struct wsdisplay_conf),
198 M_DEVBUF, M_NOWAIT);
199 dconf->emulops = type->textops;
200 dconf->emulcookie = cookie;
201 if (dconf->emulops) {
202 dconf->wsemul = wsemul_pick(emul);
203 dconf->wsemulcookie =
204 (*dconf->wsemul->attach)(0, type, cookie,
205 ccol, crow, scr);
206 } else
207 dconf->wsemul = NULL;
208 dconf->scrdata = type;
209 }
210
211 scr->scr_dconf = dconf;
212
213 /*
214 * we allocate a tty even for those devices that don't have
215 * emulators, so that e.g. 'getty' can be safely run on the
216 * devices, and so that the interface provided by all wsdisplay
217 * devices is uniform. This is a bit of a hack.
218 */
219 scr->scr_tty = ttymalloc();
220 tty_attach(scr->scr_tty);
221
222 scr->scr_open = 0;
223 #if 0
224 scr->scr_graphics =
225 type->textops ? WSDISPLAYIO_MODE_EMUL : WSDISPLAYIO_MODE_MAPPED;
226 #else /* XXX again, for getty */
227 scr->scr_graphics = WSDISPLAYIO_MODE_EMUL;
228 #endif
229 scr->scr_hold_screen = 0;
230 scr->sc = sc;
231 return (scr);
232 }
233
234 /*
235 * Autoconfiguration functions.
236 */
237 int
238 #ifdef __BROKEN_INDIRECT_CONFIG
239 wsdisplay_emul_match(parent, matchv, aux)
240 #else
241 wsdisplay_emul_match(parent, match, aux)
242 #endif
243 struct device *parent;
244 #ifdef __BROKEN_INDIRECT_CONFIG
245 void *matchv;
246 #else
247 struct cfdata *match;
248 #endif
249 void *aux;
250 {
251 #ifdef __BROKEN_INDIRECT_CONFIG
252 struct cfdata *match = matchv;
253 #endif
254 struct wsemuldisplaydev_attach_args *ap = aux;
255
256 if (match->wsemuldisplaydevcf_console !=
257 WSEMULDISPLAYDEVCF_CONSOLE_UNK) {
258 /*
259 * If console-ness of device specified, either match
260 * exactly (at high priority), or fail.
261 */
262 if (match->wsemuldisplaydevcf_console != 0 &&
263 ap->console != 0)
264 return (10);
265 else
266 return (0);
267 }
268
269 /* If console-ness unspecified, it wins. */
270 return (1);
271 }
272
273 void
274 wsdisplay_emul_attach(parent, self, aux)
275 struct device *parent, *self;
276 void *aux;
277 {
278 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
279 struct wsemuldisplaydev_attach_args *ap = aux;
280
281 wsdisplay_common_attach(sc, ap->console, ap->scrdata,
282 ap->accessops, ap->accesscookie);
283
284 if (ap->console) {
285 int maj;
286
287 /* locate the major number */
288 for (maj = 0; maj < nchrdev; maj++)
289 if (cdevsw[maj].d_open == wsdisplayopen)
290 break;
291
292 cn_tab->cn_dev = makedev(maj, self->dv_unit);
293 }
294 }
295
296 /* Print function (for parent devices). */
297 int
298 wsemuldisplaydevprint(aux, pnp)
299 void *aux;
300 const char *pnp;
301 {
302 #if 0 /* -Wunused */
303 struct wsemuldisplaydev_attach_args *ap = aux;
304 #endif
305
306 if (pnp)
307 printf("wsdisplay at %s", pnp);
308 #if 0 /* don't bother; it's ugly */
309 printf(" console %d", ap->console);
310 #endif
311
312 return (UNCONF);
313 }
314
315 int
316 wsdisplay_noemul_match(parent, match, aux)
317 struct device *parent;
318 #ifdef __BROKEN_INDIRECT_CONFIG
319 void *match;
320 #else
321 struct cfdata *match;
322 #endif
323 void *aux;
324 {
325 #if 0 /* -Wunused */
326 struct wsdisplaydev_attach_args *ap = aux;
327 #endif
328
329 /* Always match. */
330 return (1);
331 }
332
333 void
334 wsdisplay_noemul_attach(parent, self, aux)
335 struct device *parent, *self;
336 void *aux;
337 {
338 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
339 struct wsdisplaydev_attach_args *ap = aux;
340
341 wsdisplay_common_attach(sc, 0, NULL, ap->accessops, ap->accesscookie);
342 }
343
344 /* Print function (for parent devices). */
345 int
346 wsdisplaydevprint(aux, pnp)
347 void *aux;
348 const char *pnp;
349 {
350 #if 0 /* -Wunused */
351 struct wsdisplaydev_attach_args *ap = aux;
352 #endif
353
354 if (pnp)
355 printf("wsdisplay at %s", pnp);
356
357 return (UNCONF);
358 }
359
360 static void
361 wsdisplay_common_attach(sc, console, scrdata, accessops, accesscookie)
362 struct wsdisplay_softc *sc;
363 int console;
364 struct wsscreen_list *scrdata;
365 const struct wsdisplay_accessops *accessops;
366 void *accesscookie;
367 {
368 const struct wsscreen_descr *scr;
369 int res, i = 0;
370
371 if (console) {
372 KASSERT(wsdisplay_console_initted);
373 KASSERT(wsdisplay_console_device == NULL);
374
375 sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0);
376 wsdisplay_console_device = sc;
377
378 printf(": console (%s, %s emulation)",
379 wsdisplay_console_conf.scrdata->name,
380 wsdisplay_console_conf.wsemul->name);
381
382 i++;
383 }
384
385 printf("\n");
386
387 #if 1 /* XXX do this in ioctl() - user selects screen type and emulation */
388 KASSERT(scrdata->nscreens > 0);
389 scr = scrdata->screens[0];
390
391 for (; i < WSDISPLAY_MAXSCREEN; i++) {
392 void *cookie;
393 int ccol, crow;
394
395 res = ((*accessops->alloc_screen)(accesscookie, scr,
396 &cookie, &ccol, &crow));
397 if (res)
398 break;
399
400 sc->sc_scr[i] = wsscreen_attach(sc, 0, 0, scr, cookie,
401 ccol, crow);
402 }
403 #endif
404
405 sc->sc_focus = sc->sc_scr[0];
406
407 sc->sc_accessops = accessops;
408 sc->sc_accesscookie = accesscookie;
409
410 sc->sc_isconsole = console;
411 sc->sc_kbddv = NULL;
412
413 wscons_glue_set_callback();
414 }
415
416 void
417 wsdisplay_cnattach(type, cookie, ccol, crow)
418 const struct wsscreen_descr *type;
419 void *cookie;
420 int ccol, crow;
421 {
422 const struct wsemul_ops *wsemul;
423
424 KASSERT(!wsdisplay_console_initted);
425 KASSERT(type->nrows > 0);
426 KASSERT(type->ncols > 0);
427 KASSERT(crow < type->nrows);
428 KASSERT(ccol < type->ncols);
429
430 wsdisplay_console_conf.emulops = type->textops;
431 wsdisplay_console_conf.emulcookie = cookie;
432 wsdisplay_console_conf.scrdata = type;
433
434 wsemul = wsemul_pick(0); /* default */
435 wsdisplay_console_conf.wsemul = wsemul;
436 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
437 ccol, crow);
438
439 cn_tab = &wsdisplay_cons;
440
441 wsdisplay_console_initted = 1;
442 }
443
444 /*
445 * Tty and cdevsw functions.
446 */
447 int
448 wsdisplayopen(dev, flag, mode, p)
449 dev_t dev;
450 int flag, mode;
451 struct proc *p;
452 {
453 struct wsdisplay_softc *sc;
454 struct tty *tp;
455 int unit, newopen, error;
456 struct wsscreen *scr;
457
458 unit = WSDISPLAYUNIT(dev);
459 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
460 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
461 return (ENXIO);
462
463 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
464 if (!scr)
465 return (ENXIO);
466
467 tp = scr->scr_tty;
468 tp->t_oproc = wsdisplaystart;
469 tp->t_param = wsdisplayparam;
470 tp->t_dev = dev;
471 newopen = (tp->t_state & TS_ISOPEN) == 0;
472 if (newopen) {
473 ttychars(tp);
474 tp->t_iflag = TTYDEF_IFLAG;
475 tp->t_oflag = TTYDEF_OFLAG;
476 tp->t_cflag = TTYDEF_CFLAG;
477 tp->t_lflag = TTYDEF_LFLAG;
478 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
479 wsdisplayparam(tp, &tp->t_termios);
480 ttsetwater(tp);
481 } else if ((tp->t_state & TS_XCLUDE) != 0 && p->p_ucred->cr_uid != 0)
482 return EBUSY;
483 tp->t_state |= TS_CARR_ON;
484
485 error = ((*linesw[tp->t_line].l_open)(dev, tp));
486 if (newopen && (error == 0)) {
487 scr->scr_open = 1;
488
489 /* set window sizes as appropriate, and reset the emulation */
490 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows;
491 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols;
492
493 /* wsdisplay_set_emulation() */
494 }
495 return (error);
496 }
497
498 int
499 wsdisplayclose(dev, flag, mode, p)
500 dev_t dev;
501 int flag, mode;
502 struct proc *p;
503 {
504 struct wsdisplay_softc *sc;
505 struct tty *tp;
506 int unit;
507 struct wsscreen *scr;
508
509 unit = WSDISPLAYUNIT(dev);
510 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
511 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
512 return (ENXIO);
513
514 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
515
516 if (WSSCREEN_HAS_EMULATOR(scr)) {
517 if (scr->scr_hold_screen) {
518 int s;
519
520 /* XXX RESET KEYBOARD LEDS, etc. */
521 s = spltty(); /* avoid conflict with keyboard */
522 wsdisplay_kbdholdscreen((struct device *)sc, 0);
523 splx(s);
524 }
525 tp = scr->scr_tty;
526 (*linesw[tp->t_line].l_close)(tp, flag);
527 ttyclose(tp);
528 }
529 /* XXX RESET EMULATOR? */
530 #if 0
531 scr->scr_graphics =
532 wsemul ? WSDISPLAYIO_MODE_EMUL : WSDISPLAYIO_MODE_MAPPED;
533 #else /* XXX for getty */
534 scr->scr_graphics = WSDISPLAYIO_MODE_EMUL;
535 #endif
536 if (sc->sc_kbddv != NULL)
537 wskbd_set_translation(sc->sc_kbddv,
538 scr->scr_graphics == WSDISPLAYIO_MODE_EMUL);
539 scr->scr_open = 0;
540
541 return (0);
542 }
543
544 int
545 wsdisplayread(dev, uio, flag)
546 dev_t dev;
547 struct uio *uio;
548 int flag;
549 {
550 struct wsdisplay_softc *sc;
551 struct tty *tp;
552 int unit;
553 struct wsscreen *scr;
554
555 unit = WSDISPLAYUNIT(dev);
556 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
557 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
558 return (ENXIO);
559
560 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
561
562 if (WSSCREEN_GRAPHICS_MODE(scr))
563 return (ENODEV);
564
565 tp = scr->scr_tty;
566 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
567 }
568
569 int
570 wsdisplaywrite(dev, uio, flag)
571 dev_t dev;
572 struct uio *uio;
573 int flag;
574 {
575 struct wsdisplay_softc *sc;
576 struct tty *tp;
577 int unit;
578 struct wsscreen *scr;
579
580 unit = WSDISPLAYUNIT(dev);
581 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
582 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
583 return (ENXIO);
584
585 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
586
587 if (WSSCREEN_GRAPHICS_MODE(scr))
588 return (ENODEV);
589
590 tp = scr->scr_tty;
591 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
592 }
593
594 struct tty *
595 wsdisplaytty(dev)
596 dev_t dev;
597 {
598 struct wsdisplay_softc *sc;
599 int unit;
600 struct wsscreen *scr;
601
602 unit = WSDISPLAYUNIT(dev);
603 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
604 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
605 return (NULL);
606
607 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
608
609 return (scr->scr_tty);
610 }
611
612 int
613 wsdisplayioctl(dev, cmd, data, flag, p)
614 dev_t dev;
615 u_long cmd;
616 caddr_t data;
617 int flag;
618 struct proc *p;
619 {
620 struct wsdisplay_softc *sc;
621 struct tty *tp;
622 int unit, error;
623 struct wsscreen *scr;
624
625 unit = WSDISPLAYUNIT(dev);
626 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
627 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
628 return (ENXIO);
629
630 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
631
632 if (!WSSCREEN_GRAPHICS_MODE(scr)) {
633 tp = scr->scr_tty;
634
635 /* printf("disc\n"); */
636 /* do the line discipline ioctls first */
637 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
638 if (error >= 0)
639 return error;
640
641 /* printf("tty\n"); */
642 /* then the tty ioctls */
643 error = ttioctl(tp, cmd, data, flag, p);
644 if (error >= 0)
645 return error;
646 }
647
648 error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p);
649 return (error != -1 ? error : ENOTTY);
650 }
651
652 int
653 wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p)
654 struct wsdisplay_softc *sc;
655 struct wsscreen *scr;
656 u_long cmd;
657 caddr_t data;
658 int flag;
659 struct proc *p;
660 {
661 int error, flush;
662 void *buf;
663
664 if (!WSSCREEN_GRAPHICS_MODE(scr) && sc->sc_kbddv != NULL) {
665 /* check ioctls for keyboard */
666 /* printf("kbdcallback\n"); */
667 error = wskbd_displayioctl(sc->sc_kbddv, cmd, data, flag, p);
668 if (error >= 0)
669 return error;
670 }
671
672 /* printf("display\n"); */
673 switch (cmd) {
674 case WSDISPLAYIO_GMODE:
675 *(u_int *)data = scr->scr_graphics;
676 return (0);
677
678 case WSDISPLAYIO_SMODE:
679 if (*(u_int *)data != WSDISPLAYIO_MODE_EMUL &&
680 *(u_int *)data != WSDISPLAYIO_MODE_MAPPED)
681 return (EINVAL);
682 flush = (scr->scr_graphics != *(u_int *)data);
683 scr->scr_graphics = *(u_int *)data;
684 if (sc->sc_kbddv != NULL)
685 wskbd_set_translation(sc->sc_kbddv,
686 scr->scr_graphics == WSDISPLAYIO_MODE_EMUL);
687 if (flush)
688 ttyflush(scr->scr_tty, FREAD | FWRITE);
689 return (0);
690
691 case WSDISPLAYIO_SFONT:
692 #define d ((struct wsdisplay_font *)data)
693 if (d->fontheight != scr->scr_dconf->scrdata->fontheight ||
694 d->fontwidth != scr->scr_dconf->scrdata->fontwidth)
695 return (EINVAL);
696 buf = malloc(d->fontheight * d->stride * d->numchars,
697 M_DEVBUF, M_WAITOK);
698 error = copyin(d->data, buf,
699 d->fontheight * d->stride * d->numchars);
700 if (error) {
701 free(buf, M_DEVBUF);
702 return (error);
703 }
704 error =
705 (*sc->sc_accessops->load_font)(sc->sc_accesscookie,
706 scr->scr_dconf->emulcookie,
707 d->firstchar, d->numchars,
708 d->stride, buf);
709 free(buf, M_DEVBUF);
710 #undef d
711 return (error);
712 }
713
714 /* check ioctls for display */
715 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
716 flag, p));
717 }
718
719 int
720 wsdisplaymmap(dev, offset, prot)
721 dev_t dev;
722 int offset; /* XXX */
723 int prot;
724 {
725 struct wsdisplay_softc *sc;
726 int unit;
727
728 unit = WSDISPLAYUNIT(dev);
729 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
730 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
731 return (ENXIO);
732 #if 0
733 if (!WSDISPLAY_GRAPHICS_MODE(sc) && 0)
734 return (-1);
735 #endif
736 /* pass mmap to display */
737 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot));
738 }
739
740 int
741 wsdisplaypoll(dev, events, p)
742 dev_t dev;
743 int events;
744 struct proc *p;
745 {
746 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[minor(dev)];
747 struct wsscreen *scr;
748
749 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
750
751 if (WSSCREEN_GRAPHICS_MODE(scr))
752 return (0);
753 else
754 return (ttpoll(dev, events, p));
755 }
756
757 void
758 wsdisplaystart(tp)
759 register struct tty *tp;
760 {
761 struct wsdisplay_softc *sc;
762 struct wsscreen *scr;
763 register int s, n;
764 u_char buf[WSDISPLAYBURST];
765
766 s = spltty();
767 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
768 splx(s);
769 return;
770 }
771 sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(tp->t_dev)];
772 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)];
773 if (scr->scr_hold_screen) {
774 tp->t_state |= TS_TIMEOUT;
775 splx(s);
776 return;
777 }
778 tp->t_state |= TS_BUSY;
779 splx(s);
780
781 n = q_to_b(&tp->t_outq, buf, sizeof(buf));
782
783 if (WSSCREEN_HAS_EMULATOR(scr))
784 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
785 buf, n);
786
787 s = spltty();
788 tp->t_state &= ~TS_BUSY;
789 /* Come back if there's more to do */
790 if (tp->t_outq.c_cc) {
791 tp->t_state |= TS_TIMEOUT;
792 timeout(ttrstrt, tp, (hz > 128) ? (hz / 128) : 1);
793 }
794 if (tp->t_outq.c_cc <= tp->t_lowat) {
795 if (tp->t_state&TS_ASLEEP) {
796 tp->t_state &= ~TS_ASLEEP;
797 wakeup((caddr_t)&tp->t_outq);
798 }
799 selwakeup(&tp->t_wsel);
800 }
801 splx(s);
802 }
803
804 void
805 wsdisplaystop(tp, flag)
806 struct tty *tp;
807 int flag;
808 {
809 int s;
810
811 s = spltty();
812 if (ISSET(tp->t_state, TS_BUSY))
813 if (!ISSET(tp->t_state, TS_TTSTOP))
814 SET(tp->t_state, TS_FLUSH);
815 splx(s);
816 }
817
818 /* Set line parameters. */
819 int
820 wsdisplayparam(tp, t)
821 struct tty *tp;
822 struct termios *t;
823 {
824
825 tp->t_ispeed = t->c_ispeed;
826 tp->t_ospeed = t->c_ospeed;
827 tp->t_cflag = t->c_cflag;
828 return 0;
829 }
830
831 /*
832 * Callbacks for the emulation code.
833 */
834 void
835 wsdisplay_emulbell(v)
836 void *v;
837 {
838 struct wsscreen *scr = v;
839
840 if (scr == NULL) /* console, before real attach */
841 return;
842
843 if (WSSCREEN_GRAPHICS_MODE(scr)) /* can this happen? */
844 return;
845
846 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL,
847 FWRITE, NULL);
848 }
849
850 void
851 wsdisplay_emulinput(v, data, count)
852 void *v;
853 const u_char *data;
854 u_int count;
855 {
856 struct wsscreen *scr = v;
857 struct tty *tp;
858
859 if (v == NULL) /* console, before real attach */
860 return;
861
862 if (WSSCREEN_GRAPHICS_MODE(scr)) /* XXX can't happen */
863 return;
864
865 tp = scr->scr_tty;
866 while (count-- > 0)
867 (*linesw[tp->t_line].l_rint)(*data++, tp);
868 };
869
870 /*
871 * Calls from the keyboard interface.
872 */
873 void
874 wsdisplay_kbdinput(dev, data, count)
875 struct device *dev;
876 const u_char *data;
877 u_int count;
878 {
879 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
880 struct wsscreen *scr;
881 struct tty *tp;
882
883 KASSERT(sc != NULL);
884 scr = sc->sc_focus;
885
886 KASSERT(scr != NULL);
887
888 if (WSSCREEN_GRAPHICS_MODE(scr))
889 return;
890
891 tp = scr->scr_tty;
892 while (count-- > 0)
893 (*linesw[tp->t_line].l_rint)(*data++, tp);
894 }
895
896 int
897 wsdisplay_switch(dev, no)
898 struct device *dev;
899 int no;
900 {
901 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
902 struct wsscreen *ws;
903 int s;
904
905 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
906 return (ENXIO);
907
908 ws = sc->sc_scr[no];
909 if (!ws)
910 return (ENXIO);
911
912 s = spltty();
913
914 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
915 ws->scr_dconf->emulcookie);
916 sc->sc_focus = ws;
917 /* keyboard state??? */
918
919 splx(s);
920
921 return (0);
922 }
923
924 void
925 wsdisplay_kbdholdscreen(dev, hold)
926 struct device *dev;
927 int hold;
928 {
929 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
930 struct wsscreen *scr;
931
932 scr = sc->sc_focus;
933
934 if (hold)
935 scr->scr_hold_screen = 1;
936 else {
937 scr->scr_hold_screen = 0;
938 timeout(ttrstrt, scr->scr_tty, 0); /* "immediate" */
939 }
940 }
941
942 /*
943 * Calls from the glue code.
944 */
945 int
946 wsdisplay_is_console(dv)
947 struct device *dv;
948 {
949 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
950
951 KASSERT(sc != NULL);
952 return (sc->sc_isconsole);
953 }
954
955 int
956 wsdisplay_has_emulator(dv)
957 struct device *dv;
958 {
959 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
960 struct wsscreen *scr;
961
962 scr = sc->sc_focus; /* ??? */
963
964 KASSERT(sc != NULL);
965 KASSERT(scr != NULL);
966 return (WSSCREEN_HAS_EMULATOR(scr)); /* XXX XXX */
967 }
968
969 struct device *
970 wsdisplay_kbd(dv)
971 struct device *dv;
972 {
973 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
974
975 KASSERT(sc != NULL);
976 return (sc->sc_kbddv);
977 }
978
979 void
980 wsdisplay_set_kbd(dv, kbddv)
981 struct device *dv, *kbddv;
982 {
983 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
984
985 KASSERT(sc != NULL);
986 sc->sc_kbddv = kbddv;
987 }
988
989 /*
990 * Console interface.
991 */
992 void
993 wsdisplay_cnputc(dev, i)
994 dev_t dev;
995 int i;
996 {
997 struct wsdisplay_conf *dc;
998 char c = i;
999
1000 if (!wsdisplay_console_initted)
1001 return;
1002
1003 if (wsdisplay_console_device != NULL &&
1004 WSSCREEN_GRAPHICS_MODE(wsdisplay_console_device->sc_scr[0]))
1005 return;
1006
1007 dc = &wsdisplay_console_conf;
1008 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1);
1009 }
1010
1011 static int
1012 wsdisplay_getc_dummy(dev)
1013 dev_t dev;
1014 {
1015 /* panic? */
1016 return (0);
1017 }
1018
1019 static void
1020 wsdisplay_pollc_dummy(dev, on)
1021 dev_t dev;
1022 int on;
1023 {
1024 }
1025
1026 void
1027 wsdisplay_set_cons_kbd(get, poll)
1028 int (*get) __P((dev_t));
1029 void (*poll) __P((dev_t, int));
1030 {
1031 wsdisplay_cons.cn_getc = get;
1032 wsdisplay_cons.cn_pollc = poll;
1033 }
1034