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

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000  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_vglvideo.c,v 1.3 2002/04/22 21:38:05 wmay Exp $";
  21. #endif
  22. /* libvga based SDL video driver implementation.
  23. */
  24. #include <err.h>
  25. #include <osreldate.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <unistd.h>
  29. #include <sys/stat.h>
  30. #include <sys/fbio.h>
  31. #include <sys/consio.h>
  32. #include <sys/kbio.h>
  33. #include <vgl.h>
  34. #include "SDL.h"
  35. #include "SDL_error.h"
  36. #include "SDL_video.h"
  37. #include "SDL_mouse.h"
  38. #include "SDL_sysvideo.h"
  39. #include "SDL_pixels_c.h"
  40. #include "SDL_events_c.h"
  41. #include "SDL_vglvideo.h"
  42. #include "SDL_vglevents_c.h"
  43. #include "SDL_vglmouse_c.h"
  44. /* Initialization/Query functions */
  45. static int VGL_VideoInit(_THIS, SDL_PixelFormat *vformat);
  46. static SDL_Rect **VGL_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
  47. static SDL_Surface *VGL_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
  48. static int VGL_SetColors(_THIS, int firstcolor, int ncolors,
  49.   SDL_Color *colors);
  50. static void VGL_VideoQuit(_THIS);
  51. /* Hardware surface functions */
  52. static int VGL_AllocHWSurface(_THIS, SDL_Surface *surface);
  53. static int VGL_LockHWSurface(_THIS, SDL_Surface *surface);
  54. static int VGL_FlipHWSurface(_THIS, SDL_Surface *surface);
  55. static void VGL_UnlockHWSurface(_THIS, SDL_Surface *surface);
  56. static void VGL_FreeHWSurface(_THIS, SDL_Surface *surface);
  57. /* Misc function */
  58. static VGLMode ** VGLListModes(int depth, int mem_model);
  59. static void VGLWaitRetrace(void);
  60. /* VGL driver bootstrap functions */
  61. static int VGL_Available(void)
  62. {
  63. /*
  64.  * Check to see if we are root and stdin is a
  65.  * virtual console. Also try to ensure that
  66.  * modes other than 320x200 are available
  67.  */
  68. int console, hires_available, i;
  69. VGLMode **modes;
  70. console = STDIN_FILENO;
  71. if ( console >= 0 ) {
  72. struct stat sb;
  73. struct vt_mode dummy;
  74. if ( (fstat(console, &sb) < 0) ||
  75.      (ioctl(console, VT_GETMODE, &dummy) < 0) ) {
  76. console = -1;
  77. }
  78. }
  79. if (geteuid() != 0 && console == -1)
  80. return 0;
  81. modes = VGLListModes(8, V_INFO_MM_DIRECT | V_INFO_MM_PACKED);
  82. hires_available = 0;
  83. for (i = 0; modes[i] != NULL; i++) {
  84. if ((modes[i]->ModeInfo.Xsize > 320) &&
  85.     (modes[i]->ModeInfo.Ysize > 200) &&
  86.     ((modes[i]->ModeInfo.Type == VIDBUF8) ||
  87.      (modes[i]->ModeInfo.Type == VIDBUF16) ||
  88.      (modes[i]->ModeInfo.Type == VIDBUF32))) {
  89. hires_available = 1;
  90. break;
  91. }
  92. }
  93. return hires_available;
  94. }
  95. static void VGL_DeleteDevice(SDL_VideoDevice *device)
  96. {
  97. free(device->hidden);
  98. free(device);
  99. }
  100. static SDL_VideoDevice *VGL_CreateDevice(int devindex)
  101. {
  102. SDL_VideoDevice *device;
  103. /* Initialize all variables that we clean on shutdown */
  104. device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
  105. if ( device ) {
  106. memset(device, 0, (sizeof *device));
  107. device->hidden = (struct SDL_PrivateVideoData *)
  108.   malloc((sizeof *device->hidden));
  109. }
  110. if ( (device == NULL) || (device->hidden == NULL) ) {
  111. SDL_OutOfMemory();
  112. if ( device ) {
  113. free(device);
  114. }
  115. return(0);
  116. }
  117. memset(device->hidden, 0, (sizeof *device->hidden));
  118. /* Set the function pointers */
  119. device->VideoInit = VGL_VideoInit;
  120. device->ListModes = VGL_ListModes;
  121. device->SetVideoMode = VGL_SetVideoMode;
  122. device->SetColors = VGL_SetColors;
  123. device->UpdateRects = NULL;
  124. device->VideoQuit = VGL_VideoQuit;
  125. device->AllocHWSurface = VGL_AllocHWSurface;
  126. device->CheckHWBlit = NULL;
  127. device->FillHWRect = NULL;
  128. device->SetHWColorKey = NULL;
  129. device->SetHWAlpha = NULL;
  130. device->LockHWSurface = VGL_LockHWSurface;
  131. device->UnlockHWSurface = VGL_UnlockHWSurface;
  132. device->FlipHWSurface = VGL_FlipHWSurface;
  133. device->FreeHWSurface = VGL_FreeHWSurface;
  134. device->SetIcon = NULL;
  135. device->SetCaption = NULL;
  136. device->GetWMInfo = NULL;
  137. device->FreeWMCursor = VGL_FreeWMCursor;
  138. device->CreateWMCursor = VGL_CreateWMCursor;
  139. device->ShowWMCursor = VGL_ShowWMCursor;
  140. device->WarpWMCursor = VGL_WarpWMCursor;
  141. device->InitOSKeymap = VGL_InitOSKeymap;
  142. device->PumpEvents = VGL_PumpEvents;
  143. device->free = VGL_DeleteDevice;
  144. return device;
  145. }
  146. VideoBootStrap VGL_bootstrap = {
  147. "vgl", "FreeBSD libVGL",
  148. VGL_Available, VGL_CreateDevice
  149. };
  150. static int VGL_AddMode(_THIS, VGLMode *inmode)
  151. {
  152. SDL_Rect *mode;
  153. int i, index;
  154. int next_mode;
  155. /* Check to see if we already have this mode */
  156. if (inmode->Depth < 8) {  /* Not supported */
  157. return 0;
  158. }
  159. index = ((inmode->Depth + 7) / 8) - 1;
  160. for (i=0; i<SDL_nummodes[index]; ++i) {
  161. mode = SDL_modelist[index][i];
  162. if ((mode->w == inmode->ModeInfo.Xsize) &&
  163.     (mode->h == inmode->ModeInfo.Ysize))
  164. return 0;
  165. }
  166. /* Set up the new video mode rectangle */
  167. mode = (SDL_Rect *)malloc(sizeof *mode);
  168. if (mode == NULL) {
  169. SDL_OutOfMemory();
  170. return -1;
  171. }
  172. mode->x = 0;
  173. mode->y = 0;
  174. mode->w = inmode->ModeInfo.Xsize;
  175. mode->h = inmode->ModeInfo.Ysize;
  176. /* Allocate the new list of modes, and fill in the new mode */
  177. next_mode = SDL_nummodes[index];
  178. SDL_modelist[index] = (SDL_Rect **)
  179. realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
  180. if (SDL_modelist[index] == NULL) {
  181. SDL_OutOfMemory();
  182. SDL_nummodes[index] = 0;
  183. free(mode);
  184. return -1;
  185. }
  186. SDL_modelist[index][next_mode] = mode;
  187. SDL_modelist[index][next_mode+1] = NULL;
  188. SDL_nummodes[index]++;
  189. return 0;
  190. }
  191. static void VGL_UpdateVideoInfo(_THIS)
  192. {
  193. this->info.wm_available = 0;
  194. this->info.hw_available = 1;
  195. this->info.video_mem = 0;
  196. if (VGLCurMode == NULL) {
  197. return;
  198. }
  199. if (VGLCurMode->ModeInfo.PixelBytes > 0) {
  200. this->info.video_mem = VGLCurMode->ModeInfo.PixelBytes *
  201.        VGLCurMode->ModeInfo.Xsize *
  202.        VGLCurMode->ModeInfo.Ysize;
  203. }
  204. }
  205. int VGL_VideoInit(_THIS, SDL_PixelFormat *vformat)
  206. {
  207. int i;
  208. int total_modes;
  209. VGLMode **modes;
  210. /* Initialize all variables that we clean on shutdown */
  211. for ( i=0; i<NUM_MODELISTS; ++i ) {
  212. SDL_nummodes[i] = 0;
  213. SDL_modelist[i] = NULL;
  214. }
  215. /* Enable mouse and keyboard support */
  216. if (getenv("SDL_NO_RAWKBD") == NULL) {
  217. if (VGLKeyboardInit(VGL_CODEKEYS) != 0) {
  218. SDL_SetError("Unable to initialize keyboard");
  219. return -1;
  220. }
  221. } else {
  222. warnx("Requiest to put keyboard into a raw mode ignored");
  223. }
  224. if (VGL_initkeymaps(STDIN_FILENO) != 0) {
  225. SDL_SetError("Unable to initialize keymap");
  226. return -1;
  227. }
  228. if (VGL_initmouse(STDIN_FILENO) != 0) {
  229. SDL_SetError("Unable to initialize mouse");
  230. return -1;
  231. }
  232. /* Determine the screen depth */
  233. if (VGLCurMode != NULL)
  234. vformat->BitsPerPixel = VGLCurMode->Depth;
  235. else
  236. vformat->BitsPerPixel = 16; /* Good default */
  237. /* Query for the list of available video modes */
  238. total_modes = 0;
  239. modes = VGLListModes(-1, V_INFO_MM_DIRECT | V_INFO_MM_PACKED);
  240. for (i = 0; modes[i] != NULL; i++) {
  241. if ((modes[i]->ModeInfo.Type == VIDBUF8) ||
  242.     (modes[i]->ModeInfo.Type == VIDBUF16) ||
  243.     (modes[i]->ModeInfo.Type == VIDBUF32)) {
  244. VGL_AddMode(this, modes[i]);
  245. total_modes++;
  246. }
  247. }
  248. if (total_modes == 0) {
  249. SDL_SetError("No linear video modes available");
  250. return -1;
  251. }
  252. /* Fill in our hardware acceleration capabilities */
  253. VGL_UpdateVideoInfo(this);
  254. /* Create the hardware surface lock mutex */
  255. hw_lock = SDL_CreateMutex();
  256. if (hw_lock == NULL) {
  257. SDL_SetError("Unable to create lock mutex");
  258. VGL_VideoQuit(this);
  259. return -1;
  260. }
  261. /* We're done! */
  262. return 0;
  263. }
  264. SDL_Rect **VGL_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
  265. {
  266. return SDL_modelist[((format->BitsPerPixel+7)/8)-1];
  267. }
  268. /* Various screen update functions available */
  269. static void VGL_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
  270. static void VGL_BankedUpdate(_THIS, int numrects, SDL_Rect *rects);
  271. SDL_Surface *VGL_SetVideoMode(_THIS, SDL_Surface *current,
  272.       int width, int height, int bpp, Uint32 flags)
  273. {
  274. int mode_found;
  275. int i;
  276. VGLMode **modes;
  277. modes = VGLListModes(bpp, V_INFO_MM_DIRECT | V_INFO_MM_PACKED);
  278. mode_found = 0;
  279. for (i = 0; modes[i] != NULL; i++) {
  280. if ((modes[i]->ModeInfo.Xsize == width) &&
  281.     (modes[i]->ModeInfo.Ysize == height) &&
  282.     ((modes[i]->ModeInfo.Type == VIDBUF8) ||
  283.      (modes[i]->ModeInfo.Type == VIDBUF16) ||
  284.      (modes[i]->ModeInfo.Type == VIDBUF32))) {
  285. mode_found = 1;
  286. break;
  287. }
  288. }
  289. if (mode_found == 0) {
  290. SDL_SetError("No matching video mode found");
  291. return NULL;
  292. }
  293. /* Shutdown previous videomode (if any) */
  294. if (VGLCurMode != NULL)
  295. VGLEnd();
  296. /* Try to set the requested linear video mode */
  297. if (VGLInit(modes[i]->ModeId) != 0) {
  298. SDL_SetError("Unable to switch to requested mode");
  299. return NULL;
  300. }
  301. VGLCurMode = realloc(VGLCurMode, sizeof(VGLMode));
  302. VGLCurMode->ModeInfo = *VGLDisplay;
  303. VGLCurMode->Depth = modes[i]->Depth;
  304. VGLCurMode->ModeId = modes[i]->ModeId;
  305. VGLCurMode->Rmask = modes[i]->Rmask;
  306. VGLCurMode->Gmask = modes[i]->Gmask;
  307. VGLCurMode->Bmask = modes[i]->Bmask;
  308. /* Workaround a bug in libvgl */
  309. if (VGLCurMode->ModeInfo.PixelBytes == 0)
  310. (VGLCurMode->ModeInfo.PixelBytes = 1);
  311. current->w = VGLCurMode->ModeInfo.Xsize;
  312. current->h = VGLCurMode->ModeInfo.Ysize;
  313. current->pixels = VGLCurMode->ModeInfo.Bitmap;
  314. current->pitch = VGLCurMode->ModeInfo.Xsize *
  315.  VGLCurMode->ModeInfo.PixelBytes;
  316. current->flags = (SDL_FULLSCREEN | SDL_HWSURFACE);
  317. /* Check if we are in a pseudo-color mode */
  318. if (VGLCurMode->ModeInfo.Type == VIDBUF8)
  319. current->flags |= SDL_HWPALETTE;
  320. /* Check if we can do doublebuffering */
  321. if (flags & SDL_DOUBLEBUF) {
  322. if (VGLCurMode->ModeInfo.Xsize * 2 <=
  323.     VGLCurMode->ModeInfo.VYsize) {
  324. current->flags |= SDL_DOUBLEBUF;
  325. flip_page = 0;
  326. flip_address[0] = (byte *)current->pixels;
  327. flip_address[1] = (byte *)current->pixels +
  328.   current->h * current->pitch;
  329. VGL_FlipHWSurface(this, current);
  330. }
  331. }
  332. if (! SDL_ReallocFormat(current, modes[i]->Depth, VGLCurMode->Rmask,
  333. VGLCurMode->Gmask, VGLCurMode->Bmask, 0)) {
  334. return NULL;
  335. }
  336. /* Update hardware acceleration info */
  337. VGL_UpdateVideoInfo(this);
  338. /* Set the blit function */
  339. this->UpdateRects = VGL_DirectUpdate;
  340. /* We're done */
  341. return current;
  342. }
  343. /* We don't actually allow hardware surfaces other than the main one */
  344. static int VGL_AllocHWSurface(_THIS, SDL_Surface *surface)
  345. {
  346. return -1;
  347. }
  348. static void VGL_FreeHWSurface(_THIS, SDL_Surface *surface)
  349. {
  350. return;
  351. }
  352. /* We need to wait for vertical retrace on page flipped displays */
  353. static int VGL_LockHWSurface(_THIS, SDL_Surface *surface)
  354. {
  355. if (surface == SDL_VideoSurface) {
  356. SDL_mutexP(hw_lock);
  357. }
  358. return 0;
  359. }
  360. static void VGL_UnlockHWSurface(_THIS, SDL_Surface *surface)
  361. {
  362. if (surface == SDL_VideoSurface) {
  363. SDL_mutexV(hw_lock);
  364. }
  365. }
  366. static int VGL_FlipHWSurface(_THIS, SDL_Surface *surface)
  367. {
  368. // VGLWaitRetrace();
  369. if (VGLPanScreen(VGLDisplay, 0, flip_page * surface->h) < 0) {
  370. SDL_SetError("VGLPanSreen() failed");
  371.                 return -1;
  372.         }
  373. flip_page = !flip_page;
  374. surface->pixels = flip_address[flip_page];
  375. return 0;
  376. }
  377. static void VGL_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
  378. {
  379. return;
  380. }
  381. static void VGL_BankedUpdate(_THIS, int numrects, SDL_Rect *rects)
  382. {
  383. return;
  384. }
  385. int VGL_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
  386. {
  387.         int i;
  388. for(i = 0; i < ncolors; i++) {
  389.         VGLSetPaletteIndex(firstcolor + i,
  390.        colors[i].r>>2,
  391.        colors[i].g>>2,
  392.        colors[i].b>>2);
  393. }
  394. return 1;
  395. }
  396. /* Note:  If we are terminated, this could be called in the middle of
  397.    another SDL video routine -- notably UpdateRects.
  398. */
  399. void VGL_VideoQuit(_THIS)
  400. {
  401. int i, j;
  402. /* Return the keyboard to the normal state */
  403. VGLKeyboardEnd();
  404. /* Reset the console video mode if we actually initialised one */
  405. if (VGLCurMode != NULL) {
  406. VGLEnd();
  407. free(VGLCurMode);
  408. VGLCurMode = NULL;
  409. }
  410. /* Clear the lock mutex */
  411. if (hw_lock != NULL) {
  412. SDL_DestroyMutex(hw_lock);
  413. hw_lock = NULL;
  414. }
  415. /* Free video mode lists */
  416. for (i = 0; i < NUM_MODELISTS; i++) {
  417. if (SDL_modelist[i] != NULL) {
  418. for (j = 0; SDL_modelist[i][j] != NULL; ++j) {
  419. free(SDL_modelist[i][j]);
  420. }
  421. free(SDL_modelist[i]);
  422. SDL_modelist[i] = NULL;
  423. }
  424. }
  425. if ( this->screen && (this->screen->flags & SDL_HWSURFACE) ) {
  426. /* Direct screen access, not a memory buffer */
  427. this->screen->pixels = NULL;
  428. }
  429. }
  430. #define VGL_RED_INDEX 0
  431. #define VGL_GREEN_INDEX 1
  432. #define VGL_BLUE_INDEX 2
  433. static VGLMode **
  434. VGLListModes(int depth, int mem_model)
  435. {
  436.   static VGLMode **modes = NULL;
  437.   VGLBitmap *vminfop;
  438.   VGLMode **modesp, *modescp;
  439.   video_info_t minfo;
  440.   int adptype, i, modenum;
  441.   if (modes == NULL) {
  442.     modes = malloc(sizeof(VGLMode *) * M_VESA_MODE_MAX);
  443.     bzero(modes, sizeof(VGLMode *) * M_VESA_MODE_MAX);
  444.   }
  445.   modesp = modes;
  446.   for (modenum = 0; modenum < M_VESA_MODE_MAX; modenum++) {
  447.     minfo.vi_mode = modenum;
  448.     if (ioctl(0, CONS_MODEINFO, &minfo) || ioctl(0, CONS_CURRENT, &adptype))
  449.       continue;
  450.     if (minfo.vi_mode != modenum)
  451.       continue;
  452.     if ((minfo.vi_flags & V_INFO_GRAPHICS) == 0)
  453.       continue;
  454.     if ((mem_model != -1) && ((minfo.vi_mem_model & mem_model) == 0))
  455.       continue;
  456.     if ((depth > 1) && (minfo.vi_depth != depth))
  457.       continue;
  458.     /* reallocf can fail */
  459.     if ((*modesp = reallocf(*modesp, sizeof(VGLMode))) == NULL)
  460.       return NULL;
  461.     modescp = *modesp;
  462.     vminfop = &(modescp->ModeInfo);
  463.     bzero(vminfop, sizeof(VGLBitmap));
  464.     vminfop->Type = NOBUF;
  465.     vminfop->PixelBytes = 1; /* Good default value */
  466.     switch (minfo.vi_mem_model) {
  467.     case V_INFO_MM_PLANAR:
  468.       /* we can handle EGA/VGA planar modes only */
  469.       if (!(minfo.vi_depth != 4 || minfo.vi_planes != 4
  470.     || (adptype != KD_EGA && adptype != KD_VGA)))
  471. vminfop->Type = VIDBUF4;
  472.       break;
  473.     case V_INFO_MM_PACKED:
  474.       /* we can do only 256 color packed modes */
  475.       if (minfo.vi_depth == 8)
  476. vminfop->Type = VIDBUF8;
  477.       break;
  478.     case V_INFO_MM_VGAX:
  479.       vminfop->Type = VIDBUF8X;
  480.       break;
  481. #if defined(__FreeBSD_version) && __FreeBSD_version >= 500000
  482.     case V_INFO_MM_DIRECT:
  483.       vminfop->PixelBytes = minfo.vi_pixel_size;
  484.       switch (vminfop->PixelBytes) {
  485.       case 2:
  486. vminfop->Type = VIDBUF16;
  487. break;
  488. #if notyet
  489.       case 3:
  490. vminfop->Type = VIDBUF24;
  491. break;
  492. #endif
  493.       case 4:
  494. vminfop->Type = VIDBUF32;
  495. break;
  496.       default:
  497. break;
  498.       }
  499. #endif
  500.     default:
  501.       break;
  502.     }
  503.     if (vminfop->Type == NOBUF)
  504.       continue;
  505.     switch (vminfop->Type) {
  506.     case VIDBUF16:
  507.     case VIDBUF32:
  508.       modescp->Rmask = ((1 << minfo.vi_pixel_fsizes[VGL_RED_INDEX]) - 1) <<
  509.        minfo.vi_pixel_fields[VGL_RED_INDEX];
  510.       modescp->Gmask = ((1 << minfo.vi_pixel_fsizes[VGL_GREEN_INDEX]) - 1) <<
  511.        minfo.vi_pixel_fields[VGL_GREEN_INDEX];
  512.       modescp->Bmask = ((1 << minfo.vi_pixel_fsizes[VGL_BLUE_INDEX]) - 1) <<
  513.        minfo.vi_pixel_fields[VGL_BLUE_INDEX];
  514.       break;
  515.     default:
  516.       break;
  517.     }
  518.     vminfop->Xsize = minfo.vi_width;
  519.     vminfop->Ysize = minfo.vi_height;
  520.     modescp->Depth = minfo.vi_depth;
  521.     /* XXX */
  522.     if (minfo.vi_mode >= M_VESA_BASE)
  523.       modescp->ModeId = _IO('V', minfo.vi_mode - M_VESA_BASE);
  524.     else
  525.       modescp->ModeId = _IO('S', minfo.vi_mode);
  526.     /* Sort list */
  527.     for (i = 0; modes + i < modesp ; i++) {
  528.       if (modes[i]->ModeInfo.Xsize * modes[i]->ModeInfo.Ysize >
  529.   vminfop->Xsize * modes[i]->ModeInfo.Ysize)
  530. continue;
  531.       if ((modes[i]->ModeInfo.Xsize * modes[i]->ModeInfo.Ysize ==
  532.    vminfop->Xsize * vminfop->Ysize) &&
  533.   (modes[i]->Depth >= modescp->Depth))
  534. continue;
  535.       *modesp = modes[i];
  536.       modes[i] = modescp;
  537.       modescp = *modesp;
  538.       vminfop = &(modescp->ModeInfo);
  539.     }
  540.     modesp++;
  541.   }
  542.   if (*modesp != NULL) {
  543.     free(*modesp);
  544.     *modesp = NULL;
  545.   }
  546.   return modes;
  547. }
  548. static void
  549. VGLWaitRetrace(void)
  550. {
  551.   while (!(inb(0x3DA) & 8));
  552.   while (inb(0x3DA) & 8);
  553. }