Mercurial > sdl-ios-xcode
annotate src/video/fbcon/SDL_fbvideo.c @ 6:332f458469f0
Fixed 320x200 video mode on framebuffer console
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 26 Apr 2001 17:05:23 +0000 |
parents | 74212992fb08 |
children | e85e03f195b4 |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this library; if not, write to the Free | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Sam Lantinga | |
20 slouken@devolution.com | |
21 */ | |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 /* Framebuffer console based SDL video driver implementation. | |
29 */ | |
30 | |
31 #include <stdlib.h> | |
32 #include <stdio.h> | |
33 #include <string.h> | |
34 #include <fcntl.h> | |
35 #include <unistd.h> | |
36 #include <sys/ioctl.h> | |
37 #include <sys/mman.h> | |
38 #include <asm/page.h> /* For definition of PAGE_SIZE */ | |
39 | |
40 #include "SDL.h" | |
41 #include "SDL_error.h" | |
42 #include "SDL_video.h" | |
43 #include "SDL_mouse.h" | |
44 #include "SDL_sysvideo.h" | |
45 #include "SDL_pixels_c.h" | |
46 #include "SDL_events_c.h" | |
47 #include "SDL_fbvideo.h" | |
48 #include "SDL_fbmouse_c.h" | |
49 #include "SDL_fbevents_c.h" | |
50 #include "SDL_fb3dfx.h" | |
51 #include "SDL_fbmatrox.h" | |
52 | |
53 #if defined(i386) && defined(FB_TYPE_VGA_PLANES) | |
54 #define VGA16_FBCON_SUPPORT | |
55 #ifndef FB_AUX_VGA_PLANES_VGA4 | |
56 #define FB_AUX_VGA_PLANES_VGA4 0 | |
57 #endif | |
58 static inline void outb (unsigned char value, unsigned short port) | |
59 { | |
60 __asm__ __volatile__ ("outb %b0,%w1"::"a" (value), "Nd" (port)); | |
61 } | |
62 #endif /* FB_TYPE_VGA_PLANES */ | |
63 | |
64 /* A list of video resolutions that we query for (sorted largest to smallest) */ | |
65 static SDL_Rect checkres[] = { | |
66 { 0, 0, 1600, 1200 }, /* 16 bpp: 0x11E, or 286 */ | |
67 { 0, 0, 1408, 1056 }, /* 16 bpp: 0x19A, or 410 */ | |
68 { 0, 0, 1280, 1024 }, /* 16 bpp: 0x11A, or 282 */ | |
69 { 0, 0, 1152, 864 }, /* 16 bpp: 0x192, or 402 */ | |
70 { 0, 0, 1024, 768 }, /* 16 bpp: 0x117, or 279 */ | |
71 { 0, 0, 960, 720 }, /* 16 bpp: 0x18A, or 394 */ | |
72 { 0, 0, 800, 600 }, /* 16 bpp: 0x114, or 276 */ | |
73 { 0, 0, 768, 576 }, /* 16 bpp: 0x182, or 386 */ | |
74 { 0, 0, 640, 480 }, /* 16 bpp: 0x111, or 273 */ | |
75 { 0, 0, 640, 400 }, /* 8 bpp: 0x100, or 256 */ | |
76 { 0, 0, 512, 384 }, | |
77 { 0, 0, 320, 240 }, | |
78 { 0, 0, 320, 200 } | |
79 }; | |
80 static struct { | |
81 int xres; | |
82 int yres; | |
83 int pixclock; | |
84 int left; | |
85 int right; | |
86 int upper; | |
87 int lower; | |
88 int hslen; | |
89 int vslen; | |
90 int sync; | |
91 int vmode; | |
92 } vesa_timings[] = { | |
93 #ifdef USE_VESA_TIMINGS /* Only tested on Matrox Millenium I */ | |
94 { 640, 400, 39771, 48, 16, 39, 8, 96, 2, 2, 0 }, /* 70 Hz */ | |
95 { 640, 480, 39683, 48, 16, 33, 10, 96, 2, 0, 0 }, /* 60 Hz */ | |
96 { 768, 576, 26101, 144, 16, 28, 6, 112, 4, 0, 0 }, /* 60 Hz */ | |
97 { 800, 600, 24038, 144, 24, 28, 8, 112, 6, 0, 0 }, /* 60 Hz */ | |
98 { 960, 720, 17686, 144, 24, 28, 8, 112, 4, 0, 0 }, /* 60 Hz */ | |
99 { 1024, 768, 15386, 160, 32, 30, 4, 128, 4, 0, 0 }, /* 60 Hz */ | |
100 { 1152, 864, 12286, 192, 32, 30, 4, 128, 4, 0, 0 }, /* 60 Hz */ | |
101 { 1280, 1024, 9369, 224, 32, 32, 4, 136, 4, 0, 0 }, /* 60 Hz */ | |
102 { 1408, 1056, 8214, 256, 40, 32, 5, 144, 5, 0, 0 }, /* 60 Hz */ | |
103 { 1600, 1200,/*?*/0, 272, 48, 32, 5, 152, 5, 0, 0 }, /* 60 Hz */ | |
104 #else | |
105 /* You can generate these timings from your XF86Config file using | |
106 the 'modeline2fb' perl script included with the fbset package. | |
107 These timings were generated for Matrox Millenium I, 15" monitor. | |
108 */ | |
109 { 320, 200, 79440, 16, 16, 20, 4, 48, 1, 0, 2 }, /* 70 Hz */ | |
110 { 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0, 2 }, /* 72 Hz */ | |
111 { 512, 384, 49603, 48, 16, 16, 1, 64, 3, 0, 0 }, /* 78 Hz */ | |
112 { 640, 400, 31746, 96, 32, 41, 1, 64, 3, 2, 0 }, /* 85 Hz */ | |
113 { 640, 480, 31746, 120, 16, 16, 1, 64, 3, 0, 0 }, /* 75 Hz */ | |
114 { 768, 576, 26101, 144, 16, 28, 6, 112, 4, 0, 0 }, /* 60 Hz */ | |
115 { 800, 600, 20000, 64, 56, 23, 37, 120, 6, 3, 0 }, /* 72 Hz */ | |
116 { 960, 720, 17686, 144, 24, 28, 8, 112, 4, 0, 0 }, /* 60 Hz */ | |
117 { 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0, 0 }, /* 70 Hz */ | |
118 { 1152, 864, 12286, 192, 32, 30, 4, 128, 4, 0, 0 }, /* 60 Hz */ | |
119 { 1280, 1024, 9369, 224, 32, 32, 4, 136, 4, 0, 0 }, /* 60 Hz */ | |
120 { 1408, 1056, 8214, 256, 40, 32, 5, 144, 5, 0, 0 }, /* 60 Hz */ | |
121 { 1600, 1200,/*?*/0, 272, 48, 32, 5, 152, 5, 0, 0 }, /* 60 Hz */ | |
122 #endif | |
123 }; | |
124 | |
125 /* Initialization/Query functions */ | |
126 static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat); | |
127 static SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); | |
128 static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); | |
129 #ifdef VGA16_FBCON_SUPPORT | |
130 static SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); | |
131 #endif | |
132 static int FB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors); | |
133 static void FB_VideoQuit(_THIS); | |
134 | |
135 /* Hardware surface functions */ | |
136 static int FB_InitHWSurfaces(_THIS, char *base, int size); | |
137 static void FB_FreeHWSurfaces(_THIS); | |
138 static int FB_AllocHWSurface(_THIS, SDL_Surface *surface); | |
139 static int FB_LockHWSurface(_THIS, SDL_Surface *surface); | |
140 static void FB_UnlockHWSurface(_THIS, SDL_Surface *surface); | |
141 static void FB_FreeHWSurface(_THIS, SDL_Surface *surface); | |
142 static void FB_WaitVBL(_THIS); | |
143 static int FB_FlipHWSurface(_THIS, SDL_Surface *surface); | |
144 | |
145 /* Internal palette functions */ | |
146 static void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo, | |
147 struct fb_var_screeninfo *vinfo); | |
148 static void FB_RestorePalette(_THIS); | |
149 | |
150 /* FB driver bootstrap functions */ | |
151 | |
152 static int FB_Available(void) | |
153 { | |
154 int console; | |
155 const char *SDL_fbdev; | |
156 | |
157 SDL_fbdev = getenv("SDL_FBDEV"); | |
158 if ( SDL_fbdev == NULL ) { | |
159 SDL_fbdev = "/dev/fb0"; | |
160 } | |
161 console = open(SDL_fbdev, O_RDWR, 0); | |
162 if ( console >= 0 ) { | |
163 close(console); | |
164 } | |
165 return(console >= 0); | |
166 } | |
167 | |
168 static void FB_DeleteDevice(SDL_VideoDevice *device) | |
169 { | |
170 free(device->hidden); | |
171 free(device); | |
172 } | |
173 | |
174 static SDL_VideoDevice *FB_CreateDevice(int devindex) | |
175 { | |
176 SDL_VideoDevice *this; | |
177 | |
178 /* Initialize all variables that we clean on shutdown */ | |
179 this = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice)); | |
180 if ( this ) { | |
181 memset(this, 0, (sizeof *this)); | |
182 this->hidden = (struct SDL_PrivateVideoData *) | |
183 malloc((sizeof *this->hidden)); | |
184 } | |
185 if ( (this == NULL) || (this->hidden == NULL) ) { | |
186 SDL_OutOfMemory(); | |
187 if ( this ) { | |
188 free(this); | |
189 } | |
190 return(0); | |
191 } | |
192 memset(this->hidden, 0, (sizeof *this->hidden)); | |
193 wait_vbl = FB_WaitVBL; | |
194 mouse_fd = -1; | |
195 keyboard_fd = -1; | |
196 | |
197 /* Set the function pointers */ | |
198 this->VideoInit = FB_VideoInit; | |
199 this->ListModes = FB_ListModes; | |
200 this->SetVideoMode = FB_SetVideoMode; | |
201 this->SetColors = FB_SetColors; | |
202 this->UpdateRects = NULL; | |
203 this->VideoQuit = FB_VideoQuit; | |
204 this->AllocHWSurface = FB_AllocHWSurface; | |
205 this->CheckHWBlit = NULL; | |
206 this->FillHWRect = NULL; | |
207 this->SetHWColorKey = NULL; | |
208 this->SetHWAlpha = NULL; | |
209 this->LockHWSurface = FB_LockHWSurface; | |
210 this->UnlockHWSurface = FB_UnlockHWSurface; | |
211 this->FlipHWSurface = FB_FlipHWSurface; | |
212 this->FreeHWSurface = FB_FreeHWSurface; | |
213 this->SetCaption = NULL; | |
214 this->SetIcon = NULL; | |
215 this->IconifyWindow = NULL; | |
216 this->GrabInput = NULL; | |
217 this->GetWMInfo = NULL; | |
218 this->InitOSKeymap = FB_InitOSKeymap; | |
219 this->PumpEvents = FB_PumpEvents; | |
220 | |
221 this->free = FB_DeleteDevice; | |
222 | |
223 return this; | |
224 } | |
225 | |
226 VideoBootStrap FBCON_bootstrap = { | |
227 "fbcon", "Linux Framebuffer Console", | |
228 FB_Available, FB_CreateDevice | |
229 }; | |
230 | |
231 static int FB_CheckMode(_THIS, struct fb_var_screeninfo *vinfo, | |
232 int index, unsigned int *w, unsigned int *h) | |
233 { | |
234 int mode_okay; | |
235 | |
236 mode_okay = 0; | |
237 vinfo->bits_per_pixel = (index+1)*8; | |
238 vinfo->xres = *w; | |
239 vinfo->xres_virtual = *w; | |
240 vinfo->yres = *h; | |
241 vinfo->yres_virtual = *h; | |
242 vinfo->activate = FB_ACTIVATE_TEST; | |
243 if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, vinfo) == 0 ) { | |
244 #ifdef FBCON_DEBUG | |
245 fprintf(stderr, "Checked mode %dx%d at %d bpp, got mode %dx%d at %d bpp\n", *w, *h, (index+1)*8, vinfo->xres, vinfo->yres, vinfo->bits_per_pixel); | |
246 #endif | |
247 if ( (((vinfo->bits_per_pixel+7)/8)-1) == index ) { | |
248 *w = vinfo->xres; | |
249 *h = vinfo->yres; | |
250 mode_okay = 1; | |
251 } | |
252 } | |
253 return mode_okay; | |
254 } | |
255 | |
256 static int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h) | |
257 { | |
258 SDL_Rect *mode; | |
259 int i; | |
260 int next_mode; | |
261 | |
262 /* Check to see if we already have this mode */ | |
263 if ( SDL_nummodes[index] > 0 ) { | |
264 mode = SDL_modelist[index][SDL_nummodes[index]-1]; | |
265 if ( (mode->w == w) && (mode->h == h) ) { | |
266 #ifdef FBCON_DEBUG | |
267 fprintf(stderr, "We already have mode %dx%d at %d bytes per pixel\n", w, h, index+1); | |
268 #endif | |
269 return(0); | |
270 } | |
271 } | |
272 | |
273 /* Only allow a mode if we have a valid timing for it */ | |
6
332f458469f0
Fixed 320x200 video mode on framebuffer console
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
274 next_mode = -1; |
0 | 275 for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) { |
276 if ( (w == vesa_timings[i].xres) && | |
277 (h == vesa_timings[i].yres) && vesa_timings[i].pixclock ) { | |
278 next_mode = i; | |
279 break; | |
280 } | |
281 } | |
6
332f458469f0
Fixed 320x200 video mode on framebuffer console
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
282 if ( next_mode == -1 ) { |
0 | 283 #ifdef FBCON_DEBUG |
284 fprintf(stderr, "No valid timing line for mode %dx%d\n", w, h); | |
285 #endif | |
286 return(0); | |
287 } | |
288 | |
289 /* Set up the new video mode rectangle */ | |
290 mode = (SDL_Rect *)malloc(sizeof *mode); | |
291 if ( mode == NULL ) { | |
292 SDL_OutOfMemory(); | |
293 return(-1); | |
294 } | |
295 mode->x = 0; | |
296 mode->y = 0; | |
297 mode->w = w; | |
298 mode->h = h; | |
299 #ifdef FBCON_DEBUG | |
300 fprintf(stderr, "Adding mode %dx%d at %d bytes per pixel\n", w, h, index+1); | |
301 #endif | |
302 | |
303 /* Allocate the new list of modes, and fill in the new mode */ | |
304 next_mode = SDL_nummodes[index]; | |
305 SDL_modelist[index] = (SDL_Rect **) | |
306 realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *)); | |
307 if ( SDL_modelist[index] == NULL ) { | |
308 SDL_OutOfMemory(); | |
309 SDL_nummodes[index] = 0; | |
310 free(mode); | |
311 return(-1); | |
312 } | |
313 SDL_modelist[index][next_mode] = mode; | |
314 SDL_modelist[index][next_mode+1] = NULL; | |
315 SDL_nummodes[index]++; | |
316 | |
317 return(0); | |
318 } | |
319 | |
320 static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat) | |
321 { | |
322 struct fb_fix_screeninfo finfo; | |
323 struct fb_var_screeninfo vinfo; | |
324 int i, j; | |
325 int current_index; | |
326 unsigned int current_w; | |
327 unsigned int current_h; | |
328 const char *SDL_fbdev; | |
329 | |
330 /* Initialize the library */ | |
331 SDL_fbdev = getenv("SDL_FBDEV"); | |
332 if ( SDL_fbdev == NULL ) { | |
333 SDL_fbdev = "/dev/fb0"; | |
334 } | |
335 console_fd = open(SDL_fbdev, O_RDWR, 0); | |
336 if ( console_fd < 0 ) { | |
337 SDL_SetError("Unable to open %s", SDL_fbdev); | |
338 return(-1); | |
339 } | |
340 | |
341 #ifndef DISABLE_THREADS | |
342 /* Create the hardware surface lock mutex */ | |
343 hw_lock = SDL_CreateMutex(); | |
344 if ( hw_lock == NULL ) { | |
345 SDL_SetError("Unable to create lock mutex"); | |
346 FB_VideoQuit(this); | |
347 return(-1); | |
348 } | |
349 #endif | |
350 | |
351 /* Get the type of video hardware */ | |
352 if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) { | |
353 SDL_SetError("Couldn't get console hardware info"); | |
354 FB_VideoQuit(this); | |
355 return(-1); | |
356 } | |
357 switch (finfo.type) { | |
358 case FB_TYPE_PACKED_PIXELS: | |
359 /* Supported, no worries.. */ | |
360 break; | |
361 #ifdef VGA16_FBCON_SUPPORT | |
362 case FB_TYPE_VGA_PLANES: | |
363 /* VGA16 is supported, but that's it */ | |
364 if ( finfo.type_aux == FB_AUX_VGA_PLANES_VGA4 ) { | |
365 if ( ioperm(0x3b4, 0x3df - 0x3b4 + 1, 1) < 0 ) { | |
366 SDL_SetError("No I/O port permissions"); | |
367 FB_VideoQuit(this); | |
368 return(-1); | |
369 } | |
370 this->SetVideoMode = FB_SetVGA16Mode; | |
371 break; | |
372 } | |
373 /* Fall through to unsupported case */ | |
374 #endif /* VGA16_FBCON_SUPPORT */ | |
375 default: | |
376 SDL_SetError("Unsupported console hardware"); | |
377 FB_VideoQuit(this); | |
378 return(-1); | |
379 } | |
380 switch (finfo.visual) { | |
381 case FB_VISUAL_TRUECOLOR: | |
382 case FB_VISUAL_PSEUDOCOLOR: | |
383 case FB_VISUAL_STATIC_PSEUDOCOLOR: | |
384 case FB_VISUAL_DIRECTCOLOR: | |
385 break; | |
386 default: | |
387 SDL_SetError("Unsupported console hardware"); | |
388 FB_VideoQuit(this); | |
389 return(-1); | |
390 } | |
391 | |
392 /* Check if the user wants to disable hardware acceleration */ | |
393 { const char *fb_accel; | |
394 fb_accel = getenv("SDL_FBACCEL"); | |
395 if ( fb_accel ) { | |
396 finfo.accel = atoi(fb_accel); | |
397 } | |
398 } | |
399 | |
400 /* Memory map the device, compensating for buggy PPC mmap() */ | |
401 mapped_offset = (((long)finfo.smem_start) - | |
402 (((long)finfo.smem_start)&~(PAGE_SIZE-1))); | |
403 mapped_memlen = finfo.smem_len+mapped_offset; | |
404 mapped_mem = mmap(NULL, mapped_memlen, | |
405 PROT_READ|PROT_WRITE, MAP_SHARED, console_fd, 0); | |
406 if ( mapped_mem == (char *)-1 ) { | |
407 SDL_SetError("Unable to memory map the video hardware"); | |
408 mapped_mem = NULL; | |
409 FB_VideoQuit(this); | |
410 return(-1); | |
411 } | |
412 | |
413 /* Determine the current screen depth */ | |
414 if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) { | |
415 SDL_SetError("Couldn't get console pixel format"); | |
416 FB_VideoQuit(this); | |
417 return(-1); | |
418 } | |
419 vformat->BitsPerPixel = vinfo.bits_per_pixel; | |
420 if ( vformat->BitsPerPixel < 8 ) { | |
421 /* Assuming VGA16, we handle this via a shadow framebuffer */ | |
422 vformat->BitsPerPixel = 8; | |
423 } | |
424 for ( i=0; i<vinfo.red.length; ++i ) { | |
425 vformat->Rmask <<= 1; | |
426 vformat->Rmask |= (0x00000001<<vinfo.red.offset); | |
427 } | |
428 for ( i=0; i<vinfo.green.length; ++i ) { | |
429 vformat->Gmask <<= 1; | |
430 vformat->Gmask |= (0x00000001<<vinfo.green.offset); | |
431 } | |
432 for ( i=0; i<vinfo.blue.length; ++i ) { | |
433 vformat->Bmask <<= 1; | |
434 vformat->Bmask |= (0x00000001<<vinfo.blue.offset); | |
435 } | |
436 saved_vinfo = vinfo; | |
437 | |
438 /* Save hardware palette, if needed */ | |
439 FB_SavePalette(this, &finfo, &vinfo); | |
440 | |
441 /* If the I/O registers are available, memory map them so we | |
442 can take advantage of any supported hardware acceleration. | |
443 */ | |
444 vinfo.accel_flags = 0; /* Temporarily reserve registers */ | |
445 ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo); | |
446 if ( finfo.accel && finfo.mmio_len ) { | |
447 mapped_iolen = finfo.mmio_len; | |
448 mapped_io = mmap(NULL, mapped_iolen, PROT_READ|PROT_WRITE, | |
449 MAP_SHARED, console_fd, mapped_memlen); | |
450 if ( mapped_io == (char *)-1 ) { | |
451 /* Hmm, failed to memory map I/O registers */ | |
452 mapped_io = NULL; | |
453 } | |
454 } | |
455 | |
456 /* Query for the list of available video modes */ | |
457 current_w = vinfo.xres; | |
458 current_h = vinfo.yres; | |
459 current_index = ((vinfo.bits_per_pixel+7)/8)-1; | |
460 for ( i=0; i<NUM_MODELISTS; ++i ) { | |
461 SDL_nummodes[i] = 0; | |
462 SDL_modelist[i] = NULL; | |
463 for ( j=0; j<(sizeof(checkres)/sizeof(checkres[0])); ++j ) { | |
464 unsigned int w, h; | |
465 | |
466 /* See if we are querying for the current mode */ | |
467 w = checkres[j].w; | |
468 h = checkres[j].h; | |
469 if ( i == current_index ) { | |
470 if ( (current_w > w) || (current_h > h) ) { | |
471 /* Only check once */ | |
472 FB_AddMode(this, i,current_w,current_h); | |
473 current_index = -1; | |
474 } | |
475 } | |
476 if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) { | |
477 FB_AddMode(this, i, w, h); | |
478 } | |
479 } | |
480 } | |
481 | |
482 /* Fill in our hardware acceleration capabilities */ | |
483 this->info.wm_available = 0; | |
484 this->info.hw_available = 1; | |
485 this->info.video_mem = finfo.smem_len/1024; | |
486 if ( mapped_io ) { | |
487 switch (finfo.accel) { | |
488 case FB_ACCEL_MATROX_MGA2064W: | |
489 case FB_ACCEL_MATROX_MGA1064SG: | |
490 case FB_ACCEL_MATROX_MGA2164W: | |
491 case FB_ACCEL_MATROX_MGA2164W_AGP: | |
492 case FB_ACCEL_MATROX_MGAG100: | |
493 /*case FB_ACCEL_MATROX_MGAG200: G200 acceleration broken! */ | |
494 case FB_ACCEL_MATROX_MGAG400: | |
495 #ifdef FBACCEL_DEBUG | |
496 printf("Matrox hardware accelerator!\n"); | |
497 #endif | |
498 FB_MatroxAccel(this, finfo.accel); | |
499 break; | |
500 case FB_ACCEL_3DFX_BANSHEE: | |
501 #ifdef FBACCEL_DEBUG | |
502 printf("3DFX hardware accelerator!\n"); | |
503 #endif | |
504 FB_3DfxAccel(this, finfo.accel); | |
505 break; | |
506 default: | |
507 #ifdef FBACCEL_DEBUG | |
508 printf("Unknown hardware accelerator.\n"); | |
509 #endif | |
510 break; | |
511 } | |
512 } | |
513 | |
514 /* Enable mouse and keyboard support */ | |
515 if ( FB_OpenKeyboard(this) < 0 ) { | |
516 FB_VideoQuit(this); | |
517 return(-1); | |
518 } | |
519 if ( FB_OpenMouse(this) < 0 ) { | |
520 const char *sdl_nomouse; | |
521 | |
522 sdl_nomouse = getenv("SDL_NOMOUSE"); | |
523 if ( ! sdl_nomouse ) { | |
524 SDL_SetError("Unable to open mouse"); | |
525 FB_VideoQuit(this); | |
526 return(-1); | |
527 } | |
528 } | |
529 | |
530 /* We're done! */ | |
531 return(0); | |
532 } | |
533 | |
534 static SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) | |
535 { | |
536 return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]); | |
537 } | |
538 | |
539 /* Various screen update functions available */ | |
540 static void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects); | |
541 #ifdef VGA16_FBCON_SUPPORT | |
542 static void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects); | |
543 #endif | |
544 | |
545 #ifdef FBCON_DEBUG | |
546 static void print_vinfo(struct fb_var_screeninfo *vinfo) | |
547 { | |
548 fprintf(stderr, "Printing vinfo:\n"); | |
549 fprintf(stderr, "\txres: %d\n", vinfo->xres); | |
550 fprintf(stderr, "\tyres: %d\n", vinfo->yres); | |
551 fprintf(stderr, "\txres_virtual: %d\n", vinfo->xres_virtual); | |
552 fprintf(stderr, "\tyres_virtual: %d\n", vinfo->yres_virtual); | |
553 fprintf(stderr, "\txoffset: %d\n", vinfo->xoffset); | |
554 fprintf(stderr, "\tyoffset: %d\n", vinfo->yoffset); | |
555 fprintf(stderr, "\tbits_per_pixel: %d\n", vinfo->bits_per_pixel); | |
556 fprintf(stderr, "\tgrayscale: %d\n", vinfo->grayscale); | |
557 fprintf(stderr, "\tnonstd: %d\n", vinfo->nonstd); | |
558 fprintf(stderr, "\tactivate: %d\n", vinfo->activate); | |
559 fprintf(stderr, "\theight: %d\n", vinfo->height); | |
560 fprintf(stderr, "\twidth: %d\n", vinfo->width); | |
561 fprintf(stderr, "\taccel_flags: %d\n", vinfo->accel_flags); | |
562 fprintf(stderr, "\tpixclock: %d\n", vinfo->pixclock); | |
563 fprintf(stderr, "\tleft_margin: %d\n", vinfo->left_margin); | |
564 fprintf(stderr, "\tright_margin: %d\n", vinfo->right_margin); | |
565 fprintf(stderr, "\tupper_margin: %d\n", vinfo->upper_margin); | |
566 fprintf(stderr, "\tlower_margin: %d\n", vinfo->lower_margin); | |
567 fprintf(stderr, "\thsync_len: %d\n", vinfo->hsync_len); | |
568 fprintf(stderr, "\tvsync_len: %d\n", vinfo->vsync_len); | |
569 fprintf(stderr, "\tsync: %d\n", vinfo->sync); | |
570 fprintf(stderr, "\tvmode: %d\n", vinfo->vmode); | |
571 fprintf(stderr, "\tred: %d/%d\n", vinfo->red.length, vinfo->red.offset); | |
572 fprintf(stderr, "\tgreen: %d/%d\n", vinfo->green.length, vinfo->green.offset); | |
573 fprintf(stderr, "\tblue: %d/%d\n", vinfo->blue.length, vinfo->blue.offset); | |
574 fprintf(stderr, "\talpha: %d/%d\n", vinfo->transp.length, vinfo->transp.offset); | |
575 } | |
576 static void print_finfo(struct fb_fix_screeninfo *finfo) | |
577 { | |
578 fprintf(stderr, "Printing finfo:\n"); | |
579 fprintf(stderr, "\tsmem_start = %p\n", (char *)finfo->smem_start); | |
580 fprintf(stderr, "\tsmem_len = %d\n", finfo->smem_len); | |
581 fprintf(stderr, "\ttype = %d\n", finfo->type); | |
582 fprintf(stderr, "\ttype_aux = %d\n", finfo->type_aux); | |
583 fprintf(stderr, "\tvisual = %d\n", finfo->visual); | |
584 fprintf(stderr, "\txpanstep = %d\n", finfo->xpanstep); | |
585 fprintf(stderr, "\typanstep = %d\n", finfo->ypanstep); | |
586 fprintf(stderr, "\tywrapstep = %d\n", finfo->ywrapstep); | |
587 fprintf(stderr, "\tline_length = %d\n", finfo->line_length); | |
588 fprintf(stderr, "\tmmio_start = %p\n", (char *)finfo->mmio_start); | |
589 fprintf(stderr, "\tmmio_len = %d\n", finfo->mmio_len); | |
590 fprintf(stderr, "\taccel = %d\n", finfo->accel); | |
591 } | |
592 #endif | |
593 | |
594 static int choose_fbmodes_mode(struct fb_var_screeninfo *vinfo) | |
595 { | |
596 int matched; | |
597 FILE *fbmodes; | |
598 | |
599 matched = 0; | |
600 fbmodes = fopen("/etc/fb.modes", "r"); | |
601 if ( fbmodes ) { | |
602 /* FIXME: Parse the mode definition file */ | |
603 fclose(fbmodes); | |
604 } | |
605 return(matched); | |
606 } | |
607 | |
608 static int choose_vesa_mode(struct fb_var_screeninfo *vinfo) | |
609 { | |
610 int matched; | |
611 int i; | |
612 | |
613 /* Check for VESA timings */ | |
614 matched = 0; | |
615 for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) { | |
616 if ( (vinfo->xres == vesa_timings[i].xres) && | |
617 (vinfo->yres == vesa_timings[i].yres) ) { | |
618 #ifdef FBCON_DEBUG | |
619 fprintf(stderr, "Using VESA timings for %dx%d\n", | |
620 vinfo->xres, vinfo->yres); | |
621 #endif | |
622 if ( vesa_timings[i].pixclock ) { | |
623 vinfo->pixclock = vesa_timings[i].pixclock; | |
624 } | |
625 vinfo->left_margin = vesa_timings[i].left; | |
626 vinfo->right_margin = vesa_timings[i].right; | |
627 vinfo->upper_margin = vesa_timings[i].upper; | |
628 vinfo->lower_margin = vesa_timings[i].lower; | |
629 vinfo->hsync_len = vesa_timings[i].hslen; | |
630 vinfo->vsync_len = vesa_timings[i].vslen; | |
631 vinfo->sync = vesa_timings[i].sync; | |
632 vinfo->vmode = vesa_timings[i].vmode; | |
633 matched = 1; | |
634 break; | |
635 } | |
636 } | |
637 return(matched); | |
638 } | |
639 | |
640 #ifdef VGA16_FBCON_SUPPORT | |
641 static SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current, | |
642 int width, int height, int bpp, Uint32 flags) | |
643 { | |
644 struct fb_fix_screeninfo finfo; | |
645 struct fb_var_screeninfo vinfo; | |
646 | |
647 /* Set the terminal into graphics mode */ | |
648 if ( FB_EnterGraphicsMode(this) < 0 ) { | |
649 return(NULL); | |
650 } | |
651 | |
652 /* Restore the original palette */ | |
653 FB_RestorePalette(this); | |
654 | |
655 /* Set the video mode and get the final screen format */ | |
656 if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) { | |
657 SDL_SetError("Couldn't get console screen info"); | |
658 return(NULL); | |
659 } | |
660 cache_vinfo = vinfo; | |
661 #ifdef FBCON_DEBUG | |
662 fprintf(stderr, "Printing actual vinfo:\n"); | |
663 print_vinfo(&vinfo); | |
664 #endif | |
665 if ( ! SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) { | |
666 return(NULL); | |
667 } | |
668 current->format->palette->ncolors = 16; | |
669 | |
670 /* Get the fixed information about the console hardware. | |
671 This is necessary since finfo.line_length changes. | |
672 */ | |
673 if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) { | |
674 SDL_SetError("Couldn't get console hardware info"); | |
675 return(NULL); | |
676 } | |
677 #ifdef FBCON_DEBUG | |
678 fprintf(stderr, "Printing actual finfo:\n"); | |
679 print_finfo(&finfo); | |
680 #endif | |
681 | |
682 /* Save hardware palette, if needed */ | |
683 FB_SavePalette(this, &finfo, &vinfo); | |
684 | |
685 /* Set up the new mode framebuffer */ | |
686 current->flags = SDL_FULLSCREEN; | |
687 current->w = vinfo.xres; | |
688 current->h = vinfo.yres; | |
689 current->pitch = current->w; | |
690 current->pixels = malloc(current->h*current->pitch); | |
691 | |
692 /* Set the update rectangle function */ | |
693 this->UpdateRects = FB_VGA16Update; | |
694 | |
695 /* We're done */ | |
696 return(current); | |
697 } | |
698 #endif /* VGA16_FBCON_SUPPORT */ | |
699 | |
700 static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current, | |
701 int width, int height, int bpp, Uint32 flags) | |
702 { | |
703 struct fb_fix_screeninfo finfo; | |
704 struct fb_var_screeninfo vinfo; | |
705 int i; | |
706 Uint32 Rmask; | |
707 Uint32 Gmask; | |
708 Uint32 Bmask; | |
709 char *surfaces_mem; | |
710 int surfaces_len; | |
711 | |
712 /* Set the terminal into graphics mode */ | |
713 if ( FB_EnterGraphicsMode(this) < 0 ) { | |
714 return(NULL); | |
715 } | |
716 | |
717 /* Restore the original palette */ | |
718 FB_RestorePalette(this); | |
719 | |
720 /* Set the video mode and get the final screen format */ | |
721 if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) { | |
722 SDL_SetError("Couldn't get console screen info"); | |
723 return(NULL); | |
724 } | |
725 #ifdef FBCON_DEBUG | |
726 fprintf(stderr, "Printing original vinfo:\n"); | |
727 print_vinfo(&vinfo); | |
728 #endif | |
729 if ( (vinfo.xres != width) || (vinfo.yres != height) || | |
730 (vinfo.bits_per_pixel != bpp) || (flags & SDL_DOUBLEBUF) ) { | |
731 vinfo.activate = FB_ACTIVATE_NOW; | |
732 vinfo.accel_flags = 0; | |
733 vinfo.bits_per_pixel = bpp; | |
734 vinfo.xres = width; | |
735 vinfo.xres_virtual = width; | |
736 vinfo.yres = height; | |
737 if ( flags & SDL_DOUBLEBUF ) { | |
738 vinfo.yres_virtual = height*2; | |
739 } else { | |
740 vinfo.yres_virtual = height; | |
741 } | |
742 vinfo.xoffset = 0; | |
743 vinfo.yoffset = 0; | |
744 vinfo.red.length = vinfo.red.offset = 0; | |
745 vinfo.green.length = vinfo.green.offset = 0; | |
746 vinfo.blue.length = vinfo.blue.offset = 0; | |
747 vinfo.transp.length = vinfo.transp.offset = 0; | |
748 if ( ! choose_fbmodes_mode(&vinfo) ) { | |
749 choose_vesa_mode(&vinfo); | |
750 } | |
751 #ifdef FBCON_DEBUG | |
752 fprintf(stderr, "Printing wanted vinfo:\n"); | |
753 print_vinfo(&vinfo); | |
754 #endif | |
755 if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) { | |
756 vinfo.yres_virtual = height; | |
757 if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) { | |
758 SDL_SetError("Couldn't set console screen info"); | |
759 return(NULL); | |
760 } | |
761 } | |
762 } | |
763 cache_vinfo = vinfo; | |
764 #ifdef FBCON_DEBUG | |
765 fprintf(stderr, "Printing actual vinfo:\n"); | |
766 print_vinfo(&vinfo); | |
767 #endif | |
768 Rmask = 0; | |
769 for ( i=0; i<vinfo.red.length; ++i ) { | |
770 Rmask <<= 1; | |
771 Rmask |= (0x00000001<<vinfo.red.offset); | |
772 } | |
773 Gmask = 0; | |
774 for ( i=0; i<vinfo.green.length; ++i ) { | |
775 Gmask <<= 1; | |
776 Gmask |= (0x00000001<<vinfo.green.offset); | |
777 } | |
778 Bmask = 0; | |
779 for ( i=0; i<vinfo.blue.length; ++i ) { | |
780 Bmask <<= 1; | |
781 Bmask |= (0x00000001<<vinfo.blue.offset); | |
782 } | |
783 if ( ! SDL_ReallocFormat(current, vinfo.bits_per_pixel, | |
784 Rmask, Gmask, Bmask, 0) ) { | |
785 return(NULL); | |
786 } | |
787 | |
788 /* Get the fixed information about the console hardware. | |
789 This is necessary since finfo.line_length changes. | |
790 */ | |
791 if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) { | |
792 SDL_SetError("Couldn't get console hardware info"); | |
793 return(NULL); | |
794 } | |
795 | |
796 /* Save hardware palette, if needed */ | |
797 FB_SavePalette(this, &finfo, &vinfo); | |
798 | |
799 /* Set up the new mode framebuffer */ | |
800 current->flags = (SDL_FULLSCREEN|SDL_HWSURFACE); | |
801 current->w = vinfo.xres; | |
802 current->h = vinfo.yres; | |
803 current->pitch = finfo.line_length; | |
804 current->pixels = mapped_mem+mapped_offset; | |
805 | |
806 /* Let the application know we have a hardware palette */ | |
807 switch (finfo.visual) { | |
808 case FB_VISUAL_PSEUDOCOLOR: | |
809 current->flags |= SDL_HWPALETTE; | |
810 break; | |
811 default: | |
812 break; | |
813 } | |
814 | |
815 /* Update for double-buffering, if we can */ | |
816 if ( flags & SDL_DOUBLEBUF ) { | |
817 if ( vinfo.yres_virtual == (height*2) ) { | |
818 current->flags |= SDL_DOUBLEBUF; | |
819 flip_page = 0; | |
820 flip_address[0] = (char *)current->pixels; | |
821 flip_address[1] = (char *)current->pixels+ | |
822 current->h*current->pitch; | |
823 FB_FlipHWSurface(this, current); | |
824 } | |
825 } | |
826 | |
827 /* Set up the information for hardware surfaces */ | |
828 surfaces_mem = (char *)current->pixels + | |
829 vinfo.yres_virtual*current->pitch; | |
830 surfaces_len = (mapped_memlen-(surfaces_mem-mapped_mem)); | |
831 FB_FreeHWSurfaces(this); | |
832 FB_InitHWSurfaces(this, surfaces_mem, surfaces_len); | |
833 | |
834 /* Set the update rectangle function */ | |
835 this->UpdateRects = FB_DirectUpdate; | |
836 | |
837 /* We're done */ | |
838 return(current); | |
839 } | |
840 | |
841 #ifdef FBCON_DEBUG | |
842 void FB_DumpHWSurfaces(_THIS) | |
843 { | |
844 vidmem_bucket *bucket; | |
845 | |
846 printf("Memory left: %d (%d total)\n", surfaces_memleft, surfaces_memtotal); | |
847 printf("\n"); | |
848 printf(" Base Size\n"); | |
849 for ( bucket=&surfaces; bucket; bucket=bucket->next ) { | |
850 printf("Bucket: %p, %d (%s)\n", bucket->base, bucket->size, bucket->used ? "used" : "free"); | |
851 if ( bucket->prev ) { | |
852 if ( bucket->base != bucket->prev->base+bucket->prev->size ) { | |
853 printf("Warning, corrupt bucket list! (prev)\n"); | |
854 } | |
855 } else { | |
856 if ( bucket != &surfaces ) { | |
857 printf("Warning, corrupt bucket list! (!prev)\n"); | |
858 } | |
859 } | |
860 if ( bucket->next ) { | |
861 if ( bucket->next->base != bucket->base+bucket->size ) { | |
862 printf("Warning, corrupt bucket list! (next)\n"); | |
863 } | |
864 } | |
865 } | |
866 printf("\n"); | |
867 } | |
868 #endif | |
869 | |
870 static int FB_InitHWSurfaces(_THIS, char *base, int size) | |
871 { | |
872 surfaces.prev = NULL; | |
873 surfaces.used = 0; | |
874 surfaces.base = base; | |
875 surfaces.size = size; | |
876 surfaces.next = NULL; | |
877 surfaces_memtotal = size; | |
878 surfaces_memleft = size; | |
879 return(0); | |
880 } | |
881 static void FB_FreeHWSurfaces(_THIS) | |
882 { | |
883 vidmem_bucket *bucket, *freeable; | |
884 | |
885 bucket = surfaces.next; | |
886 while ( bucket ) { | |
887 freeable = bucket; | |
888 bucket = bucket->next; | |
889 free(freeable); | |
890 } | |
891 surfaces.next = NULL; | |
892 } | |
893 | |
894 static int FB_AllocHWSurface(_THIS, SDL_Surface *surface) | |
895 { | |
896 vidmem_bucket *bucket; | |
897 int size; | |
898 int extra; | |
899 | |
900 /* Temporarily, we only allow surfaces the same width as display. | |
901 Some blitters require the pitch between two hardware surfaces | |
902 to be the same. Others have interesting alignment restrictions. | |
903 Until someone who knows these details looks at the code... | |
904 */ | |
905 if ( surface->pitch > SDL_VideoSurface->pitch ) { | |
906 SDL_SetError("Surface requested wider than screen"); | |
907 return(-1); | |
908 } | |
909 surface->pitch = SDL_VideoSurface->pitch; | |
910 size = surface->h * surface->pitch; | |
911 #ifdef FBCON_DEBUG | |
912 fprintf(stderr, "Allocating bucket of %d bytes\n", size); | |
913 #endif | |
914 | |
915 /* Quick check for available mem */ | |
916 if ( size > surfaces_memleft ) { | |
917 SDL_SetError("Not enough video memory"); | |
918 return(-1); | |
919 } | |
920 | |
921 /* Search for an empty bucket big enough */ | |
922 for ( bucket=&surfaces; bucket; bucket=bucket->next ) { | |
923 if ( ! bucket->used && (size <= bucket->size) ) { | |
924 break; | |
925 } | |
926 } | |
927 if ( bucket == NULL ) { | |
928 SDL_SetError("Video memory too fragmented"); | |
929 return(-1); | |
930 } | |
931 | |
932 /* Create a new bucket for left-over memory */ | |
933 extra = (bucket->size - size); | |
934 if ( extra ) { | |
935 vidmem_bucket *newbucket; | |
936 | |
937 #ifdef FBCON_DEBUG | |
938 fprintf(stderr, "Adding new free bucket of %d bytes\n", extra); | |
939 #endif | |
940 newbucket = (vidmem_bucket *)malloc(sizeof(*newbucket)); | |
941 if ( newbucket == NULL ) { | |
942 SDL_OutOfMemory(); | |
943 return(-1); | |
944 } | |
945 newbucket->prev = bucket; | |
946 newbucket->used = 0; | |
947 newbucket->base = bucket->base+size; | |
948 newbucket->size = extra; | |
949 newbucket->next = bucket->next; | |
950 if ( bucket->next ) { | |
951 bucket->next->prev = newbucket; | |
952 } | |
953 bucket->next = newbucket; | |
954 } | |
955 | |
956 /* Set the current bucket values and return it! */ | |
957 bucket->used = 1; | |
958 bucket->size = size; | |
959 #ifdef FBCON_DEBUG | |
960 fprintf(stderr, "Allocated %d bytes at %p\n", bucket->size, bucket->base); | |
961 #endif | |
962 surfaces_memleft -= size; | |
963 surface->flags |= SDL_HWSURFACE; | |
964 surface->pixels = bucket->base; | |
965 return(0); | |
966 } | |
967 static void FB_FreeHWSurface(_THIS, SDL_Surface *surface) | |
968 { | |
969 vidmem_bucket *bucket, *freeable; | |
970 | |
971 /* Look for the bucket in the current list */ | |
972 for ( bucket=&surfaces; bucket; bucket=bucket->next ) { | |
973 if ( bucket->base == (char *)surface->pixels ) { | |
974 break; | |
975 } | |
976 } | |
977 if ( (bucket == NULL) || ! bucket->used ) { | |
978 return; | |
979 } | |
980 | |
981 /* Add the memory back to the total */ | |
982 #ifdef FBCON_DEBUG | |
983 printf("Freeing bucket of %d bytes\n", bucket->size); | |
984 #endif | |
985 surfaces_memleft += bucket->size; | |
986 | |
987 /* Can we merge the space with surrounding buckets? */ | |
988 bucket->used = 0; | |
989 if ( bucket->next && ! bucket->next->used ) { | |
990 #ifdef FBCON_DEBUG | |
991 printf("Merging with next bucket, for %d total bytes\n", bucket->size+bucket->next->size); | |
992 #endif | |
993 freeable = bucket->next; | |
994 bucket->size += bucket->next->size; | |
995 bucket->next = bucket->next->next; | |
996 if ( bucket->next ) { | |
997 bucket->next->prev = bucket; | |
998 } | |
999 free(freeable); | |
1000 } | |
1001 if ( bucket->prev && ! bucket->prev->used ) { | |
1002 #ifdef FBCON_DEBUG | |
1003 printf("Merging with previous bucket, for %d total bytes\n", bucket->prev->size+bucket->size); | |
1004 #endif | |
1005 freeable = bucket; | |
1006 bucket->prev->size += bucket->size; | |
1007 bucket->prev->next = bucket->next; | |
1008 if ( bucket->next ) { | |
1009 bucket->next->prev = bucket->prev; | |
1010 } | |
1011 free(freeable); | |
1012 } | |
1013 surface->pixels = NULL; | |
1014 } | |
1015 static int FB_LockHWSurface(_THIS, SDL_Surface *surface) | |
1016 { | |
1017 if ( surface == SDL_VideoSurface ) { | |
1018 SDL_mutexP(hw_lock); | |
1019 } | |
1020 return(0); | |
1021 } | |
1022 static void FB_UnlockHWSurface(_THIS, SDL_Surface *surface) | |
1023 { | |
1024 if ( surface == SDL_VideoSurface ) { | |
1025 SDL_mutexV(hw_lock); | |
1026 } | |
1027 } | |
1028 | |
1029 static void FB_WaitVBL(_THIS) | |
1030 { | |
1031 #ifdef FBIOWAITRETRACE /* Heheh, this didn't make it into the main kernel */ | |
1032 ioctl(console_fd, FBIOWAITRETRACE, 0); | |
1033 #endif | |
1034 return; | |
1035 } | |
1036 | |
1037 static int FB_FlipHWSurface(_THIS, SDL_Surface *surface) | |
1038 { | |
1039 /* Wait for vertical retrace and then flip display */ | |
1040 cache_vinfo.yoffset = flip_page*surface->h; | |
1041 wait_vbl(this); | |
1042 if ( ioctl(console_fd, FBIOPAN_DISPLAY, &cache_vinfo) < 0 ) { | |
1043 SDL_SetError("ioctl(FBIOPAN_DISPLAY) failed"); | |
1044 return(-1); | |
1045 } | |
1046 flip_page = !flip_page; | |
1047 | |
1048 surface->pixels = flip_address[flip_page]; | |
1049 return(0); | |
1050 } | |
1051 | |
1052 static void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) | |
1053 { | |
1054 /* The application is already updating the visible video memory */ | |
1055 return; | |
1056 } | |
1057 | |
1058 #ifdef VGA16_FBCON_SUPPORT | |
1059 /* Code adapted with thanks from the XFree86 VGA16 driver! :) */ | |
1060 #define writeGr(index, value) \ | |
1061 outb(index, 0x3CE); \ | |
1062 outb(value, 0x3CF); | |
1063 #define writeSeq(index, value) \ | |
1064 outb(index, 0x3C4); \ | |
1065 outb(value, 0x3C5); | |
1066 | |
1067 static void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects) | |
1068 { | |
1069 SDL_Surface *screen; | |
1070 int width, height, FBPitch, left, i, j, SRCPitch, phase; | |
1071 register Uint32 m; | |
1072 Uint8 s1, s2, s3, s4; | |
1073 Uint32 *src, *srcPtr; | |
1074 Uint8 *dst, *dstPtr; | |
1075 | |
1076 screen = this->screen; | |
1077 FBPitch = screen->w >> 3; | |
1078 SRCPitch = screen->pitch >> 2; | |
1079 | |
1080 writeGr(0x03, 0x00); | |
1081 writeGr(0x05, 0x00); | |
1082 writeGr(0x01, 0x00); | |
1083 writeGr(0x08, 0xFF); | |
1084 | |
1085 while(numrects--) { | |
1086 left = rects->x & ~7; | |
1087 width = (rects->w + 7) >> 3; | |
1088 height = rects->h; | |
1089 src = (Uint32*)screen->pixels + (rects->y * SRCPitch) + (left >> 2); | |
1090 dst = (Uint8*)mapped_mem + (rects->y * FBPitch) + (left >> 3); | |
1091 | |
1092 if((phase = (long)dst & 3L)) { | |
1093 phase = 4 - phase; | |
1094 if(phase > width) phase = width; | |
1095 width -= phase; | |
1096 } | |
1097 | |
1098 while(height--) { | |
1099 writeSeq(0x02, 1 << 0); | |
1100 dstPtr = dst; | |
1101 srcPtr = src; | |
1102 i = width; | |
1103 j = phase; | |
1104 while(j--) { | |
1105 m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4); | |
1106 *dstPtr++ = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3); | |
1107 srcPtr += 2; | |
1108 } | |
1109 while(i >= 4) { | |
1110 m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4); | |
1111 s1 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3); | |
1112 m = (srcPtr[3] & 0x01010101) | ((srcPtr[2] & 0x01010101) << 4); | |
1113 s2 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3); | |
1114 m = (srcPtr[5] & 0x01010101) | ((srcPtr[4] & 0x01010101) << 4); | |
1115 s3 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3); | |
1116 m = (srcPtr[7] & 0x01010101) | ((srcPtr[6] & 0x01010101) << 4); | |
1117 s4 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3); | |
1118 *((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24); | |
1119 srcPtr += 8; | |
1120 dstPtr += 4; | |
1121 i -= 4; | |
1122 } | |
1123 while(i--) { | |
1124 m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4); | |
1125 *dstPtr++ = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3); | |
1126 srcPtr += 2; | |
1127 } | |
1128 | |
1129 writeSeq(0x02, 1 << 1); | |
1130 dstPtr = dst; | |
1131 srcPtr = src; | |
1132 i = width; | |
1133 j = phase; | |
1134 while(j--) { | |
1135 m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4); | |
1136 *dstPtr++ = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2); | |
1137 srcPtr += 2; | |
1138 } | |
1139 while(i >= 4) { | |
1140 m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4); | |
1141 s1 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2); | |
1142 m = (srcPtr[3] & 0x02020202) | ((srcPtr[2] & 0x02020202) << 4); | |
1143 s2 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2); | |
1144 m = (srcPtr[5] & 0x02020202) | ((srcPtr[4] & 0x02020202) << 4); | |
1145 s3 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2); | |
1146 m = (srcPtr[7] & 0x02020202) | ((srcPtr[6] & 0x02020202) << 4); | |
1147 s4 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2); | |
1148 *((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24); | |
1149 srcPtr += 8; | |
1150 dstPtr += 4; | |
1151 i -= 4; | |
1152 } | |
1153 while(i--) { | |
1154 m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4); | |
1155 *dstPtr++ = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2); | |
1156 srcPtr += 2; | |
1157 } | |
1158 | |
1159 writeSeq(0x02, 1 << 2); | |
1160 dstPtr = dst; | |
1161 srcPtr = src; | |
1162 i = width; | |
1163 j = phase; | |
1164 while(j--) { | |
1165 m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4); | |
1166 *dstPtr++ = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1); | |
1167 srcPtr += 2; | |
1168 } | |
1169 while(i >= 4) { | |
1170 m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4); | |
1171 s1 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1); | |
1172 m = (srcPtr[3] & 0x04040404) | ((srcPtr[2] & 0x04040404) << 4); | |
1173 s2 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1); | |
1174 m = (srcPtr[5] & 0x04040404) | ((srcPtr[4] & 0x04040404) << 4); | |
1175 s3 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1); | |
1176 m = (srcPtr[7] & 0x04040404) | ((srcPtr[6] & 0x04040404) << 4); | |
1177 s4 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1); | |
1178 *((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24); | |
1179 srcPtr += 8; | |
1180 dstPtr += 4; | |
1181 i -= 4; | |
1182 } | |
1183 while(i--) { | |
1184 m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4); | |
1185 *dstPtr++ = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1); | |
1186 srcPtr += 2; | |
1187 } | |
1188 | |
1189 writeSeq(0x02, 1 << 3); | |
1190 dstPtr = dst; | |
1191 srcPtr = src; | |
1192 i = width; | |
1193 j = phase; | |
1194 while(j--) { | |
1195 m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4); | |
1196 *dstPtr++ = (m >> 27) | (m >> 18) | (m >> 9) | m; | |
1197 srcPtr += 2; | |
1198 } | |
1199 while(i >= 4) { | |
1200 m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4); | |
1201 s1 = (m >> 27) | (m >> 18) | (m >> 9) | m; | |
1202 m = (srcPtr[3] & 0x08080808) | ((srcPtr[2] & 0x08080808) << 4); | |
1203 s2 = (m >> 27) | (m >> 18) | (m >> 9) | m; | |
1204 m = (srcPtr[5] & 0x08080808) | ((srcPtr[4] & 0x08080808) << 4); | |
1205 s3 = (m >> 27) | (m >> 18) | (m >> 9) | m; | |
1206 m = (srcPtr[7] & 0x08080808) | ((srcPtr[6] & 0x08080808) << 4); | |
1207 s4 = (m >> 27) | (m >> 18) | (m >> 9) | m; | |
1208 *((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24); | |
1209 srcPtr += 8; | |
1210 dstPtr += 4; | |
1211 i -= 4; | |
1212 } | |
1213 while(i--) { | |
1214 m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4); | |
1215 *dstPtr++ = (m >> 27) | (m >> 18) | (m >> 9) | m; | |
1216 srcPtr += 2; | |
1217 } | |
1218 | |
1219 dst += FBPitch; | |
1220 src += SRCPitch; | |
1221 } | |
1222 rects++; | |
1223 } | |
1224 } | |
1225 #endif /* VGA16_FBCON_SUPPORT */ | |
1226 | |
1227 void FB_SavePaletteTo(_THIS, int palette_len, __u16 *area) | |
1228 { | |
1229 struct fb_cmap cmap; | |
1230 | |
1231 cmap.start = 0; | |
1232 cmap.len = palette_len; | |
1233 cmap.red = &area[0*palette_len]; | |
1234 cmap.green = &area[1*palette_len]; | |
1235 cmap.blue = &area[2*palette_len]; | |
1236 cmap.transp = NULL; | |
1237 ioctl(console_fd, FBIOGETCMAP, &cmap); | |
1238 } | |
1239 | |
1240 void FB_RestorePaletteFrom(_THIS, int palette_len, __u16 *area) | |
1241 { | |
1242 struct fb_cmap cmap; | |
1243 | |
1244 cmap.start = 0; | |
1245 cmap.len = palette_len; | |
1246 cmap.red = &area[0*palette_len]; | |
1247 cmap.green = &area[1*palette_len]; | |
1248 cmap.blue = &area[2*palette_len]; | |
1249 cmap.transp = NULL; | |
1250 ioctl(console_fd, FBIOPUTCMAP, &cmap); | |
1251 } | |
1252 | |
1253 static void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo, | |
1254 struct fb_var_screeninfo *vinfo) | |
1255 { | |
1256 int i; | |
1257 | |
1258 /* Save hardware palette, if needed */ | |
1259 if ( finfo->visual == FB_VISUAL_PSEUDOCOLOR ) { | |
1260 saved_cmaplen = 1<<vinfo->bits_per_pixel; | |
1261 saved_cmap=(__u16 *)malloc(3*saved_cmaplen*sizeof(*saved_cmap)); | |
1262 if ( saved_cmap != NULL ) { | |
1263 FB_SavePaletteTo(this, saved_cmaplen, saved_cmap); | |
1264 } | |
1265 } | |
1266 | |
1267 /* Added support for FB_VISUAL_DIRECTCOLOR. | |
1268 With this mode pixel information is passed through the palette... | |
1269 Neat fading and gamma correction effects can be had by simply | |
1270 fooling around with the palette instead of changing the pixel | |
1271 values themselves... Very neat! | |
1272 | |
1273 Adam Meyerowitz 1/19/2000 | |
1274 ameyerow@optonline.com | |
1275 */ | |
1276 if ( finfo->visual == FB_VISUAL_DIRECTCOLOR ) { | |
1277 __u16 new_entries[3*256]; | |
1278 | |
1279 /* Save the colormap */ | |
1280 saved_cmaplen = 256; | |
1281 saved_cmap=(__u16 *)malloc(3*saved_cmaplen*sizeof(*saved_cmap)); | |
1282 if ( saved_cmap != NULL ) { | |
1283 FB_SavePaletteTo(this, saved_cmaplen, saved_cmap); | |
1284 } | |
1285 | |
1286 /* Allocate new identity colormap */ | |
1287 for ( i=0; i<256; ++i ) { | |
1288 new_entries[(0*256)+i] = | |
1289 new_entries[(1*256)+i] = | |
1290 new_entries[(2*256)+i] = (i<<8)|i; | |
1291 } | |
1292 FB_RestorePaletteFrom(this, 256, new_entries); | |
1293 } | |
1294 } | |
1295 | |
1296 static void FB_RestorePalette(_THIS) | |
1297 { | |
1298 /* Restore the original palette */ | |
1299 if ( saved_cmap ) { | |
1300 FB_RestorePaletteFrom(this, saved_cmaplen, saved_cmap); | |
1301 free(saved_cmap); | |
1302 saved_cmap = NULL; | |
1303 } | |
1304 } | |
1305 | |
1306 static int FB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) | |
1307 { | |
1308 int i; | |
1309 __u16 r[256]; | |
1310 __u16 g[256]; | |
1311 __u16 b[256]; | |
1312 struct fb_cmap cmap; | |
1313 | |
1314 /* Set up the colormap */ | |
1315 for (i = 0; i < ncolors; i++) { | |
1316 r[i] = colors[i].r << 8; | |
1317 g[i] = colors[i].g << 8; | |
1318 b[i] = colors[i].b << 8; | |
1319 } | |
1320 cmap.start = firstcolor; | |
1321 cmap.len = ncolors; | |
1322 cmap.red = r; | |
1323 cmap.green = g; | |
1324 cmap.blue = b; | |
1325 cmap.transp = NULL; | |
1326 | |
1327 if( (ioctl(console_fd, FBIOPUTCMAP, &cmap) < 0) || | |
1328 !(this->screen->flags & SDL_HWPALETTE) ) { | |
1329 colors = this->screen->format->palette->colors; | |
1330 ncolors = this->screen->format->palette->ncolors; | |
1331 cmap.start = 0; | |
1332 cmap.len = ncolors; | |
1333 memset(r, 0, sizeof(r)); | |
1334 memset(g, 0, sizeof(g)); | |
1335 memset(b, 0, sizeof(b)); | |
1336 if ( ioctl(console_fd, FBIOGETCMAP, &cmap) == 0 ) { | |
1337 for ( i=ncolors-1; i>=0; --i ) { | |
1338 colors[i].r = (r[i]>>8); | |
1339 colors[i].g = (g[i]>>8); | |
1340 colors[i].b = (b[i]>>8); | |
1341 } | |
1342 } | |
1343 return(0); | |
1344 } | |
1345 return(1); | |
1346 } | |
1347 | |
1348 /* Note: If we are terminated, this could be called in the middle of | |
1349 another SDL video routine -- notably UpdateRects. | |
1350 */ | |
1351 static void FB_VideoQuit(_THIS) | |
1352 { | |
1353 int i, j; | |
1354 | |
1355 if ( this->screen ) { | |
1356 /* Clear screen and tell SDL not to free the pixels */ | |
1357 if ( this->screen->pixels && FB_InGraphicsMode(this) ) { | |
1358 #ifdef __powerpc__ /* SIGBUS when using memset() ?? */ | |
1359 Uint8 *rowp = (Uint8 *)this->screen->pixels; | |
1360 int left = this->screen->pitch*this->screen->h; | |
1361 while ( left-- ) { *rowp++ = 0; } | |
1362 #else | |
1363 memset(this->screen->pixels,0,this->screen->h*this->screen->pitch); | |
1364 #endif | |
1365 } | |
1366 /* This test fails when using the VGA16 shadow memory */ | |
1367 if ( ((char *)this->screen->pixels >= mapped_mem) && | |
1368 ((char *)this->screen->pixels < (mapped_mem+mapped_memlen)) ) { | |
1369 this->screen->pixels = NULL; | |
1370 } | |
1371 } | |
1372 | |
1373 /* Clear the lock mutex */ | |
1374 if ( hw_lock ) { | |
1375 SDL_DestroyMutex(hw_lock); | |
1376 hw_lock = NULL; | |
1377 } | |
1378 | |
1379 /* Clean up defined video modes */ | |
1380 for ( i=0; i<NUM_MODELISTS; ++i ) { | |
1381 if ( SDL_modelist[i] != NULL ) { | |
1382 for ( j=0; SDL_modelist[i][j]; ++j ) { | |
1383 free(SDL_modelist[i][j]); | |
1384 } | |
1385 free(SDL_modelist[i]); | |
1386 SDL_modelist[i] = NULL; | |
1387 } | |
1388 } | |
1389 | |
1390 /* Clean up the memory bucket list */ | |
1391 FB_FreeHWSurfaces(this); | |
1392 | |
1393 /* Close console and input file descriptors */ | |
1394 if ( console_fd > 0 ) { | |
1395 /* Unmap the video framebuffer and I/O registers */ | |
1396 if ( mapped_mem ) { | |
1397 munmap(mapped_mem, mapped_memlen); | |
1398 mapped_mem = NULL; | |
1399 } | |
1400 if ( mapped_io ) { | |
1401 munmap(mapped_io, mapped_iolen); | |
1402 mapped_io = NULL; | |
1403 } | |
1404 | |
1405 /* Restore the original video mode and palette */ | |
1406 if ( FB_InGraphicsMode(this) ) { | |
1407 FB_RestorePalette(this); | |
1408 ioctl(console_fd, FBIOPUT_VSCREENINFO, &saved_vinfo); | |
1409 } | |
1410 | |
1411 /* We're all done with the framebuffer */ | |
1412 close(console_fd); | |
1413 console_fd = -1; | |
1414 } | |
1415 FB_CloseMouse(this); | |
1416 FB_CloseKeyboard(this); | |
1417 } |