4 * Copyright (c) 1998 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
7 * This code is derived from software contributed to The DragonFly Project
8 * by Sascha Wildner <saw@online.de>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer as
15 * the first lines of this file unmodified.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * $FreeBSD: src/sys/dev/syscons/scvidctl.c,v 1.19.2.2 2000/05/05 09:16:08 nyan Exp $
32 * $DragonFly: src/sys/dev/misc/syscons/scvidctl.c,v 1.16 2007/08/19 11:39:11 swildner Exp $
35 #include "opt_syscons.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
40 #include <sys/signalvar.h>
42 #include <sys/kernel.h>
43 #include <sys/thread2.h>
45 #include <machine/console.h>
47 #include <dev/video/fb/fbreg.h>
50 SET_DECLARE(scrndr_set, const sc_renderer_t);
53 sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize,
62 lwkt_gettoken(&tty_token);
63 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, mode, &info)) {
64 lwkt_reltoken(&tty_token);
67 lwkt_reltoken(&tty_token);
69 /* adjust argument values */
71 fontsize = info.vi_cheight;
74 #ifndef SC_NO_FONT_LOADING
75 if (!(scp->sc->fonts_loaded & FONT_8))
77 font = scp->sc->font_8;
81 } else if (fontsize >= 16) {
83 #ifndef SC_NO_FONT_LOADING
84 if (!(scp->sc->fonts_loaded & FONT_16))
86 font = scp->sc->font_16;
92 #ifndef SC_NO_FONT_LOADING
93 if (!(scp->sc->fonts_loaded & FONT_14))
95 font = scp->sc->font_14;
100 if ((xsize <= 0) || (xsize > info.vi_width))
101 xsize = info.vi_width;
102 if ((ysize <= 0) || (ysize > info.vi_height))
103 ysize = info.vi_height;
105 /* stop screen saver, etc */
107 if ((error = sc_clean_up(scp))) {
112 if (sc_render_match(scp, scp->sc->adp->va_name, V_INFO_MM_TEXT) == NULL) {
119 #ifndef SC_NO_HISTORY
120 if (scp->history != NULL) {
122 new_ysize = sc_vtb_rows(scp->history);
125 prev_ysize = scp->ysize;
127 * This is a kludge to fend off scrn_update() while we
128 * muck around with scp. XXX
130 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN;
131 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE | MOUSE_VISIBLE);
133 scp->model = V_INFO_MM_TEXT;
138 scp->xpixel = scp->xsize*8;
139 scp->ypixel = scp->ysize*fontsize;
141 scp->font_size = fontsize;
143 /* allocate buffers */
144 sc_alloc_scr_buffer(scp, TRUE, TRUE);
145 sc_init_emulator(scp, NULL);
146 #ifndef SC_NO_CUTPASTE
147 sc_alloc_cut_buffer(scp, FALSE);
149 #ifndef SC_NO_HISTORY
150 sc_alloc_history_buffer(scp, new_ysize, prev_ysize, FALSE);
154 if (scp == scp->sc->cur_scp)
156 scp->status &= ~UNKNOWN_MODE;
160 DPRINTF(5, ("ws_*size (%d,%d), size (%d,%d)\n",
161 tp->t_winsize.ws_col, tp->t_winsize.ws_row, scp->xsize, scp->ysize));
162 if (tp->t_winsize.ws_col != scp->xsize
163 || tp->t_winsize.ws_row != scp->ysize) {
164 tp->t_winsize.ws_col = scp->xsize;
165 tp->t_winsize.ws_row = scp->ysize;
166 pgsignal(tp->t_pgrp, SIGWINCH, 1);
173 sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode)
175 #ifdef SC_NO_MODE_CHANGE
181 lwkt_gettoken(&tty_token);
182 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, mode, &info)) {
183 lwkt_reltoken(&tty_token);
186 lwkt_reltoken(&tty_token);
188 /* stop screen saver, etc */
190 if ((error = sc_clean_up(scp))) {
195 if (sc_render_match(scp, scp->sc->adp->va_name, V_INFO_MM_OTHER) == NULL) {
201 scp->status |= (UNKNOWN_MODE | GRAPHICS_MODE | MOUSE_HIDDEN);
202 scp->status &= ~(PIXEL_MODE | MOUSE_VISIBLE);
204 scp->model = V_INFO_MM_OTHER;
206 * Don't change xsize and ysize; preserve the previous vty
207 * and history buffers.
211 scp->xpixel = info.vi_width;
212 scp->ypixel = info.vi_height;
215 #ifndef SC_NO_SYSMOUSE
216 /* move the mouse cursor at the center of the screen */
217 sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2);
219 sc_init_emulator(scp, NULL);
222 if (scp == scp->sc->cur_scp)
224 /* clear_graphics();*/
225 refresh_ega_palette(scp);
226 scp->status &= ~UNKNOWN_MODE;
230 if (tp->t_winsize.ws_xpixel != scp->xpixel
231 || tp->t_winsize.ws_ypixel != scp->ypixel) {
232 tp->t_winsize.ws_xpixel = scp->xpixel;
233 tp->t_winsize.ws_ypixel = scp->ypixel;
234 pgsignal(tp->t_pgrp, SIGWINCH, 1);
238 #endif /* SC_NO_MODE_CHANGE */
242 sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize,
245 #ifndef SC_PIXEL_MODE
254 lwkt_gettoken(&tty_token);
255 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info)) {
256 lwkt_reltoken(&tty_token);
257 return ENODEV; /* this shouldn't happen */
260 /* adjust argument values */
262 fontsize = info.vi_cheight;
265 #ifndef SC_NO_FONT_LOADING
266 if (!(scp->sc->fonts_loaded & FONT_8))
268 font = scp->sc->font_8;
272 } else if (fontsize >= 16) {
274 #ifndef SC_NO_FONT_LOADING
275 if (!(scp->sc->fonts_loaded & FONT_16))
277 font = scp->sc->font_16;
283 #ifndef SC_NO_FONT_LOADING
284 if (!(scp->sc->fonts_loaded & FONT_14))
286 font = scp->sc->font_14;
292 xsize = info.vi_width/8;
294 ysize = info.vi_height/fontsize;
296 if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize))
300 * We currently support the following graphic modes:
302 * - 4 bpp planar modes whose memory size does not exceed 64K
303 * - 8 bbp packed pixel modes
304 * - 15, 16, 24 and 32 bpp direct modes with linear frame buffer
307 if (info.vi_mem_model == V_INFO_MM_PLANAR) {
308 if (info.vi_planes != 4)
312 * A memory size >64K requires bank switching to access the entire
316 if (info.vi_width * info.vi_height / 8 > info.vi_window_size)
318 } else if (info.vi_mem_model == V_INFO_MM_PACKED) {
319 if (info.vi_depth != 8)
321 } else if (info.vi_mem_model == V_INFO_MM_DIRECT) {
322 if (!(info.vi_flags & V_INFO_LINEAR) &&
323 (info.vi_depth != 15) && (info.vi_depth != 16) &&
324 (info.vi_depth != 24) && (info.vi_depth != 32))
329 /* stop screen saver, etc */
331 if ((error = sc_clean_up(scp))) {
336 if (sc_render_match(scp, scp->sc->adp->va_name, info.vi_mem_model) == NULL) {
343 (*scp->tsw->te_term)(scp, scp->ts);
350 #ifndef SC_NO_HISTORY
351 if (scp->history != NULL) {
353 new_ysize = sc_vtb_rows(scp->history);
356 prev_ysize = scp->ysize;
357 scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN);
358 scp->status &= ~(GRAPHICS_MODE | MOUSE_VISIBLE);
359 scp->model = info.vi_mem_model;
362 scp->xoff = (scp->xpixel/8 - xsize)/2;
363 scp->yoff = (scp->ypixel/fontsize - ysize)/2;
365 scp->font_size = fontsize;
367 /* allocate buffers */
368 sc_alloc_scr_buffer(scp, TRUE, TRUE);
369 sc_init_emulator(scp, NULL);
370 #ifndef SC_NO_CUTPASTE
371 sc_alloc_cut_buffer(scp, FALSE);
373 #ifndef SC_NO_HISTORY
374 sc_alloc_history_buffer(scp, new_ysize, prev_ysize, FALSE);
378 if (scp == scp->sc->cur_scp) {
379 sc_set_border(scp, scp->border);
380 sc_set_cursor_image(scp);
383 scp->status &= ~UNKNOWN_MODE;
387 if (tp->t_winsize.ws_col != scp->xsize
388 || tp->t_winsize.ws_row != scp->ysize) {
389 tp->t_winsize.ws_col = scp->xsize;
390 tp->t_winsize.ws_row = scp->ysize;
391 pgsignal(tp->t_pgrp, SIGWINCH, 1);
395 #endif /* SC_PIXEL_MODE */
398 #define fb_ioctl(a, c, d) \
399 (((a) == NULL) ? ENODEV : \
400 (*vidsw[(a)->va_index]->ioctl)((a), (c), (caddr_t)(d)))
403 sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
406 video_adapter_t *adp;
412 scp = SC_STAT(tp->t_dev);
413 if (scp == NULL) /* tp == SC_MOUSE */
416 if (adp == NULL) /* shouldn't happen??? */
419 lwkt_gettoken(&tty_token);
422 case CONS_CURRENTADP: /* get current adapter index */
424 ret = fb_ioctl(adp, FBIO_ADAPTER, data);
425 lwkt_reltoken(&tty_token);
428 case CONS_CURRENT: /* get current adapter type */
430 ret = fb_ioctl(adp, FBIO_ADPTYPE, data);
431 lwkt_reltoken(&tty_token);
434 case CONS_ADPINFO: /* adapter information */
436 if (((video_adapter_info_t *)data)->va_index >= 0) {
437 adp = vid_get_adapter(((video_adapter_info_t *)data)->va_index);
439 lwkt_reltoken(&tty_token);
443 ret = fb_ioctl(adp, FBIO_ADPINFO, data);
444 lwkt_reltoken(&tty_token);
447 case CONS_GET: /* get current video mode */
449 *(int *)data = scp->mode;
450 lwkt_reltoken(&tty_token);
453 #ifndef SC_NO_MODE_CHANGE
455 case FBIO_SETMODE: /* set video mode */
456 if (!(adp->va_flags & V_ADP_MODECHANGE)) {
457 lwkt_reltoken(&tty_token);
460 info.vi_mode = *(int *)data;
461 error = fb_ioctl(adp, FBIO_MODEINFO, &info);
463 lwkt_reltoken(&tty_token);
466 if (info.vi_flags & V_INFO_GRAPHICS) {
467 lwkt_reltoken(&tty_token);
468 return sc_set_graphics_mode(scp, tp, *(int *)data);
470 lwkt_reltoken(&tty_token);
471 return sc_set_text_mode(scp, tp, *(int *)data, 0, 0, 0);
473 #endif /* SC_NO_MODE_CHANGE */
475 case CONS_MODEINFO: /* get mode information */
477 ret = fb_ioctl(adp, FBIO_MODEINFO, data);
478 lwkt_reltoken(&tty_token);
481 case CONS_FINDMODE: /* find a matching video mode */
483 ret = fb_ioctl(adp, FBIO_FINDMODE, data);
484 lwkt_reltoken(&tty_token);
487 case CONS_SETWINORG: /* set frame buffer window origin */
489 if (scp != scp->sc->cur_scp) {
490 lwkt_reltoken(&tty_token);
491 return ENODEV; /* XXX */
493 ret = fb_ioctl(adp, FBIO_SETWINORG, data);
494 lwkt_reltoken(&tty_token);
497 case FBIO_GETWINORG: /* get frame buffer window origin */
498 if (scp != scp->sc->cur_scp) {
499 lwkt_reltoken(&tty_token);
500 return ENODEV; /* XXX */
502 ret = fb_ioctl(adp, FBIO_GETWINORG, data);
503 lwkt_reltoken(&tty_token);
506 case FBIO_GETDISPSTART:
507 case FBIO_SETDISPSTART:
508 case FBIO_GETLINEWIDTH:
509 case FBIO_SETLINEWIDTH:
510 if (scp != scp->sc->cur_scp) {
511 lwkt_reltoken(&tty_token);
512 return ENODEV; /* XXX */
514 ret = fb_ioctl(adp, cmd, data);
515 lwkt_reltoken(&tty_token);
518 case FBIO_GETPALETTE:
519 case FBIO_SETPALETTE:
531 if (scp != scp->sc->cur_scp) {
532 lwkt_reltoken(&tty_token);
533 return ENODEV; /* XXX */
535 ret = fb_ioctl(adp, cmd, data);
536 lwkt_reltoken(&tty_token);
539 case KDSETMODE: /* set current mode of this (virtual) console */
540 switch (*(int *)data) {
541 case KD_TEXT: /* switch to TEXT (known) mode */
543 * If scp->mode is of graphics modes, we don't know which
544 * text mode to switch back to...
546 if (scp->status & GRAPHICS_MODE) {
547 lwkt_reltoken(&tty_token);
550 /* restore fonts & palette ! */
552 #ifndef SC_NO_FONT_LOADING
553 if (ISFONTAVAIL(adp->va_flags)
554 && !(scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
557 * Don't load fonts for now... XXX
559 if (scp->sc->fonts_loaded & FONT_8)
560 sc_load_font(scp, 0, 8, scp->sc->font_8, 0, 256);
561 if (scp->sc->fonts_loaded & FONT_14)
562 sc_load_font(scp, 0, 14, scp->sc->font_14, 0, 256);
563 if (scp->sc->fonts_loaded & FONT_16)
564 sc_load_font(scp, 0, 16, scp->sc->font_16, 0, 256);
566 #endif /* SC_NO_FONT_LOADING */
569 #ifndef SC_NO_PALETTE_LOADING
570 load_palette(adp, scp->sc->palette);
573 /* move hardware cursor out of the way */
574 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
577 case KD_TEXT1: /* switch to TEXT (known) mode */
579 * If scp->mode is of graphics modes, we don't know which
580 * text/pixel mode to switch back to...
582 if (scp->status & GRAPHICS_MODE) {
583 lwkt_reltoken(&tty_token);
587 if ((error = sc_clean_up(scp))) {
589 lwkt_reltoken(&tty_token);
592 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN;
594 /* no restore fonts & palette */
595 if (scp == scp->sc->cur_scp)
597 sc_clear_screen(scp);
598 scp->status &= ~UNKNOWN_MODE;
599 lwkt_reltoken(&tty_token);
603 case KD_PIXEL: /* pixel (raster) display */
604 if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) {
605 lwkt_reltoken(&tty_token);
608 if (scp->status & GRAPHICS_MODE) {
609 lwkt_reltoken(&tty_token);
610 return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize,
614 if ((error = sc_clean_up(scp))) {
616 lwkt_reltoken(&tty_token);
619 scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN);
621 if (scp == scp->sc->cur_scp) {
623 #ifndef SC_NO_PALETTE_LOADING
624 load_palette(adp, scp->sc->palette);
627 sc_clear_screen(scp);
628 scp->status &= ~UNKNOWN_MODE;
629 lwkt_reltoken(&tty_token);
631 #endif /* SC_PIXEL_MODE */
633 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */
635 if ((error = sc_clean_up(scp))) {
637 lwkt_reltoken(&tty_token);
640 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN;
642 lwkt_reltoken(&tty_token);
646 lwkt_reltoken(&tty_token);
652 case KDRASTER: /* set pixel (raster) display mode */
653 if (ISUNKNOWNSC(scp) || ISTEXTSC(scp)) {
654 lwkt_reltoken(&tty_token);
657 lwkt_reltoken(&tty_token);
658 return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1],
660 #endif /* SC_PIXEL_MODE */
662 case KDGETMODE: /* get current mode of this (virtual) console */
664 * From the user program's point of view, KD_PIXEL is the same
667 *data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT;
668 lwkt_reltoken(&tty_token);
671 case KDSBORDER: /* set border color of this (virtual) console */
673 if (scp == scp->sc->cur_scp)
674 sc_set_border(scp, scp->border);
675 lwkt_reltoken(&tty_token);
679 lwkt_reltoken(&tty_token);
683 static LIST_HEAD(, sc_renderer) sc_rndr_list =
684 LIST_HEAD_INITIALIZER(sc_rndr_list);
687 sc_render_add(sc_renderer_t *rndr)
689 LIST_INSERT_HEAD(&sc_rndr_list, rndr, link);
694 sc_render_remove(sc_renderer_t *rndr)
697 LIST_REMOVE(rndr, link);
699 return EBUSY; /* XXX */
703 sc_render_match(scr_stat *scp, char *name, int model)
705 const sc_renderer_t **list;
706 const sc_renderer_t *p;
708 if (!LIST_EMPTY(&sc_rndr_list)) {
709 LIST_FOREACH(p, &sc_rndr_list, link) {
710 if ((strcmp(p->name, name) == 0) &&
711 (model == p->model)) {
713 ~(VR_CURSOR_ON | VR_CURSOR_BLINK);
718 SET_FOREACH(list, scrndr_set) {
720 if ((strcmp(p->name, name) == 0) &&
721 (model == p->model)) {
723 ~(VR_CURSOR_ON | VR_CURSOR_BLINK);