Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

718 lines
20 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: modex.c
  6. * Content: 16-bit DirectDraw HAL
  7. * These routines redirect the callbacks from the 32-bit
  8. * side to the driver
  9. * History:
  10. * Date By Reason
  11. * ==== == ======
  12. * 20-aug-95 craige initial implementation (from dispdib)
  13. * 10-sep-95 toddla set/clear the BUSY bit for poor drivers
  14. * 21-sep-95 craige bug 1215: use Death/Resurrection for uncertified
  15. * drivers only
  16. * 15-dec-96 jeffno added more modex modes
  17. *
  18. ***************************************************************************/
  19. #include "ddraw16.h"
  20. // in gdihelp.c
  21. extern BOOL bInOurSetMode;
  22. extern UINT FlatSel;
  23. extern DIBENGINE FAR *pdeDisplay;
  24. // in DIBENG
  25. extern void FAR PASCAL DIB_SetPaletteExt(UINT, UINT, LPVOID, DIBENGINE FAR *);
  26. UINT ModeX_Width;
  27. UINT ModeX_Height;
  28. /*
  29. * IsVGA
  30. */
  31. BOOL IsVGA()
  32. {
  33. BOOL f = FALSE;
  34. _asm
  35. {
  36. mov ax,1A00h ; Read display combination code
  37. int 10h
  38. cmp al,1Ah ; Is function supported?
  39. jne NoDisplaySupport
  40. ; BL should contain active display code, however, on some VGA cards this
  41. ; call will return the active display in BH. If BL is zero, BH is assumed to
  42. ; contain the active display. This assumes that the only display attached is
  43. ; then the active display.
  44. or bl,bl ; Is there an active display?
  45. jnz CheckActiveDisplay ; Yes, then continue on normaly.
  46. mov bl,bh ; No, then move bh to bl.
  47. or bl,bl ; Is anything supported?
  48. jz NoDisplaySupport
  49. CheckActiveDisplay:
  50. cmp bl,07h ; VGA with monochrome display
  51. je SetMCGAPresent
  52. cmp bl,08h ; VGA with color display
  53. je SetMCGAPresent
  54. cmp bl,0Bh ; MCGA with monochrome display
  55. je SetMCGAPresent
  56. cmp bl,0Ch ; MCGA with color display
  57. jne NoDisplaySupport
  58. SetMCGAPresent:
  59. inc f ; _bMCGAPresent = TRUE
  60. NoDisplaySupport:
  61. }
  62. return f;
  63. }
  64. /*
  65. * ModeX_Flip
  66. */
  67. extern WORD ScreenDisplay;
  68. LONG DDAPI ModeX_Flip( DWORD lpBackBuffer )
  69. {
  70. if( ModeX_Width == 0 )
  71. {
  72. DPF(1, "ModeX_Flip: called while not in ModeX!");
  73. DEBUG_BREAK();
  74. return DDERR_GENERIC;
  75. }
  76. /* PixBlt requires:
  77. * -start aligned on DWORD
  78. * -width a multiple of 32 OR mutliple of 32 with 8 remaining (i.e. 360x)
  79. */
  80. DDASSERT( (ModeX_Width & 0x3)==0 );
  81. DDASSERT( ((ModeX_Width & 0x1f)==0) || ((ModeX_Width & 0x1f)==8) );
  82. PixBlt(ModeX_Width,ModeX_Height,MAKELP(FlatSel, 0),lpBackBuffer,ModeX_Width);
  83. /*
  84. * We only do the multiple buffering if two buffers will fit in the VGA frame
  85. * buffer. If not, then it's blt to the visible primary on every Flip.
  86. * We implement this by not calling FlipPage so our internal idea of which
  87. * physical page is the back buffer remains the same (i.e. pointing to the
  88. * front buffer).
  89. * FlipPage is actually very clever and will refuse to flip if two pages
  90. * exceed 64k. Since this is setdisplaymode, something of an essential OS
  91. * service, I'm going to be extra paranoid and do the check here as well.
  92. * We are working with words, so group operations to avoid overflow.
  93. * Note that FlipPage is smart enough to do triple buffering if a page is less
  94. * than 64k/3 (as it is in the x175 nodes(. If we ever implement a scheme
  95. * whereby the app can specify dirty subrects to copy (either on flip or by blt)
  96. * we'll have to let them know the difference between single-, double- and
  97. * triple-buffering or else their idea of what's on the primary could get out of
  98. * sync.
  99. */
  100. if ( (ModeX_Width/4)*ModeX_Height < 32768 ) /* i.e two pages would be < 64k */
  101. {
  102. DPF(5,"ModeX_Flip called, display offset is %08x",ScreenDisplay);
  103. FlipPage();
  104. }
  105. return DD_OK;
  106. } /* ModeX_Blt */
  107. #define MODEX_HACK_ENTRY "AlternateLowResInit"
  108. static BOOL bCertified;
  109. /*
  110. * useDeathResurrection
  111. */
  112. static BOOL useDeathResurrection( void )
  113. {
  114. int rc;
  115. /*
  116. * is a value specified? if not, use certified bit
  117. */
  118. rc = GetProfileInt( "DirectDraw", MODEX_HACK_ENTRY, -99 );
  119. if( rc == -99 )
  120. {
  121. DPF( 3, "useDeathResurrection = %d", !bCertified );
  122. return !bCertified;
  123. }
  124. /*
  125. * use ini file entry
  126. */
  127. DPF( 3, "OVERRIDE: useDeathResurrection = %d", rc );
  128. return rc;
  129. } /* useDeathResurrection */
  130. /*
  131. * patchReg
  132. */
  133. static WORD patchReg( WORD bpp )
  134. {
  135. HKEY hkey;
  136. DPF( 3, "patching HKEY_CURRENT_CONFIG\\Display\\Settings\\BitsPerPixel" );
  137. if( !RegOpenKey(HKEY_CURRENT_CONFIG, "Display\\Settings", &hkey) )
  138. {
  139. char str[20];
  140. DWORD cb;
  141. if( bpp == 0 )
  142. {
  143. str[0] = 0;
  144. cb = sizeof( str );
  145. if( !RegQueryValueEx( hkey, "BitsPerPixel", NULL, NULL, str, &cb ) )
  146. {
  147. bpp = atoi( str );
  148. DPF( 3, "BitsPerPixel of display is \"%s\" (%d)", str, bpp );
  149. strcpy( str, "8" );
  150. }
  151. }
  152. else
  153. {
  154. _itoa( bpp, str, 10 );
  155. }
  156. if( bpp != 0 )
  157. {
  158. DPF( 3, "Setting BitsPerPixel of display to \"%s\"", str );
  159. RegSetValueEx( hkey, "BitsPerPixel", 0, REG_SZ,
  160. (CONST LPBYTE)str, strlen( str ) );
  161. }
  162. RegCloseKey( hkey );
  163. }
  164. else
  165. {
  166. bpp = 0;
  167. }
  168. return bpp;
  169. } /* patchReg */
  170. /*
  171. * DD16_SetCertified
  172. */
  173. void DDAPI DD16_SetCertified( BOOL iscert )
  174. {
  175. bCertified = (BOOL) iscert;
  176. } /* DD16_SetCertified */
  177. /*
  178. * ModeX_SetMode
  179. */
  180. LONG DDAPI ModeX_SetMode( UINT wWidth, UINT wHeight, UINT wStandardVGAFlag )
  181. {
  182. LONG lResult = DD_OK;
  183. if ( (wWidth != 320) && (wWidth != 360) )
  184. {
  185. DPF(1, "ModeX_SetMode: %dx%d is an invalid mode!",wWidth,wHeight);
  186. return DDERR_INVALIDMODE;
  187. }
  188. if ( (wHeight != 175) && (wHeight != 200) && (wHeight != 240) &&
  189. (wHeight != 350) && (wHeight != 400) && (wHeight != 480) )
  190. {
  191. DPF(1, "ModeX_SetMode: %dx%d is an invalid mode!",wWidth,wHeight);
  192. return DDERR_INVALIDMODE;
  193. }
  194. if (!IsVGA())
  195. {
  196. DPF(1, "not a VGA");
  197. return DDERR_INVALIDMODE;
  198. }
  199. ModeX_Width = wWidth;
  200. ModeX_Height = wHeight;
  201. bInOurSetMode = TRUE;
  202. _asm
  203. {
  204. mov ax, 4001h
  205. int 2fh ; notify background switch
  206. }
  207. if( useDeathResurrection() )
  208. {
  209. extern FAR PASCAL Death( HDC );
  210. HDC hdc = GetDC( NULL );
  211. DPF( 4, "Calling driver Disable" );
  212. _asm _emit 0x66 _asm _emit 0x60 ; pushad
  213. Death( hdc );
  214. _asm _emit 0x66 _asm _emit 0x61 ; popad
  215. ReleaseDC( NULL, hdc );
  216. }
  217. //
  218. // after calling disable the BUSY bit better be set
  219. // some display driver people thew out our sample code
  220. // and rewrote it, and made it "better"
  221. //
  222. if (pdeDisplay && !(pdeDisplay->deFlags & BUSY))
  223. {
  224. DPF(1, "*** GIVE ME A GUN, NOW!, I WANT TO SHOOT SOMEONE ***");
  225. pdeDisplay->deFlags |= BUSY;
  226. }
  227. DPF( 5, "ModeX_SetMode(%d,%d, VGAFlag:%d)", wWidth, wHeight, wStandardVGAFlag);
  228. /*
  229. if (wHeight == 200)
  230. SetMode320x200x8();
  231. else if (wHeight == 240)
  232. SetMode320x240x8();
  233. else
  234. SetMode320x400x8();
  235. */
  236. if ( wStandardVGAFlag )
  237. {
  238. /*
  239. * Call BIOS to do set mode 013h. Assume successful.
  240. */
  241. _asm
  242. {
  243. mov ax,12h
  244. int 10h ; have BIOS clear memory
  245. mov ax,13h ; set display mode 320x200x8
  246. int 10h
  247. }
  248. }
  249. else
  250. {
  251. lResult = SetVGAForModeX( wWidth, wHeight );
  252. }
  253. bInOurSetMode = FALSE;
  254. return lResult;
  255. } /* ModeX_Enter */
  256. /*
  257. * ModeX_Leave
  258. */
  259. LONG DDAPI ModeX_RestoreMode( void )
  260. {
  261. if (ModeX_Width == 0)
  262. {
  263. DPF(1, "ModeX_RestoreMode: not in ModeX!");
  264. return DDERR_GENERIC;
  265. }
  266. DPF( 4, "Leaving ModeX" );
  267. ModeX_Width = 0;
  268. ModeX_Height = 0;
  269. bInOurSetMode = TRUE;
  270. _asm
  271. {
  272. mov ax, 0003h ; text mode
  273. int 10h
  274. }
  275. if( useDeathResurrection() )
  276. {
  277. WORD bpp;
  278. HDC hdc;
  279. extern void FAR PASCAL Resurrection(HDC, LONG, LONG, LONG);
  280. bpp = patchReg( 0 );
  281. hdc = GetDC( NULL );
  282. DPF( 4, "Calling driver Enable" );
  283. _asm _emit 0x66 _asm _emit 0x60 ; pushad
  284. Resurrection( hdc, 0, 0, 0 );
  285. _asm _emit 0x66 _asm _emit 0x61 ; popad
  286. ReleaseDC( NULL, hdc );
  287. patchReg( bpp );
  288. }
  289. _asm
  290. {
  291. mov ax, 4002h ; notify foreground
  292. int 2fh
  293. }
  294. //
  295. // after calling enable the BUSY bit better be clear
  296. // some display driver people thew out our sample code
  297. // and rewrote it, and made it "better"
  298. //
  299. if (pdeDisplay && (pdeDisplay->deFlags & BUSY))
  300. {
  301. DPF(1, "*** GIVE ME A GUN, NOW!, I WANT TO SHOOT SOMEONE ***");
  302. pdeDisplay->deFlags &= ~BUSY;
  303. }
  304. bInOurSetMode = FALSE;
  305. } /* ModeX_Leave */
  306. /*
  307. * ModeX_SetPaletteEntries
  308. */
  309. LONG DDAPI ModeX_SetPaletteEntries(UINT wBase, UINT wNumEntries, LPPALETTEENTRY lpColorTable)
  310. {
  311. #ifdef DEBUG
  312. if (ModeX_Width == 0)
  313. {
  314. DPF(0, "ModeX_SetPaletteEntries: not in ModeX!!!");
  315. DEBUG_BREAK();
  316. return DDERR_GENERIC;
  317. }
  318. #endif
  319. //
  320. // call the DIBENG so it can update the color table is uses for
  321. // colr matching.
  322. //
  323. if (pdeDisplay)
  324. {
  325. DIB_SetPaletteExt(wBase, wNumEntries, lpColorTable, pdeDisplay);
  326. }
  327. //
  328. // now program the hardware DACs
  329. //
  330. SetPalette(wBase, wNumEntries, lpColorTable);
  331. return DD_OK;
  332. } /* ModeX_SetPaletteEntries */
  333. /*============================================================================*
  334. New ModeX mode-set code.
  335. This code can manage horizontal resolutions of 320 or 360, with vertical
  336. resolutions of 175, 200, 240, 350, 400 and 480.
  337. This chart shows the operations necessary to set each of these modes, and
  338. the order in which these operations are done.
  339. Read the chart from top to bottom for a given vertical resolution, doing
  340. what's appropriate at each operation for the chosen horizontal resolution.
  341. Vertical Res:| 175 200 240 350 400 480 Horizontal
  342. | Resolution
  343. Operation |
  344. -------------+-----------------------------------------------------------------
  345. |
  346. Call int 10h | ....................... ALL ...........................
  347. |
  348. Reset CRT and|
  349. put this in | a3 No e3 a3 No e3 320
  350. MISC_OUTPUT | a7 67 e7 a7 67 e7 360
  351. |
  352. Disable Chain| ....................... ALL ...........................
  353. |
  354. CRT_INDEX | ....................... ALL ...........................
  355. "tweak" |
  356. |
  357. Set 360 | ........................ NO .............. 320 DUHH!!!!
  358. | ........................ YES ............. 360
  359. |
  360. Set Vertical |
  361. |
  362. Which table? | 350* None 480* 350 None 480 Both horz. res's.
  363. |
  364. * There are two tables defining how registers are to be munged to set a new
  365. vertical mode; one for 350 and one for 480. To set half this vertical resolution,
  366. skip the first entry in the table (which sets CRT_INDEX 9 to 0x40
  367. *============================================================================*/
  368. #define SC_INDEX 0x3c4
  369. #define CRT_INDEX 0x3d4
  370. #define MISC_OUTPUT 0x3c2
  371. /*
  372. * These def's are to make port to NT painless...
  373. */
  374. #define WRITE_PORT_USHORT(port,value) {\
  375. DPF(5,"out %04x,%04x",port,value);_outpw(port,value);\
  376. _asm push ax \
  377. _asm pop ax \
  378. _asm push ax \
  379. _asm pop ax \
  380. }
  381. #define WRITE_PORT_UCHAR(port,value) {\
  382. DPF(5,"out %04x,%02x",port,value);_outp(port,value);\
  383. _asm push ax \
  384. _asm pop ax \
  385. _asm push ax \
  386. _asm pop ax \
  387. }
  388. static WORD wCRT_Tweak[] = {
  389. 0x0014, /* Turn off DWORD mode */
  390. 0xe317 /* Turn on BYTE mode */
  391. };
  392. #define NUM_CRT_Tweak (sizeof(wCRT_Tweak)/sizeof(wCRT_Tweak[0]))
  393. static WORD wCRT_Set360Columns[] = {
  394. 0x6b00, /* Horizontal total 107 */
  395. 0x5901, /* Horizontal display end 89 */
  396. 0x5a02, /* Start horizontal blank 90 */
  397. 0x8e03, /* End horizontal blank */
  398. 0x5e04, /* Start horizontal retrace 94 */
  399. 0x8a05, /* End horizontal retrace */
  400. 0x2d13 /* Offset register 90 */
  401. };
  402. #define NUM_CRT_Set360Columns (sizeof(wCRT_Set360Columns)/sizeof(wCRT_Set360Columns[0]))
  403. static WORD wCRT_Set175Lines[] = {
  404. 0x1f07, /* Overflow register */
  405. 0xbf06, /* Vertical total 447 */
  406. 0x8310, /* Vertical retrace start 387 */
  407. 0x8511, /* Vertical retrace end */
  408. 0x6315, /* Start vertical blanking 355 */
  409. 0xba16, /* End vertical blanking */
  410. 0x5d12 /* Vertical display end 349 */
  411. };
  412. #define NUM_CRT_Set175Lines (sizeof(wCRT_Set175Lines)/sizeof(wCRT_Set175Lines[0]))
  413. static WORD wCRT_Set240Lines[] = {
  414. 0x0d06, /* Vertical total 523 */
  415. 0x3e07, /* Overflow register */
  416. 0xea10, /* Vertical retrace start 490 */
  417. 0xac11, /* Vertical retrace end */
  418. 0xdf12, /* Vertical display end 479 */
  419. 0xe715, /* Start vertical blanking 487 */
  420. 0x0616 /* End vertical blanking */
  421. };
  422. #define NUM_CRT_Set240Lines (sizeof(wCRT_Set240Lines)/sizeof(wCRT_Set240Lines[0]))
  423. void BatchSetVGARegister(UINT iRegister, LPWORD pWordArray, int iCount)
  424. {
  425. int i;
  426. for (i = 0; i< iCount; i++)
  427. {
  428. WRITE_PORT_USHORT(iRegister,pWordArray[i]);
  429. }
  430. }
  431. /*
  432. * The routines in mvgaxx.asm expect these two initialised.
  433. * These externs MUST stay in sync with what's in mvgaxx.asm.
  434. */
  435. extern WORD ScreenOffset;
  436. extern WORD cdwScreenWidthInDWORDS;
  437. /*
  438. * This must be a multiple of 256
  439. */
  440. extern WORD cbScreenPageSize;
  441. LONG SetVGAForModeX(UINT wWidth, UINT wHeight)
  442. {
  443. BOOL bIsXHundredMode = FALSE;
  444. BOOL bIsStretchedMode = FALSE;
  445. LPWORD pwVerticalTable;
  446. UINT cwVerticalCount;
  447. /*
  448. * These three are required by routines in mvgaxx.asm
  449. */
  450. ScreenOffset = 0;
  451. ScreenDisplay = 0;
  452. cdwScreenWidthInDWORDS = wWidth/4;
  453. /*
  454. * Page size must be a multiple of 256 as required by
  455. * FlipPage in vgaxx.asm
  456. */
  457. cbScreenPageSize = (wWidth/4 * wHeight + 0xff) & (~0xff) ;
  458. DDASSERT( (cbScreenPageSize & 0xff) == 0);
  459. DPF(5,"SetVGAForModeX called (%d,%d)",wWidth,wHeight);
  460. /*
  461. * First validate requested resolution
  462. */
  463. if ( (wWidth != 320) && (wWidth != 360) )
  464. {
  465. return DDERR_UNSUPPORTEDMODE;
  466. }
  467. if (
  468. (wHeight != 175) &&
  469. (wHeight != 200) &&
  470. (wHeight != 240) &&
  471. (wHeight != 350) &&
  472. (wHeight != 400) &&
  473. (wHeight != 480) )
  474. {
  475. return DDERR_UNSUPPORTEDMODE;
  476. }
  477. /*
  478. * Setup some useful booleans
  479. */
  480. if ( (wHeight==200) || (wHeight==400) )
  481. {
  482. bIsXHundredMode = TRUE;
  483. }
  484. if ( (wHeight == 350) || (wHeight == 400) || (wHeight == 480) )
  485. {
  486. bIsStretchedMode = TRUE;
  487. }
  488. /*
  489. * The first step for any mode set is calling BIOS to do set mode 013h
  490. */
  491. _asm
  492. {
  493. mov ax,12h
  494. int 10h ; have BIOS clear memory
  495. mov ax,13h ; set display mode 320x200x8
  496. int 10h
  497. }
  498. _asm
  499. {
  500. mov dx,CRT_INDEX ;reprogram the CRT Controller
  501. mov al,11h ;VSync End reg contains register write
  502. out dx,al ; protect bit
  503. inc dx ;CRT Controller Data register
  504. in al,dx ;get current VSync End register setting
  505. and al,7fh ;remove write protect on various
  506. out dx,al ; CRTC registers
  507. dec dx ;CRT Controller Index
  508. }
  509. BatchSetVGARegister(CRT_INDEX, (LPWORD) wCRT_Tweak, NUM_CRT_Tweak);
  510. /*
  511. * Every ModeX mode needs Chain4 turned off etc.
  512. */
  513. DPF(5,"Set unchained");
  514. WRITE_PORT_USHORT(SC_INDEX,0x604);
  515. /*
  516. * For everything but 320x200 and 320x400 we need to reset the CRT and
  517. * reprogram the MISC_OUTPUT register
  518. */
  519. if ( ! ((wWidth == 320 ) && (bIsXHundredMode)) )
  520. {
  521. WORD wMISC;
  522. if ( (wHeight == 175) || (wHeight == 350) )
  523. {
  524. wMISC = 0xa3;
  525. }
  526. else if ( bIsXHundredMode )
  527. {
  528. wMISC = 0x63;
  529. }
  530. else
  531. {
  532. wMISC = 0xe3;
  533. }
  534. if ( wWidth == 360 )
  535. {
  536. wMISC |= 0x4;
  537. }
  538. /*
  539. * Set the dot clock...
  540. */
  541. DPF(5,"Setting dot clock");
  542. _asm cli;
  543. WRITE_PORT_USHORT(SC_INDEX,0x100);
  544. WRITE_PORT_UCHAR(MISC_OUTPUT,wMISC);
  545. WRITE_PORT_USHORT(SC_INDEX,0x300);
  546. _asm sti;
  547. } /* if required reset */
  548. /*
  549. * And now the magic scan stretch for 360x modes
  550. */
  551. if (wWidth == 360)
  552. {
  553. BatchSetVGARegister(CRT_INDEX, (LPWORD) wCRT_Set360Columns, NUM_CRT_Set360Columns);
  554. }
  555. /*
  556. * Now set the vertical resolution....
  557. * There are two tables, one for 240 and one for 175. We can set double these
  558. * heights by a single write of 0x40 to sequencer register 9. This trick
  559. * also works to stretch x200 into x400.
  560. */
  561. if (wHeight == 200)
  562. {
  563. /*
  564. * All done for 200 lines
  565. */
  566. return DD_OK;
  567. }
  568. if (bIsStretchedMode)
  569. {
  570. /*
  571. * Double the cell height for 350, 400 or 480 lines...
  572. */
  573. DDASSERT( wHeight == 350 || wHeight == 400 || wHeight == 480 );
  574. WRITE_PORT_USHORT(CRT_INDEX,0x4009); /* 0x40 into register 9 */
  575. }
  576. else
  577. {
  578. /*
  579. * Double the cell height for 350, 400 or 480 lines...
  580. */
  581. DDASSERT( wHeight == 175 || wHeight == 200 || wHeight == 240 );
  582. WRITE_PORT_USHORT(CRT_INDEX,0x4109); /* 0x41 into register 9 */
  583. }
  584. if (wHeight == 400)
  585. {
  586. /*
  587. * 400 is simply stretched 200, so we're done
  588. */
  589. return DD_OK;
  590. }
  591. if ( (wHeight == 175) || (wHeight == 350) )
  592. {
  593. pwVerticalTable = wCRT_Set175Lines;
  594. cwVerticalCount = NUM_CRT_Set175Lines;
  595. }
  596. else if ( (wHeight == 240) || (wHeight == 480) )
  597. {
  598. pwVerticalTable = wCRT_Set240Lines;
  599. cwVerticalCount = NUM_CRT_Set240Lines;
  600. }
  601. #ifdef DEBUG
  602. else
  603. {
  604. DPF_ERR("Flow logic in SetVGAForModeX is wrong!!!");
  605. DDASSERT(FALSE);
  606. return DDERR_UNSUPPORTEDMODE;
  607. }
  608. #endif
  609. /*
  610. *Just write the vertical info, and we're done
  611. */
  612. BatchSetVGARegister(CRT_INDEX, (LPWORD) pwVerticalTable, cwVerticalCount);
  613. return DD_OK;
  614. }