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