]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libvgl/main.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libvgl / main.c
1 /*-
2  * Copyright (c) 1991-1997 Søren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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 without specific prior written permission
16  *
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.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include <sys/signal.h>
35 #include <sys/file.h>
36 #include <sys/ioctl.h>
37 #include <sys/mman.h>
38 #include <sys/fbio.h>
39 #include <sys/kbio.h>
40 #include <sys/consio.h>
41 #include "vgl.h"
42
43 /* XXX Direct Color 24bits modes unsupported */
44
45 #define min(x, y)       (((x) < (y)) ? (x) : (y))
46 #define max(x, y)       (((x) > (y)) ? (x) : (y))
47
48 VGLBitmap *VGLDisplay;
49 video_info_t VGLModeInfo;
50 video_adapter_info_t VGLAdpInfo;
51 byte *VGLBuf;
52
53 static int VGLMode;
54 static int VGLOldMode;
55 static size_t VGLBufSize;
56 static byte *VGLMem = MAP_FAILED;
57 static int VGLSwitchPending;
58 static int VGLAbortPending;
59 static int VGLOnDisplay;
60 static unsigned int VGLCurWindow;
61 static int VGLInitDone = 0;
62 static vid_info_t VGLOldVInfo;
63
64 void
65 VGLEnd()
66 {
67 struct vt_mode smode;
68
69   if (!VGLInitDone)
70     return;
71   VGLInitDone = 0;
72   VGLSwitchPending = 0;
73   VGLAbortPending = 0;
74
75   signal(SIGUSR1, SIG_IGN);
76
77   if (VGLMem != MAP_FAILED) {
78     VGLClear(VGLDisplay, 0);
79     munmap(VGLMem, VGLAdpInfo.va_window_size);
80   }
81
82   if (VGLOldMode >= M_VESA_BASE) {
83     /* ugly, but necessary */
84     ioctl(0, _IO('V', VGLOldMode - M_VESA_BASE), 0);
85     if (VGLOldMode == M_VESA_800x600) {
86       int size[3];
87       size[0] = VGLOldVInfo.mv_csz;
88       size[1] = VGLOldVInfo.mv_rsz;
89       size[2] = 16;
90       ioctl(0, KDRASTER, size);
91     }
92   } else {
93     ioctl(0, _IO('S', VGLOldMode), 0);
94   }
95   ioctl(0, KDDISABIO, 0);
96   ioctl(0, KDSETMODE, KD_TEXT);
97   smode.mode = VT_AUTO;
98   ioctl(0, VT_SETMODE, &smode);
99   if (VGLBuf)
100     free(VGLBuf);
101   VGLBuf = NULL;
102   free(VGLDisplay);
103   VGLDisplay = NULL;
104   VGLKeyboardEnd();
105 }
106
107 static void 
108 VGLAbort(int arg __unused)
109 {
110   VGLAbortPending = 1;
111   signal(SIGINT, SIG_IGN);
112   signal(SIGTERM, SIG_IGN);
113   signal(SIGSEGV, SIG_IGN);
114   signal(SIGBUS, SIG_IGN);
115   signal(SIGUSR2, SIG_IGN);
116 }
117
118 static void
119 VGLSwitch(int arg __unused)
120 {
121   if (!VGLOnDisplay)
122     VGLOnDisplay = 1;
123   else
124     VGLOnDisplay = 0;
125   VGLSwitchPending = 1;
126   signal(SIGUSR1, VGLSwitch);
127 }
128
129 int
130 VGLInit(int mode)
131 {
132   struct vt_mode smode;
133   int adptype;
134
135   if (VGLInitDone)
136     return -1;
137
138   signal(SIGUSR1, VGLSwitch);
139   signal(SIGINT, VGLAbort);
140   signal(SIGTERM, VGLAbort);
141   signal(SIGSEGV, VGLAbort);
142   signal(SIGBUS, VGLAbort);
143   signal(SIGUSR2, SIG_IGN);
144
145   VGLOnDisplay = 1;
146   VGLSwitchPending = 0;
147   VGLAbortPending = 0;
148
149   if (ioctl(0, CONS_GET, &VGLOldMode) || ioctl(0, CONS_CURRENT, &adptype))
150     return -1;
151   if (IOCGROUP(mode) == 'V')    /* XXX: this is ugly */
152     VGLModeInfo.vi_mode = (mode & 0x0ff) + M_VESA_BASE;
153   else
154     VGLModeInfo.vi_mode = mode & 0x0ff;
155   if (ioctl(0, CONS_MODEINFO, &VGLModeInfo))    /* FBIO_MODEINFO */
156     return -1;
157
158   /* If current mode is VESA_800x600 then save its geometry to restore later */
159   if ((VGLOldMode >= M_VESA_BASE) && (VGLOldMode == M_VESA_800x600)) {
160     VGLOldVInfo.size = sizeof(VGLOldVInfo);
161     if (ioctl(0, CONS_GETINFO, &VGLOldVInfo))
162       return -1;
163   }
164
165   VGLDisplay = (VGLBitmap *)malloc(sizeof(VGLBitmap));
166   if (VGLDisplay == NULL)
167     return -2;
168
169   if (ioctl(0, KDENABIO, 0)) {
170     free(VGLDisplay);
171     return -3;
172   }
173
174   VGLInitDone = 1;
175
176   /*
177    * vi_mem_model specifies the memory model of the current video mode
178    * in -CURRENT.
179    */
180   switch (VGLModeInfo.vi_mem_model) {
181   case V_INFO_MM_PLANAR:
182     /* we can handle EGA/VGA planner modes only */
183     if (VGLModeInfo.vi_depth != 4 || VGLModeInfo.vi_planes != 4
184         || (adptype != KD_EGA && adptype != KD_VGA)) {
185       VGLEnd();
186       return -4;
187     }
188     VGLDisplay->Type = VIDBUF4;
189     break;
190   case V_INFO_MM_PACKED:
191     /* we can do only 256 color packed modes */
192     if (VGLModeInfo.vi_depth != 8) {
193       VGLEnd();
194       return -4;
195     }
196     VGLDisplay->Type = VIDBUF8;
197     VGLDisplay->PixelBytes = 1;
198     break;
199   case V_INFO_MM_VGAX:
200     VGLDisplay->Type = VIDBUF8X;
201     VGLDisplay->PixelBytes = 1;
202     break;
203   case V_INFO_MM_DIRECT:
204     VGLDisplay->PixelBytes = VGLModeInfo.vi_pixel_size;
205     switch (VGLDisplay->PixelBytes) {
206     case 2:
207       VGLDisplay->Type = VIDBUF16;
208       break;
209 #if notyet
210     case 3:
211       VGLDisplay->Type = VIDBUF24;
212       break;
213 #endif
214     case 4:
215       VGLDisplay->Type = VIDBUF32;
216       break;
217     default:
218       VGLEnd();
219       return -4;
220     }
221     break;
222   default:
223     VGLEnd();
224     return -4;
225   }
226
227   ioctl(0, VT_WAITACTIVE, 0);
228   ioctl(0, KDSETMODE, KD_GRAPHICS);
229   if (ioctl(0, mode, 0)) {
230     VGLEnd();
231     return -5;
232   }
233   if (ioctl(0, CONS_ADPINFO, &VGLAdpInfo)) {    /* FBIO_ADPINFO */
234     VGLEnd();
235     return -6;
236   }
237
238   /*
239    * Calculate the shadow screen buffer size.  In -CURRENT, va_buffer_size
240    * always holds the entire frame buffer size, wheather it's in the linear
241    * mode or windowed mode.  
242    *     VGLBufSize = VGLAdpInfo.va_buffer_size;
243    * In -STABLE, va_buffer_size holds the frame buffer size, only if
244    * the linear frame buffer mode is supported. Otherwise the field is zero.
245    * We shall calculate the minimal size in this case:
246    *     VGLAdpInfo.va_line_width*VGLModeInfo.vi_height*VGLModeInfo.vi_planes
247    * or
248    *     VGLAdpInfo.va_window_size*VGLModeInfo.vi_planes;
249    * Use whichever is larger.
250    */
251   if (VGLAdpInfo.va_buffer_size != 0)
252     VGLBufSize = VGLAdpInfo.va_buffer_size;
253   else
254     VGLBufSize = max(VGLAdpInfo.va_line_width*VGLModeInfo.vi_height,
255                      VGLAdpInfo.va_window_size)*VGLModeInfo.vi_planes;
256   VGLBuf = malloc(VGLBufSize);
257   if (VGLBuf == NULL) {
258     VGLEnd();
259     return -7;
260   }
261
262 #ifdef LIBVGL_DEBUG
263   fprintf(stderr, "VGLBufSize:0x%x\n", VGLBufSize);
264 #endif
265
266   /* see if we are in the windowed buffer mode or in the linear buffer mode */
267   if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) {
268     switch (VGLDisplay->Type) {
269     case VIDBUF4:
270       VGLDisplay->Type = VIDBUF4S;
271       break;
272     case VIDBUF8:
273       VGLDisplay->Type = VIDBUF8S;
274       break;
275     case VIDBUF16:
276       VGLDisplay->Type = VIDBUF16S;
277       break;
278     case VIDBUF24:
279       VGLDisplay->Type = VIDBUF24S;
280       break;
281     case VIDBUF32:
282       VGLDisplay->Type = VIDBUF32S;
283       break;
284     default:
285       VGLEnd();
286       return -8;
287     }
288   }
289
290   VGLMode = mode;
291   VGLCurWindow = 0;
292
293   VGLDisplay->Xsize = VGLModeInfo.vi_width;
294   VGLDisplay->Ysize = VGLModeInfo.vi_height;
295   VGLDisplay->VXsize = VGLAdpInfo.va_line_width
296                            *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes);
297   VGLDisplay->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width;
298   VGLDisplay->Xorigin = 0;
299   VGLDisplay->Yorigin = 0;
300
301   VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE,
302                        MAP_FILE, 0, 0);
303   if (VGLMem == MAP_FAILED) {
304     VGLEnd();
305     return -7;
306   }
307   VGLDisplay->Bitmap = VGLMem;
308
309   VGLSavePalette();
310
311 #ifdef LIBVGL_DEBUG
312   fprintf(stderr, "va_line_width:%d\n", VGLAdpInfo.va_line_width);
313   fprintf(stderr, "VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
314           VGLDisplay->Xsize, VGLDisplay->Ysize, 
315           VGLDisplay->VXsize, VGLDisplay->VYsize);
316 #endif
317
318   smode.mode = VT_PROCESS;
319   smode.waitv = 0;
320   smode.relsig = SIGUSR1;
321   smode.acqsig = SIGUSR1;
322   smode.frsig  = SIGINT;        
323   if (ioctl(0, VT_SETMODE, &smode)) {
324     VGLEnd();
325     return -9;
326   }
327   VGLTextSetFontFile((byte*)0);
328   VGLClear(VGLDisplay, 0);
329   return 0;
330 }
331
332 void
333 VGLCheckSwitch()
334 {
335   if (VGLAbortPending) {
336     VGLEnd();
337     exit(0);
338   }
339   while (VGLSwitchPending) {
340     unsigned int offset;
341     unsigned int len;
342     int i;
343
344     VGLSwitchPending = 0;
345     if (VGLOnDisplay) {
346       ioctl(0, KDENABIO, 0);
347       ioctl(0, KDSETMODE, KD_GRAPHICS);
348       ioctl(0, VGLMode, 0);
349       VGLCurWindow = 0;
350       VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE,
351                            MAP_FILE, 0, 0);
352
353       /* XXX: what if mmap() has failed! */
354       VGLDisplay->Type = VIDBUF8;       /* XXX */
355       switch (VGLModeInfo.vi_mem_model) {
356       case V_INFO_MM_PLANAR:
357         if (VGLModeInfo.vi_depth == 4 && VGLModeInfo.vi_planes == 4) {
358           if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
359             VGLDisplay->Type = VIDBUF4S;
360           else
361             VGLDisplay->Type = VIDBUF4;
362         } else {
363           /* shouldn't be happening */
364         }
365         break;
366       case V_INFO_MM_PACKED:
367         if (VGLModeInfo.vi_depth == 8) {
368           if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
369             VGLDisplay->Type = VIDBUF8S;
370           else
371             VGLDisplay->Type = VIDBUF8;
372         }
373         break;
374       case V_INFO_MM_VGAX:
375         VGLDisplay->Type = VIDBUF8X;
376         break;
377       case V_INFO_MM_DIRECT:
378         switch (VGLModeInfo.vi_pixel_size) {
379           case 2:
380             if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
381               VGLDisplay->Type = VIDBUF16S;
382             else
383               VGLDisplay->Type = VIDBUF16;
384             break;
385           case 3:
386             if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
387               VGLDisplay->Type = VIDBUF24S;
388             else
389               VGLDisplay->Type = VIDBUF24;
390             break;
391           case 4:
392             if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
393               VGLDisplay->Type = VIDBUF32S;
394             else
395               VGLDisplay->Type = VIDBUF32;
396             break;
397           default:
398           /* shouldn't be happening */
399           break;
400         }
401       default:
402         /* shouldn't be happening */
403         break;
404       }
405
406       VGLDisplay->Bitmap = VGLMem;
407       VGLDisplay->Xsize = VGLModeInfo.vi_width;
408       VGLDisplay->Ysize = VGLModeInfo.vi_height;
409       VGLSetVScreenSize(VGLDisplay, VGLDisplay->VXsize, VGLDisplay->VYsize);
410       VGLPanScreen(VGLDisplay, VGLDisplay->Xorigin, VGLDisplay->Yorigin);
411       switch (VGLDisplay->Type) {
412       case VIDBUF4S:
413         outb(0x3c6, 0xff);
414         outb(0x3ce, 0x01); outb(0x3cf, 0x00);           /* set/reset enable */
415         outb(0x3ce, 0x08); outb(0x3cf, 0xff);           /* bit mask */
416         for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes;
417              offset += len) {
418           VGLSetSegment(offset);
419           len = min(VGLBufSize/VGLModeInfo.vi_planes - offset,
420                     VGLAdpInfo.va_window_size);
421           for (i = 0; i < VGLModeInfo.vi_planes; i++) {
422             outb(0x3c4, 0x02);
423             outb(0x3c5, 0x01<<i);
424             bcopy(&VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset],
425                   VGLMem, len);
426           }
427         }
428         break;
429       case VIDBUF4:
430       case VIDBUF8X:
431         outb(0x3c6, 0xff);
432         outb(0x3ce, 0x01); outb(0x3cf, 0x00);           /* set/reset enable */
433         outb(0x3ce, 0x08); outb(0x3cf, 0xff);           /* bit mask */
434         for (i = 0; i < VGLModeInfo.vi_planes; i++) {
435           outb(0x3c4, 0x02);
436           outb(0x3c5, 0x01<<i);
437           bcopy(&VGLBuf[i*VGLAdpInfo.va_window_size], VGLMem,
438                 VGLAdpInfo.va_window_size);
439         }
440         break;
441       case VIDBUF8:
442       case VIDBUF8S:
443       case VIDBUF16:
444       case VIDBUF16S:
445       case VIDBUF24:
446       case VIDBUF24S:
447       case VIDBUF32:
448       case VIDBUF32S:
449         for (offset = 0; offset < VGLBufSize; offset += len) {
450           VGLSetSegment(offset);
451           len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size);
452           bcopy(&VGLBuf[offset], VGLMem, len);
453         }
454         break;
455       }
456       VGLRestorePalette();
457       ioctl(0, VT_RELDISP, VT_ACKACQ);
458     }
459     else {
460       switch (VGLDisplay->Type) {
461       case VIDBUF4S:
462         for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes;
463              offset += len) {
464           VGLSetSegment(offset);
465           len = min(VGLBufSize/VGLModeInfo.vi_planes - offset,
466                     VGLAdpInfo.va_window_size);
467           for (i = 0; i < VGLModeInfo.vi_planes; i++) {
468             outb(0x3ce, 0x04);
469             outb(0x3cf, i);
470             bcopy(VGLMem, &VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset],
471                   len);
472           }
473         }
474         break;
475       case VIDBUF4:
476       case VIDBUF8X:
477         /*
478          * NOTE: the saved buffer is NOT in the MEMBUF format which 
479          * the ordinary memory bitmap object is stored in. XXX
480          */
481         for (i = 0; i < VGLModeInfo.vi_planes; i++) {
482           outb(0x3ce, 0x04);
483           outb(0x3cf, i);
484           bcopy(VGLMem, &VGLBuf[i*VGLAdpInfo.va_window_size],
485                 VGLAdpInfo.va_window_size);
486         }
487         break;
488       case VIDBUF8:
489       case VIDBUF8S:
490       case VIDBUF16:
491       case VIDBUF16S:
492       case VIDBUF24:
493       case VIDBUF24S:
494       case VIDBUF32:
495       case VIDBUF32S:
496         for (offset = 0; offset < VGLBufSize; offset += len) {
497           VGLSetSegment(offset);
498           len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size);
499           bcopy(VGLMem, &VGLBuf[offset], len);
500         }
501         break;
502       }
503       VGLMem = MAP_FAILED;
504       munmap(VGLDisplay->Bitmap, VGLAdpInfo.va_window_size);
505       ioctl(0, VGLOldMode, 0);
506       ioctl(0, KDSETMODE, KD_TEXT);
507       ioctl(0, KDDISABIO, 0);
508       ioctl(0, VT_RELDISP, VT_TRUE);
509       VGLDisplay->Bitmap = VGLBuf;
510       VGLDisplay->Type = MEMBUF;
511       VGLDisplay->Xsize = VGLDisplay->VXsize;
512       VGLDisplay->Ysize = VGLDisplay->VYsize;
513       while (!VGLOnDisplay) pause();
514     }
515   }
516 }
517
518 int
519 VGLSetSegment(unsigned int offset)
520 {
521   if (offset/VGLAdpInfo.va_window_size != VGLCurWindow) {
522     ioctl(0, CONS_SETWINORG, offset);           /* FBIO_SETWINORG */
523     VGLCurWindow = offset/VGLAdpInfo.va_window_size;
524   }
525   return (offset%VGLAdpInfo.va_window_size);
526 }
527
528 int
529 VGLSetVScreenSize(VGLBitmap *object, int VXsize, int VYsize)
530 {
531   if (VXsize < object->Xsize || VYsize < object->Ysize)
532     return -1;
533   if (object->Type == MEMBUF)
534     return -1;
535   if (ioctl(0, FBIO_SETLINEWIDTH, &VXsize))
536     return -1;
537   ioctl(0, CONS_ADPINFO, &VGLAdpInfo);  /* FBIO_ADPINFO */
538   object->VXsize = VGLAdpInfo.va_line_width
539                            *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes);
540   object->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width;
541   if (VYsize < object->VYsize)
542     object->VYsize = VYsize;
543
544 #ifdef LIBVGL_DEBUG
545   fprintf(stderr, "new size: VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
546           object->Xsize, object->Ysize, object->VXsize, object->VYsize);
547 #endif
548
549   return 0;
550 }
551
552 int
553 VGLPanScreen(VGLBitmap *object, int x, int y)
554 {
555   video_display_start_t origin;
556
557   if (x < 0 || x + object->Xsize > object->VXsize
558       || y < 0 || y + object->Ysize > object->VYsize)
559     return -1;
560   if (object->Type == MEMBUF)
561     return 0;
562   origin.x = x;
563   origin.y = y;
564   if (ioctl(0, FBIO_SETDISPSTART, &origin))
565     return -1;
566   object->Xorigin = x;
567   object->Yorigin = y;
568
569 #ifdef LIBVGL_DEBUG
570   fprintf(stderr, "new origin: (%d, %d)\n", x, y);
571 #endif
572
573   return 0;
574 }