SDL_fbvideo.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:43k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

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