2 * Copyright (c) 1991-1997 Søren Schmidt
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
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. The name of the author may not be used to endorse or promote products
15 * derived from this software withough specific prior written permission
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * $FreeBSD: src/lib/libvgl/main.c,v 1.6.2.2 2001/07/30 14:31:30 yokota Exp $
29 * $DragonFly: src/lib/libvgl/main.c,v 1.4 2008/09/30 16:57:06 swildner Exp $
33 #include <sys/types.h>
34 #include <sys/signal.h>
36 #include <sys/ioctl.h>
38 #include <machine/console.h>
41 #define min(x, y) (((x) < (y)) ? (x) : (y))
42 #define max(x, y) (((x) > (y)) ? (x) : (y))
44 VGLBitmap
*VGLDisplay
;
45 video_info_t VGLModeInfo
;
46 video_adapter_info_t VGLAdpInfo
;
50 static int VGLOldMode
;
51 static size_t VGLBufSize
;
52 static byte
*VGLMem
= MAP_FAILED
;
53 static int VGLSwitchPending
;
54 static int VGLAbortPending
;
55 static int VGLOnDisplay
;
56 static unsigned int VGLCurWindow
;
57 static int VGLInitDone
= 0;
58 static struct winsize VGLOldWSize
;
71 signal(SIGUSR1
, SIG_IGN
);
73 if (VGLMem
!= MAP_FAILED
) {
74 VGLClear(VGLDisplay
, 0);
75 munmap(VGLMem
, VGLAdpInfo
.va_window_size
);
78 if (VGLOldMode
>= M_VESA_BASE
) {
79 /* ugly, but necessary */
80 ioctl(0, _IO('V', VGLOldMode
- M_VESA_BASE
), 0);
81 if (VGLOldMode
== M_VESA_800x600
) {
83 size
[0] = VGLOldWSize
.ws_col
;
84 size
[1] = VGLOldWSize
.ws_row
;
86 ioctl(0, KDRASTER
, size
);
89 ioctl(0, _IO('S', VGLOldMode
), 0);
91 ioctl(0, KDDISABIO
, 0);
92 ioctl(0, KDSETMODE
, KD_TEXT
);
94 ioctl(0, VT_SETMODE
, &smode
);
104 VGLAbort(int signo __unused
)
107 signal(SIGINT
, SIG_IGN
);
108 signal(SIGTERM
, SIG_IGN
);
109 signal(SIGSEGV
, SIG_IGN
);
110 signal(SIGBUS
, SIG_IGN
);
111 signal(SIGUSR2
, SIG_IGN
);
115 VGLSwitch(int signo __unused
)
121 VGLSwitchPending
= 1;
122 signal(SIGUSR1
, VGLSwitch
);
128 struct vt_mode smode
;
134 signal(SIGUSR1
, VGLSwitch
);
135 signal(SIGINT
, VGLAbort
);
136 signal(SIGTERM
, VGLAbort
);
137 signal(SIGSEGV
, VGLAbort
);
138 signal(SIGBUS
, VGLAbort
);
139 signal(SIGUSR2
, SIG_IGN
);
142 VGLSwitchPending
= 0;
145 if (ioctl(0, CONS_GET
, &VGLOldMode
) || ioctl(0, CONS_CURRENT
, &adptype
))
147 VGLModeInfo
.vi_mode
= mode
;
148 if (ioctl(0, CONS_MODEINFO
, &VGLModeInfo
)) /* FBIO_MODEINFO */
151 /* If current mode is VESA_800x600 then save its geometry to restore later */
152 if ((VGLOldMode
>= M_VESA_BASE
) && (VGLOldMode
== M_VESA_800x600
))
153 if (ioctl(0, TIOCGWINSZ
, &VGLOldWSize
))
156 VGLDisplay
= (VGLBitmap
*)malloc(sizeof(VGLBitmap
));
157 if (VGLDisplay
== NULL
)
160 if (ioctl(0, KDENABIO
, 0)) {
168 * vi_mem_model specifies the memory model of the current video mode
171 switch (VGLModeInfo
.vi_mem_model
) {
172 case V_INFO_MM_PLANAR
:
173 /* we can handle EGA/VGA planner modes only */
174 if (VGLModeInfo
.vi_depth
!= 4 || VGLModeInfo
.vi_planes
!= 4
175 || (adptype
!= KD_EGA
&& adptype
!= KD_VGA
)) {
179 VGLDisplay
->Type
= VIDBUF4
;
181 case V_INFO_MM_PACKED
:
182 /* we can do only 256 color packed modes */
183 if (VGLModeInfo
.vi_depth
!= 8) {
187 VGLDisplay
->Type
= VIDBUF8
;
190 VGLDisplay
->Type
= VIDBUF8X
;
197 ioctl(0, VT_WAITACTIVE
, 0);
198 ioctl(0, KDSETMODE
, KD_GRAPHICS
);
199 if (ioctl(0, CONS_SET
, &mode
)) {
203 if (ioctl(0, CONS_ADPINFO
, &VGLAdpInfo
)) { /* FBIO_ADPINFO */
209 * Calculate the shadow screen buffer size. In -CURRENT, va_buffer_size
210 * always holds the entire frame buffer size, wheather it's in the linear
211 * mode or windowed mode.
212 * VGLBufSize = VGLAdpInfo.va_buffer_size;
213 * In -STABLE, va_buffer_size holds the frame buffer size, only if
214 * the linear frame buffer mode is supported. Otherwise the field is zero.
215 * We shall calculate the minimal size in this case:
216 * VGLAdpInfo.va_line_width*VGLModeInfo.vi_height*VGLModeInfo.vi_planes
218 * VGLAdpInfo.va_window_size*VGLModeInfo.vi_planes;
219 * Use whichever is larger.
221 if (VGLAdpInfo
.va_buffer_size
!= 0)
222 VGLBufSize
= VGLAdpInfo
.va_buffer_size
;
224 VGLBufSize
= max(VGLAdpInfo
.va_line_width
*VGLModeInfo
.vi_height
,
225 VGLAdpInfo
.va_window_size
)*VGLModeInfo
.vi_planes
;
226 VGLBuf
= malloc(VGLBufSize
);
227 if (VGLBuf
== NULL
) {
233 fprintf(stderr
, "VGLBufSize:0x%x\n", VGLBufSize
);
236 /* see if we are in the windowed buffer mode or in the linear buffer mode */
237 if (VGLBufSize
/VGLModeInfo
.vi_planes
> VGLAdpInfo
.va_window_size
) {
238 if (VGLDisplay
->Type
== VIDBUF4
)
239 VGLDisplay
->Type
= VIDBUF4S
;
240 else if (VGLDisplay
->Type
== VIDBUF8
)
241 VGLDisplay
->Type
= VIDBUF8S
;
247 VGLDisplay
->Xsize
= VGLModeInfo
.vi_width
;
248 VGLDisplay
->Ysize
= VGLModeInfo
.vi_height
;
249 VGLDisplay
->VXsize
= VGLAdpInfo
.va_line_width
250 *8/(VGLModeInfo
.vi_depth
/VGLModeInfo
.vi_planes
);
251 VGLDisplay
->VYsize
= VGLBufSize
/VGLModeInfo
.vi_planes
/VGLAdpInfo
.va_line_width
;
252 VGLDisplay
->Xorigin
= 0;
253 VGLDisplay
->Yorigin
= 0;
255 VGLMem
= (byte
*)mmap(0, VGLAdpInfo
.va_window_size
, PROT_READ
|PROT_WRITE
,
257 if (VGLMem
== MAP_FAILED
) {
261 VGLDisplay
->Bitmap
= VGLMem
;
266 fprintf(stderr
, "va_line_width:%d\n", VGLAdpInfo
.va_line_width
);
267 fprintf(stderr
, "VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
268 VGLDisplay
->Xsize
, VGLDisplay
->Ysize
,
269 VGLDisplay
->VXsize
, VGLDisplay
->VYsize
);
272 smode
.mode
= VT_PROCESS
;
274 smode
.relsig
= SIGUSR1
;
275 smode
.acqsig
= SIGUSR1
;
276 smode
.frsig
= SIGINT
;
277 if (ioctl(0, VT_SETMODE
, &smode
)) {
281 VGLTextSetFontFile(NULL
);
282 VGLClear(VGLDisplay
, 0);
289 if (VGLAbortPending
) {
293 while (VGLSwitchPending
) {
298 VGLSwitchPending
= 0;
300 ioctl(0, KDENABIO
, 0);
301 ioctl(0, KDSETMODE
, KD_GRAPHICS
);
302 ioctl(0, VGLMode
, 0);
304 VGLMem
= (byte
*)mmap(0, VGLAdpInfo
.va_window_size
, PROT_READ
|PROT_WRITE
,
307 /* XXX: what if mmap() has failed! */
308 VGLDisplay
->Type
= VIDBUF8
; /* XXX */
309 switch (VGLModeInfo
.vi_mem_model
) {
310 case V_INFO_MM_PLANAR
:
311 if (VGLModeInfo
.vi_depth
== 4 && VGLModeInfo
.vi_planes
== 4) {
312 if (VGLBufSize
/VGLModeInfo
.vi_planes
> VGLAdpInfo
.va_window_size
)
313 VGLDisplay
->Type
= VIDBUF4S
;
315 VGLDisplay
->Type
= VIDBUF4
;
317 /* shouldn't be happening */
320 case V_INFO_MM_PACKED
:
321 if (VGLModeInfo
.vi_depth
== 8) {
322 if (VGLBufSize
/VGLModeInfo
.vi_planes
> VGLAdpInfo
.va_window_size
)
323 VGLDisplay
->Type
= VIDBUF8S
;
325 VGLDisplay
->Type
= VIDBUF8
;
327 /* shouldn't be happening */
331 VGLDisplay
->Type
= VIDBUF8X
;
334 /* shouldn't be happening */
338 VGLDisplay
->Bitmap
= VGLMem
;
339 VGLDisplay
->Xsize
= VGLModeInfo
.vi_width
;
340 VGLDisplay
->Ysize
= VGLModeInfo
.vi_height
;
341 VGLSetVScreenSize(VGLDisplay
, VGLDisplay
->VXsize
, VGLDisplay
->VYsize
);
342 VGLPanScreen(VGLDisplay
, VGLDisplay
->Xorigin
, VGLDisplay
->Yorigin
);
343 switch (VGLDisplay
->Type
) {
346 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */
347 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */
348 for (offset
= 0; offset
< VGLBufSize
/VGLModeInfo
.vi_planes
;
350 VGLSetSegment(offset
);
351 len
= min(VGLBufSize
/VGLModeInfo
.vi_planes
- offset
,
352 VGLAdpInfo
.va_window_size
);
353 for (i
= 0; i
< VGLModeInfo
.vi_planes
; i
++) {
355 outb(0x3c5, 0x01<<i
);
356 bcopy(&VGLBuf
[i
*VGLBufSize
/VGLModeInfo
.vi_planes
+ offset
],
364 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */
365 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */
366 for (i
= 0; i
< VGLModeInfo
.vi_planes
; i
++) {
368 outb(0x3c5, 0x01<<i
);
369 bcopy(&VGLBuf
[i
*VGLAdpInfo
.va_window_size
], VGLMem
,
370 VGLAdpInfo
.va_window_size
);
375 for (offset
= 0; offset
< VGLBufSize
; offset
+= len
) {
376 VGLSetSegment(offset
);
377 len
= min(VGLBufSize
- offset
, VGLAdpInfo
.va_window_size
);
378 bcopy(&VGLBuf
[offset
], VGLMem
, len
);
383 ioctl(0, VT_RELDISP
, VT_ACKACQ
);
386 switch (VGLDisplay
->Type
) {
388 for (offset
= 0; offset
< VGLBufSize
/VGLModeInfo
.vi_planes
;
390 VGLSetSegment(offset
);
391 len
= min(VGLBufSize
/VGLModeInfo
.vi_planes
- offset
,
392 VGLAdpInfo
.va_window_size
);
393 for (i
= 0; i
< VGLModeInfo
.vi_planes
; i
++) {
396 bcopy(VGLMem
, &VGLBuf
[i
*VGLBufSize
/VGLModeInfo
.vi_planes
+ offset
],
404 * NOTE: the saved buffer is NOT in the MEMBUF format which
405 * the ordinary memory bitmap object is stored in. XXX
407 for (i
= 0; i
< VGLModeInfo
.vi_planes
; i
++) {
410 bcopy(VGLMem
, &VGLBuf
[i
*VGLAdpInfo
.va_window_size
],
411 VGLAdpInfo
.va_window_size
);
416 for (offset
= 0; offset
< VGLBufSize
; offset
+= len
) {
417 VGLSetSegment(offset
);
418 len
= min(VGLBufSize
- offset
, VGLAdpInfo
.va_window_size
);
419 bcopy(VGLMem
, &VGLBuf
[offset
], len
);
424 munmap(VGLDisplay
->Bitmap
, VGLAdpInfo
.va_window_size
);
425 ioctl(0, VGLOldMode
, 0);
426 ioctl(0, KDSETMODE
, KD_TEXT
);
427 ioctl(0, KDDISABIO
, 0);
428 ioctl(0, VT_RELDISP
, VT_TRUE
);
429 VGLDisplay
->Bitmap
= VGLBuf
;
430 VGLDisplay
->Type
= MEMBUF
;
431 VGLDisplay
->Xsize
= VGLDisplay
->VXsize
;
432 VGLDisplay
->Ysize
= VGLDisplay
->VYsize
;
433 while (!VGLOnDisplay
) pause();
439 VGLSetSegment(unsigned int offset
)
441 if (offset
/VGLAdpInfo
.va_window_size
!= VGLCurWindow
) {
442 ioctl(0, CONS_SETWINORG
, offset
); /* FBIO_SETWINORG */
443 VGLCurWindow
= offset
/VGLAdpInfo
.va_window_size
;
445 return (offset
%VGLAdpInfo
.va_window_size
);
449 VGLSetVScreenSize(VGLBitmap
*object
, int VXsize
, int VYsize
)
451 if (VXsize
< object
->Xsize
|| VYsize
< object
->Ysize
)
453 if (object
->Type
== MEMBUF
)
455 if (ioctl(0, FBIO_SETLINEWIDTH
, &VXsize
))
457 ioctl(0, CONS_ADPINFO
, &VGLAdpInfo
); /* FBIO_ADPINFO */
458 object
->VXsize
= VGLAdpInfo
.va_line_width
459 *8/(VGLModeInfo
.vi_depth
/VGLModeInfo
.vi_planes
);
460 object
->VYsize
= VGLBufSize
/VGLModeInfo
.vi_planes
/VGLAdpInfo
.va_line_width
;
461 if (VYsize
< object
->VYsize
)
462 object
->VYsize
= VYsize
;
465 fprintf(stderr
, "new size: VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
466 object
->Xsize
, object
->Ysize
, object
->VXsize
, object
->VYsize
);
473 VGLPanScreen(VGLBitmap
*object
, int x
, int y
)
475 video_display_start_t origin
;
477 if (x
< 0 || x
+ object
->Xsize
> object
->VXsize
478 || y
< 0 || y
+ object
->Ysize
> object
->VYsize
)
480 if (object
->Type
== MEMBUF
)
484 if (ioctl(0, FBIO_SETDISPSTART
, &origin
))
490 fprintf(stderr
, "new origin: (%d, %d)\n", x
, y
);