1 /**
2 ** vesa.c ---- the GRX 2.0 VESA BIOS interface
3 **
4 ** Copyright (c) 1995 Csaba Biegl, 820 Stirrup Dr, Nashville, TN 37221
5 ** [e-mail: csaba@vuse.vanderbilt.edu]
6 **
7 ** This file is part of the GRX graphics library.
8 **
9 ** The GRX graphics library is free software; you can redistribute it
10 ** and/or modify it under some conditions; see the "copying.grx" file
11 ** for details.
12 **
13 ** This library is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 **
17 ** Contributions by: (See "doc/credits.doc" for details)
18 ** Hartmut Schirmer (hsc@techfak.uni-kiel.de)
19 ** Andrzej Lawa [FidoNet: Andrzej Lawa 2:480/19.77]
20 **/
21
22 #include <string.h>
23
24 #include "libgrx.h"
25 #include "grdriver.h"
26 #include "arith.h"
27 #include "int86.h"
28 #include "ioport.h"
29 #include "memcopy.h"
30 #include "memfill.h"
31 #include "vesa.h"
32
33 #if defined(__GNUC__) || (defined(__WATCOMC__) && defined(__386__))
34 #define NUM_MODES 100 /* max # of supported modes */
35 #define NUM_EXTS 25 /* max # of mode extensions */
36 #else
37 #define NUM_MODES 40 /* max # of supported modes */
38 #define NUM_EXTS 12 /* max # of mode extensions */
39 #endif
40
41 static GrVideoMode modes[NUM_MODES];
42 static GrVideoModeExt exts[NUM_EXTS];
43
44 static unsigned char _GrVidDrvVESAflags = 0;
45 #define HICOLOR32K 0x01
46 #define PROTBANKING 0x02
47 #define USE_REALMODE 0x04
48 #define NOT_LINEAR 0x08
49 #define NO_8BIT_DAC 0x10
50
51 static char fast256 = 0;
52 static char varDAC = FALSE;
53 static unsigned long VRAMsize = 0;
54 static int VESAversion;
55 static int nexts;
56
57 /* VESA driver (and others) need this information for paging */
58 int _GrVidDrvVESAbanksft = (-1);
59 int _GrVidDrvVESArdbank;
60 int _GrVidDrvVESAwrbank;
61
62 /* these variables hold the correct paging functions:
63 **
64 ** Turbo-C : normal bios access or direct function call
65 ** GNU-C : normal real mode bios access or protected mode banking
66 */
67 static void (*_SETRWBANKS)(int rb, int wb);
68 static void (*_SETBANK)(int bk);
69
70
71 /* get the real mode stuff ... */
72 #include "vesa_rm.c"
73
74 #if (defined(__WATCOMC__) && defined (__386__)) \
75 || (defined(DJGPP) && defined(DJGPP_MINOR))
76 #define HAVE_VBE2
77 /* get the VBE2 protected mode stuff ... */
78 #include "vesa_pm.c"
79
80 # define MC(a,b) a##b
81 # define MODE(md) ((ep->flags & GR_VMODEF_LINEAR) ? MC(md,_LFB) : md)
82
83 #else /* no protected mode support */
84 # define _SETUP _GrViDrvSetEGAVGAmode
85 # define reset _GrViDrvResetEGAVGA
86 # define MODE(md) (md)
87 #endif
88
89
detect(void)90 static int detect(void)
91 {
92 if(_GrViDrvDetectVGA()) {
93 VESAvgaInfoBlock blk;
94 if(_GrViDrvVESAgetVGAinfo(&blk)) return(TRUE);
95 }
96 return(FALSE);
97 }
98
99
100 /* special setup: check for 8bit DAC in palette modes */
setup48(GrVideoMode * mp,int noclear)101 static int setup48(GrVideoMode *mp,int noclear) {
102 int res = _SETUP(mp, noclear);
103 DBGPRINTF(DBG_DRIVER,("setup48 called\n"));
104 if (res) {
105 mp->extinfo->cprec[0] =
106 mp->extinfo->cprec[1] =
107 mp->extinfo->cprec[2] = 6;
108 _GrViDrvSetDACshift(8-6);
109 if (varDAC) {
110 /* have variable DAC, try setting 8bit per color component */
111 Int86Regs r;
112 sttzero(&r);
113 IREG_AX(r) = VESA_FUNC + VESA_PAL_CNTRL;
114 IREG_BX(r) = 0x0800; /* BL = 0 -> set DAC width, BH=8 -> req. width */
115 DBGPRINTF(DBG_DRIVER,("Variable DAC\n"));
116 #ifdef __WATCOMC__
117 int10x(&r);
118 #else
119 int10(&r);
120 #endif
121 if(IREG_AX(r) == VESA_SUCCESS) {
122 DBGPRINTF(DBG_DRIVER,("Variable DAC initialised\n"));
123 _GrViDrvSetDACshift(8-IREG_BH(r));
124 mp->extinfo->cprec[0] =
125 mp->extinfo->cprec[1] =
126 mp->extinfo->cprec[2] = IREG_BH(r);
127 }
128 }
129 }
130 DBGPRINTF(DBG_DRIVER,("setup48 complete\n"));
131 return res;
132 }
133
134
build_video_mode(VESAmodeInfoBlock * ip,GrVideoMode * mp,GrVideoModeExt * ep)135 static int build_video_mode( VESAmodeInfoBlock *ip,
136 GrVideoMode *mp, GrVideoModeExt *ep)
137 {
138 int banksft = 0;
139 int rdbank = (-1);
140 int wrbank = (-1);
141 mp->present = TRUE;
142 mp->width = ip->XResolution;
143 mp->height = ip->YResolution;
144 mp->bpp = ip->BitsPerPixel;
145 mp->lineoffset = ip->BytesPerScanLine;
146 mp->extinfo = NULL;
147 mp->privdata = 0;
148 if(!(ip->ModeAttributes & MODE_ISGRAPHICS)) {
149 mp->extinfo = &_GrViDrvEGAVGAtextModeExt;
150 return(TRUE);
151 }
152 if(ip->WinSize != 64) return(FALSE);
153 while((ip->WinGranularity << banksft) < 64) banksft++;
154 if((ip->WinGranularity << banksft) != 64) return(FALSE);
155 if(ip->WinAAttributes & WIN_SUPPORTED) {
156 if(ip->WinAAttributes & WIN_WRITABLE) wrbank = 0;
157 if(ip->WinAAttributes & WIN_READABLE) rdbank = 0;
158 }
159 if(ip->WinBAttributes & WIN_SUPPORTED) {
160 if(ip->WinBAttributes & WIN_WRITABLE) wrbank = 1;
161 if(ip->WinBAttributes & WIN_READABLE) rdbank = 1;
162 }
163 if(wrbank < 0) return(FALSE);
164 if(rdbank >= 0) {
165 if(rdbank == wrbank) rdbank = (-1);
166 if(ip->WinASegment != ip->WinBSegment) rdbank = (-1);
167 }
168 if(_GrVidDrvVESAbanksft >= 0) {
169 if(banksft != _GrVidDrvVESAbanksft) return(FALSE);
170 if(wrbank != _GrVidDrvVESAwrbank) return(FALSE);
171 if(rdbank != _GrVidDrvVESArdbank) return(FALSE);
172 }
173 _GrVidDrvVESAbanksft = banksft;
174 _GrVidDrvVESAwrbank = wrbank;
175 _GrVidDrvVESArdbank = rdbank;
176
177 ep->mode = GR_frameUndef;
178 ep->drv = NULL;
179 ep->frame = MK_FP((wrbank ? ip->WinBSegment : ip->WinASegment),0);
180 ep->flags = 0;
181 ep->cprec[0] = ep->cprec[1] = ep->cprec[2] = 6;
182 ep->cpos[0] = ep->cpos[1] = ep->cpos[2] = 0;
183
184 #ifdef __TURBOC__
185 if ( _GrVidDrvVESAflags & PROTBANKING) {
186 if(VESAbankfn && (VESAbankfn != ip->WinFuncPtr)) {
187 _GrVidDrvVESAflags &= ~PROTBANKING;
188 _SETRWBANKS = RM_setrwbanks;
189 _SETBANK = RM_setbank;
190 } else {
191 VESAbankfn = ip->WinFuncPtr;
192 _SETRWBANKS = RM_protsetrwbanks;
193 _SETBANK = RM_protsetbank;
194 }
195 }
196 #endif
197 #ifdef HAVE_VBE2
198 if(!(_GrVidDrvVESAflags&NOT_LINEAR) && VESAversion>=VESA_VERSION(2,0)) {
199 /* check for linear frame buffer */
200 if (ip->ModeAttributes&MODE_LIN_FRAME) {
201 DBGPRINTF(DBG_DRIVER,("Linear mode at 0x%08x\n", ip->LinearFrameBuffer));
202 map_linear(ip->LinearFrameBuffer,VRAMsize,
203 &LFB_Selector, &LFB_LinearAddress);
204 DBGPRINTF(DBG_DRIVER,("Linear mode mapped to selector 0x%08x, linear address 0x%08x\n", LFB_Selector, LFB_LinearAddress));
205 ep->LFB_Selector=LFB_Selector;
206 if (LFB_Selector >= 0 && LFB_LinearAddress) {
207 /* every thing went well: allow linear frame buffer access */
208 ep->flags |= GR_VMODEF_LINEAR;
209 ep->frame = LFB_virtualAddr();
210 }
211 }
212 }
213 #endif
214 ep->setup = _SETUP;
215 ep->setvsize = _GrViDrvVESAsetVirtualSize;
216 ep->scroll = _GrViDrvVESAvirtualScroll;
217 ep->setbank = _SETBANK;
218 ep->setrwbanks = (rdbank >= 0) ? _SETRWBANKS : NULL;
219 ep->loadcolor = NULL;
220 switch(ip->BitsPerPixel) {
221 case 4:
222 if(ip->MemoryModel != MODEL_4PLANE) return(FALSE);
223 if(ip->NumberOfPlanes != 4) return(FALSE);
224 ep->mode = GR_frameSVGA4;
225 ep->loadcolor = _GrViDrvLoadColorVGA4;
226 ep->flags = 0; /* no LFB with 4bit modes */
227 ep->setup = setup48;
228 break;
229 case 8:
230 if(ip->MemoryModel != MODEL_PACKED) return(FALSE);
231 if(ip->NumberOfPlanes != 1) return(FALSE);
232 ep->mode = MODE(GR_frameSVGA8);
233 ep->loadcolor = _GrViDrvLoadColorVGA8;
234 ep->flags |= fast256;
235 ep->setup = setup48;
236 break;
237 case 15:
238 case 16:
239 case 24:
240 case 32:
241 if((ip->MemoryModel != MODEL_PACKED) &&
242 (ip->MemoryModel != MODEL_DIRECT)) return(FALSE);
243 if(ip->NumberOfPlanes != 1) return(FALSE);
244 mp->bpp = ip->BitsPerPixel;
245 switch (ip->BitsPerPixel) {
246 case 32: if(VESAversion < VESA_VERSION(1,2))
247 return(FALSE);
248 if (ip->ReservedMaskSize != 8)
249 return(FALSE);
250 switch (ip->ReservedMaskPos) {
251 case 24: ep->mode = MODE(GR_frameSVGA32L);
252 break;
253 case 0: ep->mode = MODE(GR_frameSVGA32H);
254 break;
255 default: return(FALSE);
256 }
257 mp->bpp = 24;
258 break;
259 case 24: ep->mode = MODE(GR_frameSVGA24);
260 break;
261 case 16: if (ip->ReservedMaskSize == 1) mp->bpp = 15;
262 goto Default;
263 default:
264 Default: ep->mode = MODE(GR_frameSVGA16);
265 break;
266 }
267 if(VESAversion < VESA_VERSION(1,2)) {
268 if(ip->BitsPerPixel == 24 || ip->BitsPerPixel == 32) {
269 ep->cprec[0] = 8; ep->cpos[0] = 16;
270 ep->cprec[1] = 8; ep->cpos[1] = 8;
271 ep->cprec[2] = 8; ep->cpos[2] = 0;
272 break;
273 }
274 if((ip->BitsPerPixel==15) || (_GrVidDrvVESAflags&HICOLOR32K)) {
275 mp->bpp = 15;
276 ep->cprec[0] = 5; ep->cpos[0] = 10;
277 ep->cprec[1] = 5; ep->cpos[1] = 5;
278 ep->cprec[2] = 5; ep->cpos[2] = 0;
279 break;
280 }
281 mp->bpp = 16;
282 ep->cprec[0] = 5; ep->cpos[0] = 11;
283 ep->cprec[1] = 6; ep->cpos[1] = 5;
284 ep->cprec[2] = 5; ep->cpos[2] = 0;
285 break;
286 }
287 ep->cprec[0] = ip->RedMaskSize; ep->cpos[0] = ip->RedMaskPos;
288 ep->cprec[1] = ip->GreenMaskSize; ep->cpos[1] = ip->GreenMaskPos;
289 ep->cprec[2] = ip->BlueMaskSize; ep->cpos[2] = ip->BlueMaskPos;
290 break;
291 default:
292 return(FALSE);
293 }
294 DBGPRINTF(DBG_DRIVER,("build_video_mode complete\n" ));
295 return(TRUE);
296 }
297
add_video_mode(GrVideoMode * mp,GrVideoModeExt * ep,GrVideoMode ** mpp,GrVideoModeExt ** epp)298 static void add_video_mode(
299 GrVideoMode *mp, GrVideoModeExt *ep,
300 GrVideoMode **mpp,GrVideoModeExt **epp
301 ){
302 if(*mpp < &modes[NUM_MODES]) {
303 if(!mp->extinfo) {
304 GrVideoModeExt *etp = &exts[0];
305 while(etp < *epp) {
306 if(memcmp(etp,ep,sizeof(GrVideoModeExt)) == 0) {
307 mp->extinfo = etp;
308 break;
309 }
310 etp++;
311 }
312 if(!mp->extinfo) {
313 if(etp >= &exts[NUM_EXTS]) return;
314 sttcopy(etp,ep);
315 mp->extinfo = etp;
316 *epp = ++etp;
317 }
318 }
319 sttcopy(*mpp,mp);
320 (*mpp)++;
321 }
322 }
323
get_tweaked_text_mode(GrVideoMode * mp,GrVideoMode * etable)324 static int get_tweaked_text_mode(GrVideoMode *mp,GrVideoMode *etable)
325 {
326 if(etable < &modes[NUM_MODES]) {
327 GrVideoMode *m1,*m2;
328 for(m1 = modes; m1 < etable; m1++) {
329 if((m1->present) &&
330 (m1->extinfo) &&
331 (m1->extinfo->mode == GR_frameText) &&
332 (m1->height == 25) &&
333 (m1->width > 80)) {
334 VESAmodeInfoBlock mdinfo;
335 if((_GrViDrvVESAgetModeInfo(m1->mode,&mdinfo)) &&
336 (mdinfo.ModeAttributes & MODE_EXTINFO) &&
337 (mdinfo.YCharSize == 16)) {
338 int h,exists = FALSE;
339 for(h = 28; h <= 50; h += (50 - 28)) {
340 for(m2 = modes; m2 < etable; m2++) {
341 if((m2->present) &&
342 (m2->extinfo) &&
343 (m2->extinfo->mode == GR_frameText) &&
344 (m2->height == h) &&
345 (m2->width == m1->width) &&
346 (m2->bpp == m1->bpp)) {
347 exists = TRUE;
348 break;
349 }
350 }
351 if(!exists) {
352 sttcopy(mp,m1);
353 mp->height = h;
354 mp->extinfo = &_GrViDrvEGAVGAcustomTextModeExt;
355 return(TRUE);
356 }
357 }
358 }
359 }
360 }
361 }
362 return(FALSE);
363 }
364
365 /* This code will fail if the controller is not VGA compatible.
366 ** One should get the VESA info first and check the Capability
367 ** flags for VGA base controller. If not VGA based all functions
368 ** must use BIOS calls (eg. DAC programming), no tweaked modes,
369 ** don't inherit EGA/VGA modes
370 ** Don't know if (and how) this should be done (hsc 970710) */
init(char * options)371 static int init(char *options)
372 {
373 DBGPRINTF(DBG_DRIVER,("options: \"%s\"\n",options));
374 if(_GrViDrvInitEGAVGA(options)) {
375 VESAvgaInfoBlock blk;
376 memzero(modes,sizeof(modes));
377 memzero(exts,sizeof(exts));
378 nexts = 0;
379 if(_GrViDrvVESAgetVGAinfo(&blk)) {
380 VESAmodeInfoBlock mdinfo;
381 GrVideoMode mode,*modep = &modes[0];
382 GrVideoModeExt ext, *extp = &exts[0];
383 short far *mp;
384 VRAMsize = blk.MemorySize;
385 VRAMsize <<= 16;
386 _GrVidDrvVESAflags = 0;
387 _GrVidDrvVESAbanksft = (-1);
388 VESAversion = blk.VESAversion;
389 DBGPRINTF(DBG_DRIVER,("VESAversion = %d.%d\n",
390 VESA_VERSION_MAJOR(VESAversion),
391 VESA_VERSION_MINOR(VESAversion) ));
392 DBGPRINTF(DBG_DRIVER,("VRAMsize = %lu bytes\n", VRAMsize));
393 if(options) while(*options != '\0') {
394 switch(*options) {
395 case '5':
396 _GrVidDrvVESAflags |= HICOLOR32K;
397 DBGPRINTF(DBG_DRIVER,("option '5': setting HICOLOR32K\n"));
398 break;
399 case 'p':
400 case 'P':
401 DBGPRINTF(DBG_DRIVER,("option 'p': setting PROTBANKING\n"));
402 _GrVidDrvVESAflags |= PROTBANKING;
403 break;
404 case 'f':
405 case 'F':
406 fast256 = GR_VMODEF_FAST_SVGA8;
407 break;
408 case 'r':
409 case 'R':
410 _GrVidDrvVESAflags |= USE_REALMODE;
411 break;
412 case 'b':
413 case 'B':
414 _GrVidDrvVESAflags |= NOT_LINEAR;
415 break;
416 }
417 options++;
418 }
419 /* set up default banking function */
420 _SETRWBANKS = RM_setrwbanks;
421 _SETBANK = RM_setbank;
422 #ifdef HAVE_VBE2
423 /* Check out and set up VBE 2+ portected mode banking */
424 if ( !(_GrVidDrvVESAflags & USE_REALMODE) )
425 VBE2ProtMode();
426 #endif
427 /* Check for variable width DAC */
428 varDAC = (_GrVidDrvVESAflags & NO_8BIT_DAC) == 0
429 && (blk.Capabilities & CAP_DAC_WIDTH) != 0;
430 for(mp = blk.VideoModePtr; *mp != (-1); mp++) {
431 mode.mode = *mp;
432 if(!_GrViDrvVESAgetModeInfo(*mp,&mdinfo)) continue;
433 if(!(mdinfo.ModeAttributes & MODE_EXTINFO)) continue;
434 if(!build_video_mode(&mdinfo,&mode,&ext)) continue;
435 add_video_mode(&mode,&ext,&modep,&extp);
436 }
437 while(get_tweaked_text_mode(&mode,modep)) {
438 add_video_mode(&mode,&ext,&modep,&extp);
439 }
440 nexts = (int)(extp-exts);
441 }
442 return(TRUE);
443 }
444 return(FALSE);
445 }
446
447 GrVideoDriver _GrVideoDriverVESA = {
448 "VESA", /* name */
449 GR_VGA, /* adapter type */
450 &_GrVideoDriverSTDVGA, /* inherit modes from this driver */
451 modes, /* mode table */
452 itemsof(modes), /* # of modes */
453 detect, /* detection routine */
454 init, /* initialization routine */
455 reset, /* reset routine */
456 _gr_selectmode, /* standard mode select routine */
457 0 /* no additional capabilities */
458 };
459