FreeBASIC  0.91.0
gfx_vesa_core.c
Go to the documentation of this file.
1 /* common VESA VBE routines
2  * Partially based on Allegro src/dos/vesa.c
3  */
4 
5 #include "../fb_gfx.h"
6 #include "fb_gfx_dos.h"
7 #include <go32.h>
8 #include <sys/farptr.h>
9 
13 
14 static int detected = FALSE;
15 
17 {
18  unsigned short *p;
19  __dpmi_meminfo meminfo;
20 
22 
23  if( fb_dos.vesa_info.vbe_version < 0x200 )
24  return;
25 
26  fb_dos.regs.x.ax = VBE_PMODE;
27  fb_dos.regs.x.bx = VBE_PMODE_GET;
28  __dpmi_int( 0x10, &fb_dos.regs );
29  if( fb_dos.regs.x.ax != VBE_STATUS_OK )
30  return;
31 
32  fb_dos_vesa_pm_info = malloc( fb_dos.regs.x.cx );
33 
34  dosmemget( SEGOFF_TO_RM( fb_dos.regs.x.es, fb_dos.regs.x.di ), fb_dos.regs.x.cx, fb_dos_vesa_pm_info );
35 
36  if( fb_dos_vesa_pm_info->IOPrivInfo )
37  {
38  /* ports are always accessible; skip to memory */
39  p = (unsigned short *)((intptr_t)fb_dos_vesa_pm_info + fb_dos_vesa_pm_info->IOPrivInfo);
40  while( *p++ != 0xFFFF )
41  ;
42  if( *++p != 0xFFFF ) /* need to map memory? */
43  {
44  meminfo.address = *(intptr_t *)p;
45  meminfo.size = *(p + 2);
46 
47  if( __dpmi_physical_address_mapping( &meminfo ) != 0 )
48  return;
49 
50  fb_dos.vesa_mmio_linear = meminfo.address;
51 
52  __dpmi_lock_linear_region( &meminfo );
53 
54  fb_dos.vesa_mmio_sel = __dpmi_allocate_ldt_descriptors( 1 );
55  if( fb_dos.vesa_mmio_sel == -1 )
56  {
58  return;
59  }
60 
61  if( __dpmi_set_segment_base_address( fb_dos.vesa_mmio_sel, meminfo.address ) == -1 )
62  {
63  return;
64  }
65 
66  if( __dpmi_set_segment_limit( fb_dos.vesa_mmio_sel, MAX( meminfo.size - 1, 0xFFFF ) ) )
67  {
68  return;
69  }
70  }
71  }
72 
73  fb_dos_vesa_pm_bank_switcher = (intptr_t)fb_dos_vesa_pm_info + fb_dos_vesa_pm_info->setWindow;
74  fb_dos_vesa_pm_set_palette = (intptr_t)fb_dos_vesa_pm_info + fb_dos_vesa_pm_info->setPalette;
75 
77 }
78 
79 static int vesa_get_mode_info( int mode )
80 {
81  fb_hFarMemSet( _dos_ds, MASK_LINEAR( __tb ), 0, sizeof( VesaModeInfo ) );
82 
83  fb_dos.regs.x.ax = VBE_MODEINFO;
84  fb_dos.regs.x.di = RM_OFFSET( __tb );
85  fb_dos.regs.x.es = RM_SEGMENT( __tb );
86  fb_dos.regs.x.cx = mode;
87  __dpmi_int( 0x10, &fb_dos.regs );
88  if( fb_dos.regs.x.ax != VBE_STATUS_OK )
89  return -1;
90 
91  dosmemget( MASK_LINEAR( __tb ), sizeof(fb_dos.vesa_mode_info), &fb_dos.vesa_mode_info );
92  return 0;
93 }
94 
96 {
97  int mode_list[256];
98  int number_of_modes;
99  long mode_ptr;
100  int c;
102 
103  if( detected )
104  return;
105 
106  detected = TRUE;
107 
108  fb_dos.vesa_ok = FALSE;
109 
110  fb_hFarMemSet( _dos_ds, MASK_LINEAR( __tb ), 0, sizeof( VbeInfoBlock ) );
111  dosmemput( "VBE2", 4, MASK_LINEAR( __tb ) ); /* get VESA 2 info if available */
112 
113  fb_dos.regs.x.ax = VBE_INFO;
114  fb_dos.regs.x.di = RM_OFFSET( __tb );
115  fb_dos.regs.x.es = RM_SEGMENT( __tb );
116  __dpmi_int( 0x10, &fb_dos.regs );
117 
118  if( fb_dos.regs.x.ax != VBE_STATUS_OK )
119  {
120  return;
121  }
122 
123  dosmemget( MASK_LINEAR( __tb ), sizeof( VbeInfoBlock ), &fb_dos.vesa_info );
124 
125  if( strncmp( fb_dos.vesa_info.vbe_signature, "VESA", 4 ) != 0 )
126  {
127  return;
128  }
129 
130  fb_dos.vesa_ok = TRUE;
131 
132  /* get VESA modes */
134 
135  number_of_modes = 0;
136 
137  while( _farpeekw( _dos_ds, mode_ptr ) != 0xFFFF )
138  {
139  mode_list[number_of_modes] = _farpeekw( _dos_ds, mode_ptr );
140  number_of_modes++;
141  mode_ptr += 2;
142  }
143 
144  fb_dos.num_vesa_modes = number_of_modes;
145 
146  fb_dos.vesa_modes = malloc( number_of_modes * sizeof(VesaModeInfo) );
147 
148  for( c = 0; c < number_of_modes; c++ )
149  {
150  if ( (vesa_get_mode_info(mode_list[c]) == 0) &&
151  ((fb_dos.vesa_mode_info.ModeAttributes & attribs) == attribs) && /* color graphics mode and supported */
155  ((fb_dos.vesa_info.vbe_version < 0x200) ||
156  ((unsigned int)fb_dos.vesa_info.total_memory << 16 >=
158  {
159  /* clobber WinFuncPtr to hold mode number */
160  fb_dos.vesa_mode_info.WinFuncPtr = mode_list[c];
161 
162  /* add to list */
163  memcpy( &fb_dos.vesa_modes[c], &fb_dos.vesa_mode_info, sizeof(VesaModeInfo) );
164  }
165  }
166 }
167 
168 int fb_dos_vesa_set_mode( int w, int h, int depth, int linear )
169 {
170  int i, mode = 0;
171  int bpp;
172  int tries;
173  int good_bpp;
174  int success = 0;
175 
176  if( depth == 15 ) depth = 16;
177  if( depth == 24 ) depth = 32;
178 
179  for( tries = 0; tries <= 2; tries++ )
180  {
181  for( i = 0; i < fb_dos.num_vesa_modes; i++ )
182  {
183  if( (fb_dos.vesa_modes[i].XResolution == w) && (fb_dos.vesa_modes[i].YResolution == h) )
184  {
185  bpp = fb_dos.vesa_modes[i].BitsPerPixel;
186  if( tries == 0 )
187  {
188  good_bpp = (bpp == depth);
189  }
190  else if( tries == 1 )
191  {
192  good_bpp = (bpp == 24 && depth == 32) ||
193  (bpp == 15 && depth == 16);
194  }
195  else /*if( tries == 2 )*/
196  {
197  good_bpp = ((bpp == 24 || bpp == 32) && depth < 24) ||
198  ((bpp == 15 || bpp == 16) && depth < 15);
199  }
200 
201  if( good_bpp )
202  {
203  if ( !linear || (fb_dos.vesa_modes[i].ModeAttributes & VMI_MA_LFB) )
204  {
205  memcpy( &fb_dos.vesa_mode_info, &fb_dos.vesa_modes[i], sizeof(VesaModeInfo) );
206  mode = fb_dos.vesa_modes[i].WinFuncPtr;
207  break;
208  }
209  }
210  }
211  }
212 
213  if( !mode )
214  continue;
215 
216  fb_dos.regs.x.ax = VBE_SETMODE;
217  fb_dos.regs.x.bx = mode;
218 
219  if( linear )
220  {
221  fb_dos.regs.x.bx |= 0x4000;
222  }
223 
224  __dpmi_int( 0x10, &fb_dos.regs );
225  success = (fb_dos.regs.h.ah == 0);
226 
227  if( success )
228  {
229  break;
230  }
231  }
232 
233  if( success )
234  {
235  fb_dos.palbuf_seg = __dpmi_allocate_dos_memory( (256 * 4) >> 4, &fb_dos.palbuf_sel ); // FIXME
236  if( fb_dos.palbuf_seg == -1 )
237  {
239  return -1;
240  }
241  }
242 
243  return (success ? 0 : -1);
244 }
245 
246 int *fb_dos_vesa_fetch_modes(int depth, int *size)
247 {
248  int *modes;
249  int count, i;
250  int bpp;
251 
252  if (!fb_dos.detected) fb_dos_detect();
254 
255  modes = malloc(sizeof(VesaModeInfo) * fb_dos.num_vesa_modes);
256 
257  for( i = 0, count = 0; i < fb_dos.num_vesa_modes; i++ )
258  {
259  if( fb_dos.vesa_modes[i].XResolution != 0 )
260  {
261  bpp = fb_dos.vesa_modes[i].BitsPerPixel;
262  if( (bpp == depth) ||
263  (bpp == 15 && depth == 16) ||
264  (bpp == 16 && depth == 15) ||
265  (bpp == 24 && depth == 32) ||
266  (bpp == 32 && depth == 24) )
267  {
269  }
270  }
271  }
272  *size = count;
273  return modes;
274 }
275 
277 {
278  int color_count;
279 
280  color_count = MIN( (1 << fb_dos.depth), fb_dos.pal_last - fb_dos.pal_first + 1 );
281 
282  movedata( _my_ds( ), (unsigned)fb_dos.pal, fb_dos.palbuf_sel, fb_dos.pal_first * 4, color_count * 4 );
283 
284  fb_dos.regs.x.ax = VBE_SETGETPAL;
288  fb_dos.regs.x.cx = color_count;
289  fb_dos.regs.x.dx = fb_dos.pal_first;
290 
291  fb_dos.regs.x.es = fb_dos.palbuf_seg;
292  fb_dos.regs.x.di = 0;
293 
294  __dpmi_int( 0x10, &fb_dos.regs );
295 
296  if( fb_dos.regs.x.ax != VBE_STATUS_OK )
297  {
300  return;
301  }
302 
304  fb_dos.pal_last = 0;
305  fb_dos.pal_first = 256;
306 }
307 
308 #if 0
309 /* !!!FIXME!!! */
310 
311 static void fb_dos_vesa_set_palette_pm(void)
312 {
313  int color_count;
314  unsigned short data_sel;
315 
316  data_sel = fb_dos.vesa_mmio_sel ? fb_dos.vesa_mmio_sel : _my_ds();
317 
318  color_count = MIN( (1 << fb_dos.depth), fb_dos.pal_last - fb_dos.pal_first + 1 );
319 
320  __asm__ __volatile__ (
321  "pushw %%ds \n\t"
322  "movw %1, %%ds \n\t"
323  "call *%0 \n\t"
324  "popw %%ds \n\t"
325  :
327  "m"(data_sel),
328  "a"(VBE_SETGETPAL), /* ax = 4F09h (set/get palette data) */
331  : VBE_SETGETPAL_SET), /* bl = 00h (set) or 80h (wait for blank and set) */
332  "c"(color_count), /* cx = number of entries to update */
333  "d"(fb_dos.pal_first), /* dx = first entry to update */
334  "D"(fb_dos.pal + fb_dos.pal_first) /* edi = table of palette values */
335  : "cc"
336  );
337 
339  fb_dos.pal_last = 0;
340  fb_dos.pal_first = 256;
341 }
342 
343 #endif
344 
346 {
348  fb_dos.set_palette( );
349 }