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.2 2003/06/17 04:26:52 dillon 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
);
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
);
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 if (IOCGROUP(mode
) == 'V') /* XXX: this is ugly */
148 VGLModeInfo
.vi_mode
= (mode
& 0x0ff) + M_VESA_BASE
;
150 VGLModeInfo
.vi_mode
= mode
& 0x0ff;
151 if (ioctl(0, CONS_MODEINFO
, &VGLModeInfo
)) /* FBIO_MODEINFO */
154 /* If current mode is VESA_800x600 then save its geometry to restore later */
155 if ((VGLOldMode
>= M_VESA_BASE
) && (VGLOldMode
== M_VESA_800x600
))
156 if (ioctl(0, TIOCGWINSZ
, &VGLOldWSize
))
159 VGLDisplay
= (VGLBitmap
*)malloc(sizeof(VGLBitmap
));
160 if (VGLDisplay
== NULL
)
163 if (ioctl(0, KDENABIO
, 0)) {
171 * vi_mem_model specifies the memory model of the current video mode
174 switch (VGLModeInfo
.vi_mem_model
) {
175 case V_INFO_MM_PLANAR
:
176 /* we can handle EGA/VGA planner modes only */
177 if (VGLModeInfo
.vi_depth
!= 4 || VGLModeInfo
.vi_planes
!= 4
178 || (adptype
!= KD_EGA
&& adptype
!= KD_VGA
)) {
182 VGLDisplay
->Type
= VIDBUF4
;
184 case V_INFO_MM_PACKED
:
185 /* we can do only 256 color packed modes */
186 if (VGLModeInfo
.vi_depth
!= 8) {
190 VGLDisplay
->Type
= VIDBUF8
;
193 VGLDisplay
->Type
= VIDBUF8X
;
200 ioctl(0, VT_WAITACTIVE
, 0);
201 ioctl(0, KDSETMODE
, KD_GRAPHICS
);
202 if (ioctl(0, mode
, 0)) {
206 if (ioctl(0, CONS_ADPINFO
, &VGLAdpInfo
)) { /* FBIO_ADPINFO */
212 * Calculate the shadow screen buffer size. In -CURRENT, va_buffer_size
213 * always holds the entire frame buffer size, wheather it's in the linear
214 * mode or windowed mode.
215 * VGLBufSize = VGLAdpInfo.va_buffer_size;
216 * In -STABLE, va_buffer_size holds the frame buffer size, only if
217 * the linear frame buffer mode is supported. Otherwise the field is zero.
218 * We shall calculate the minimal size in this case:
219 * VGLAdpInfo.va_line_width*VGLModeInfo.vi_height*VGLModeInfo.vi_planes
221 * VGLAdpInfo.va_window_size*VGLModeInfo.vi_planes;
222 * Use whichever is larger.
224 if (VGLAdpInfo
.va_buffer_size
!= 0)
225 VGLBufSize
= VGLAdpInfo
.va_buffer_size
;
227 VGLBufSize
= max(VGLAdpInfo
.va_line_width
*VGLModeInfo
.vi_height
,
228 VGLAdpInfo
.va_window_size
)*VGLModeInfo
.vi_planes
;
229 VGLBuf
= malloc(VGLBufSize
);
230 if (VGLBuf
== NULL
) {
236 fprintf(stderr
, "VGLBufSize:0x%x\n", VGLBufSize
);
239 /* see if we are in the windowed buffer mode or in the linear buffer mode */
240 if (VGLBufSize
/VGLModeInfo
.vi_planes
> VGLAdpInfo
.va_window_size
) {
241 if (VGLDisplay
->Type
== VIDBUF4
)
242 VGLDisplay
->Type
= VIDBUF4S
;
243 else if (VGLDisplay
->Type
== VIDBUF8
)
244 VGLDisplay
->Type
= VIDBUF8S
;
250 VGLDisplay
->Xsize
= VGLModeInfo
.vi_width
;
251 VGLDisplay
->Ysize
= VGLModeInfo
.vi_height
;
252 VGLDisplay
->VXsize
= VGLAdpInfo
.va_line_width
253 *8/(VGLModeInfo
.vi_depth
/VGLModeInfo
.vi_planes
);
254 VGLDisplay
->VYsize
= VGLBufSize
/VGLModeInfo
.vi_planes
/VGLAdpInfo
.va_line_width
;
255 VGLDisplay
->Xorigin
= 0;
256 VGLDisplay
->Yorigin
= 0;
258 VGLMem
= (byte
*)mmap(0, VGLAdpInfo
.va_window_size
, PROT_READ
|PROT_WRITE
,
260 if (VGLMem
== MAP_FAILED
) {
264 VGLDisplay
->Bitmap
= VGLMem
;
269 fprintf(stderr
, "va_line_width:%d\n", VGLAdpInfo
.va_line_width
);
270 fprintf(stderr
, "VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
271 VGLDisplay
->Xsize
, VGLDisplay
->Ysize
,
272 VGLDisplay
->VXsize
, VGLDisplay
->VYsize
);
275 smode
.mode
= VT_PROCESS
;
277 smode
.relsig
= SIGUSR1
;
278 smode
.acqsig
= SIGUSR1
;
279 smode
.frsig
= SIGINT
;
280 if (ioctl(0, VT_SETMODE
, &smode
)) {
284 VGLTextSetFontFile((byte
*)0);
285 VGLClear(VGLDisplay
, 0);
292 if (VGLAbortPending
) {
296 while (VGLSwitchPending
) {
301 VGLSwitchPending
= 0;
303 ioctl(0, KDENABIO
, 0);
304 ioctl(0, KDSETMODE
, KD_GRAPHICS
);
305 ioctl(0, VGLMode
, 0);
307 VGLMem
= (byte
*)mmap(0, VGLAdpInfo
.va_window_size
, PROT_READ
|PROT_WRITE
,
310 /* XXX: what if mmap() has failed! */
311 VGLDisplay
->Type
= VIDBUF8
; /* XXX */
312 switch (VGLModeInfo
.vi_mem_model
) {
313 case V_INFO_MM_PLANAR
:
314 if (VGLModeInfo
.vi_depth
== 4 && VGLModeInfo
.vi_planes
== 4) {
315 if (VGLBufSize
/VGLModeInfo
.vi_planes
> VGLAdpInfo
.va_window_size
)
316 VGLDisplay
->Type
= VIDBUF4S
;
318 VGLDisplay
->Type
= VIDBUF4
;
320 /* shouldn't be happening */
323 case V_INFO_MM_PACKED
:
324 if (VGLModeInfo
.vi_depth
== 8) {
325 if (VGLBufSize
/VGLModeInfo
.vi_planes
> VGLAdpInfo
.va_window_size
)
326 VGLDisplay
->Type
= VIDBUF8S
;
328 VGLDisplay
->Type
= VIDBUF8
;
330 /* shouldn't be happening */
334 VGLDisplay
->Type
= VIDBUF8X
;
337 /* shouldn't be happening */
341 VGLDisplay
->Bitmap
= VGLMem
;
342 VGLDisplay
->Xsize
= VGLModeInfo
.vi_width
;
343 VGLDisplay
->Ysize
= VGLModeInfo
.vi_height
;
344 VGLSetVScreenSize(VGLDisplay
, VGLDisplay
->VXsize
, VGLDisplay
->VYsize
);
345 VGLPanScreen(VGLDisplay
, VGLDisplay
->Xorigin
, VGLDisplay
->Yorigin
);
346 switch (VGLDisplay
->Type
) {
349 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */
350 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */
351 for (offset
= 0; offset
< VGLBufSize
/VGLModeInfo
.vi_planes
;
353 VGLSetSegment(offset
);
354 len
= min(VGLBufSize
/VGLModeInfo
.vi_planes
- offset
,
355 VGLAdpInfo
.va_window_size
);
356 for (i
= 0; i
< VGLModeInfo
.vi_planes
; i
++) {
358 outb(0x3c5, 0x01<<i
);
359 bcopy(&VGLBuf
[i
*VGLBufSize
/VGLModeInfo
.vi_planes
+ offset
],
367 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */
368 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */
369 for (i
= 0; i
< VGLModeInfo
.vi_planes
; i
++) {
371 outb(0x3c5, 0x01<<i
);
372 bcopy(&VGLBuf
[i
*VGLAdpInfo
.va_window_size
], VGLMem
,
373 VGLAdpInfo
.va_window_size
);
378 for (offset
= 0; offset
< VGLBufSize
; offset
+= len
) {
379 VGLSetSegment(offset
);
380 len
= min(VGLBufSize
- offset
, VGLAdpInfo
.va_window_size
);
381 bcopy(&VGLBuf
[offset
], VGLMem
, len
);
386 ioctl(0, VT_RELDISP
, VT_ACKACQ
);
389 switch (VGLDisplay
->Type
) {
391 for (offset
= 0; offset
< VGLBufSize
/VGLModeInfo
.vi_planes
;
393 VGLSetSegment(offset
);
394 len
= min(VGLBufSize
/VGLModeInfo
.vi_planes
- offset
,
395 VGLAdpInfo
.va_window_size
);
396 for (i
= 0; i
< VGLModeInfo
.vi_planes
; i
++) {
399 bcopy(VGLMem
, &VGLBuf
[i
*VGLBufSize
/VGLModeInfo
.vi_planes
+ offset
],
407 * NOTE: the saved buffer is NOT in the MEMBUF format which
408 * the ordinary memory bitmap object is stored in. XXX
410 for (i
= 0; i
< VGLModeInfo
.vi_planes
; i
++) {
413 bcopy(VGLMem
, &VGLBuf
[i
*VGLAdpInfo
.va_window_size
],
414 VGLAdpInfo
.va_window_size
);
419 for (offset
= 0; offset
< VGLBufSize
; offset
+= len
) {
420 VGLSetSegment(offset
);
421 len
= min(VGLBufSize
- offset
, VGLAdpInfo
.va_window_size
);
422 bcopy(VGLMem
, &VGLBuf
[offset
], len
);
427 munmap(VGLDisplay
->Bitmap
, VGLAdpInfo
.va_window_size
);
428 ioctl(0, VGLOldMode
, 0);
429 ioctl(0, KDSETMODE
, KD_TEXT
);
430 ioctl(0, KDDISABIO
, 0);
431 ioctl(0, VT_RELDISP
, VT_TRUE
);
432 VGLDisplay
->Bitmap
= VGLBuf
;
433 VGLDisplay
->Type
= MEMBUF
;
434 VGLDisplay
->Xsize
= VGLDisplay
->VXsize
;
435 VGLDisplay
->Ysize
= VGLDisplay
->VYsize
;
436 while (!VGLOnDisplay
) pause();
442 VGLSetSegment(unsigned int offset
)
444 if (offset
/VGLAdpInfo
.va_window_size
!= VGLCurWindow
) {
445 ioctl(0, CONS_SETWINORG
, offset
); /* FBIO_SETWINORG */
446 VGLCurWindow
= offset
/VGLAdpInfo
.va_window_size
;
448 return (offset
%VGLAdpInfo
.va_window_size
);
452 VGLSetVScreenSize(VGLBitmap
*object
, int VXsize
, int VYsize
)
454 if (VXsize
< object
->Xsize
|| VYsize
< object
->Ysize
)
456 if (object
->Type
== MEMBUF
)
458 if (ioctl(0, FBIO_SETLINEWIDTH
, &VXsize
))
460 ioctl(0, CONS_ADPINFO
, &VGLAdpInfo
); /* FBIO_ADPINFO */
461 object
->VXsize
= VGLAdpInfo
.va_line_width
462 *8/(VGLModeInfo
.vi_depth
/VGLModeInfo
.vi_planes
);
463 object
->VYsize
= VGLBufSize
/VGLModeInfo
.vi_planes
/VGLAdpInfo
.va_line_width
;
464 if (VYsize
< object
->VYsize
)
465 object
->VYsize
= VYsize
;
468 fprintf(stderr
, "new size: VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
469 object
->Xsize
, object
->Ysize
, object
->VXsize
, object
->VYsize
);
476 VGLPanScreen(VGLBitmap
*object
, int x
, int y
)
478 video_display_start_t origin
;
480 if (x
< 0 || x
+ object
->Xsize
> object
->VXsize
481 || y
< 0 || y
+ object
->Ysize
> object
->VYsize
)
483 if (object
->Type
== MEMBUF
)
487 if (ioctl(0, FBIO_SETDISPSTART
, &origin
))
493 fprintf(stderr
, "new origin: (%d, %d)\n", x
, y
);