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.

873 lines
22 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spvidfb.c
  5. Abstract:
  6. Text setup display support for frame buffer displays.
  7. Author:
  8. Ted Miller (tedm) 29-July-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #pragma hdrstop
  13. #define MINXRES 80
  14. #define MINYRES 32
  15. //
  16. // Vector for frame buffer functions.
  17. //
  18. VIDEO_FUNCTION_VECTOR FrameBufferVideoVector =
  19. {
  20. FrameBufferDisplayString,
  21. FrameBufferClearRegion,
  22. FrameBufferSpecificInit,
  23. FrameBufferSpecificReInit,
  24. FrameBufferSpecificTerminate,
  25. FrameBufferSpecificInitPalette,
  26. FrameBufferSpecificScrollUp
  27. };
  28. BOOLEAN FrameBufferInitialized = FALSE;
  29. //
  30. // Variables that indicate whether we should double the width
  31. // and/or height of a font glyph when it is drawn. This is useful
  32. // on a 1280*1024 screen for example, to make things readable
  33. // with an 8*12 font like vgaoem.fon.
  34. //
  35. BOOLEAN DoubleCharWidth,DoubleCharHeight;
  36. //
  37. // Number of bytes that make up a row of characters.
  38. // Equal to the screen stride (number of bytes on a scan line)
  39. // multiplied by the height of a char in bytes; double that
  40. // if DoubleCharHeight is TRUE.
  41. //
  42. ULONG CharRowDelta;
  43. ULONG ScaledCharWidth,HeightIterations;
  44. ULONG BytesPerPixel;
  45. PULONG GlyphMap;
  46. //
  47. // Pointer to a dynamically allocated buffer that is the size of one scanline.
  48. //
  49. VOID
  50. pFrameBufferInitGlyphs(
  51. VOID
  52. );
  53. VOID
  54. FrameBufferSpecificInit(
  55. IN PVIDEO_MODE_INFORMATION VideoModes,
  56. IN ULONG NumberOfModes,
  57. IN ULONG ModeSize
  58. )
  59. /*++
  60. Routine Description:
  61. Perform frame buffer specific initialization. This includes
  62. - setting the desired video mode.
  63. Arguments:
  64. None.
  65. Return Value:
  66. --*/
  67. {
  68. NTSTATUS Status;
  69. IO_STATUS_BLOCK IoStatusBlock;
  70. VIDEO_MODE VideoMode;
  71. PVIDEO_MODE_INFORMATION mode;
  72. //
  73. // headless isn't enabled on frame buffer because no frame buffer systems
  74. // currently exist. if this changes, then this code must be enabled for
  75. // headless operation.
  76. //
  77. ASSERT( HeadlessTerminalConnected == FALSE );
  78. if(FrameBufferInitialized) {
  79. return;
  80. }
  81. mode = pFrameBufferDetermineModeToUse(VideoModes,NumberOfModes, ModeSize);
  82. if(mode == 0) {
  83. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_BADMODE, 0);
  84. while(TRUE); // loop forever
  85. }
  86. //
  87. // Save away the mode info in a global.
  88. //
  89. VideoVars.VideoModeInfo = *mode;
  90. //
  91. // Set the desired mode.
  92. //
  93. VideoMode.RequestedMode = VideoVars.VideoModeInfo.ModeIndex;
  94. Status = ZwDeviceIoControlFile(
  95. VideoVars.hDisplay,
  96. NULL,
  97. NULL,
  98. NULL,
  99. &IoStatusBlock,
  100. IOCTL_VIDEO_SET_CURRENT_MODE,
  101. &VideoMode,
  102. sizeof(VideoMode),
  103. NULL,
  104. 0
  105. );
  106. if(!NT_SUCCESS(Status)) {
  107. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status));
  108. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status);
  109. while(TRUE); // loop forever
  110. }
  111. //
  112. // Map the frame buffer.
  113. //
  114. pSpvidMapVideoMemory(TRUE);
  115. FrameBufferInitialized = TRUE;
  116. //
  117. // Determine the width of the screen. If it's double the size
  118. // of the minimum number of characters per row (or larger)
  119. // then we'll double the width of each character as we draw it.
  120. //
  121. VideoVars.ScreenWidth = VideoVars.VideoModeInfo.VisScreenWidth / FontCharacterWidth;
  122. if(VideoVars.ScreenWidth >= 2*MINXRES) {
  123. VideoVars.ScreenWidth /= 2;
  124. DoubleCharWidth = TRUE;
  125. } else {
  126. DoubleCharWidth = FALSE;
  127. }
  128. //
  129. // Determine the height of the screen. If it's double the size
  130. // of the minimum number of characters per column (or larger)
  131. // then we'll double the height of each character as we draw it.
  132. //
  133. VideoVars.ScreenHeight = VideoVars.VideoModeInfo.VisScreenHeight / FontCharacterHeight;
  134. CharRowDelta = VideoVars.VideoModeInfo.ScreenStride * FontCharacterHeight;
  135. if(VideoVars.ScreenHeight >= 2*MINYRES) {
  136. VideoVars.ScreenHeight /= 2;
  137. DoubleCharHeight = TRUE;
  138. CharRowDelta *= 2;
  139. } else {
  140. DoubleCharHeight = FALSE;
  141. }
  142. BytesPerPixel = VideoVars.VideoModeInfo.BitsPerPlane / 8;
  143. if(BytesPerPixel == 3) {
  144. BytesPerPixel = 4;
  145. }
  146. ScaledCharWidth = (DoubleCharWidth ? 2 : 1) * FontCharacterWidth * BytesPerPixel;
  147. HeightIterations = DoubleCharHeight ? 2 : 1;
  148. //
  149. // initialize glyphs.
  150. //
  151. pFrameBufferInitGlyphs();
  152. //
  153. // get hold of the space require for background textmode video buffer
  154. // while upgrade graphics mode is running in the foreground
  155. //
  156. if (SP_IS_UPGRADE_GRAPHICS_MODE()) {
  157. VideoVars.VideoBufferSize = VideoVars.VideoModeInfo.VisScreenHeight *
  158. VideoVars.VideoModeInfo.VisScreenWidth * BytesPerPixel;
  159. VideoVars.VideoBuffer = SpMemAlloc(VideoVars.VideoBufferSize);
  160. if (!VideoVars.VideoBuffer) {
  161. //
  162. // Out of memory, run only in textmode
  163. //
  164. VideoVars.VideoBufferSize = 0;
  165. SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
  166. VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
  167. } else {
  168. VideoVars.ActiveVideoBuffer = VideoVars.VideoBuffer;
  169. }
  170. } else {
  171. VideoVars.VideoBufferSize = 0;
  172. VideoVars.VideoBuffer = NULL;
  173. VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
  174. }
  175. }
  176. VOID
  177. FrameBufferSpecificReInit(
  178. VOID
  179. )
  180. {
  181. NTSTATUS Status;
  182. IO_STATUS_BLOCK IoStatusBlock;
  183. VIDEO_MODE VideoMode;
  184. if (!FrameBufferInitialized) {
  185. return;
  186. }
  187. //
  188. // Set the desired mode.
  189. //
  190. VideoMode.RequestedMode = VideoVars.VideoModeInfo.ModeIndex;
  191. Status = ZwDeviceIoControlFile(
  192. VideoVars.hDisplay,
  193. NULL,
  194. NULL,
  195. NULL,
  196. &IoStatusBlock,
  197. IOCTL_VIDEO_SET_CURRENT_MODE,
  198. &VideoMode,
  199. sizeof(VideoMode),
  200. NULL,
  201. 0
  202. );
  203. if(!NT_SUCCESS(Status)) {
  204. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status));
  205. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status);
  206. while(TRUE); // loop forever
  207. }
  208. //
  209. // Determine the width of the screen. If it's double the size
  210. // of the minimum number of characters per row (or larger)
  211. // then we'll double the width of each character as we draw it.
  212. //
  213. VideoVars.ScreenWidth = VideoVars.VideoModeInfo.VisScreenWidth / FontCharacterWidth;
  214. if(VideoVars.ScreenWidth >= 2*MINXRES) {
  215. VideoVars.ScreenWidth /= 2;
  216. DoubleCharWidth = TRUE;
  217. } else {
  218. DoubleCharWidth = FALSE;
  219. }
  220. //
  221. // Determine the height of the screen. If it's double the size
  222. // of the minimum number of characters per column (or larger)
  223. // then we'll double the height of each character as we draw it.
  224. //
  225. VideoVars.ScreenHeight = VideoVars.VideoModeInfo.VisScreenHeight / FontCharacterHeight;
  226. CharRowDelta = VideoVars.VideoModeInfo.ScreenStride * FontCharacterHeight;
  227. if(VideoVars.ScreenHeight >= 2*MINYRES) {
  228. VideoVars.ScreenHeight /= 2;
  229. DoubleCharHeight = TRUE;
  230. CharRowDelta *= 2;
  231. } else {
  232. DoubleCharHeight = FALSE;
  233. }
  234. BytesPerPixel = VideoVars.VideoModeInfo.BitsPerPlane / 8;
  235. if(BytesPerPixel == 3) {
  236. BytesPerPixel = 4;
  237. }
  238. ScaledCharWidth = (DoubleCharWidth ? 2 : 1) * FontCharacterWidth * BytesPerPixel;
  239. HeightIterations = DoubleCharHeight ? 2 : 1;
  240. //
  241. // initialize glyphs.
  242. //
  243. pFrameBufferInitGlyphs();
  244. FrameBufferSpecificInitPalette();
  245. //
  246. // Blast the cached video memory to the real framebuffer now
  247. //
  248. if (SP_IS_UPGRADE_GRAPHICS_MODE() && VideoVars.VideoBuffer &&
  249. VideoVars.VideoBufferSize) {
  250. PUCHAR Source = VideoVars.VideoBuffer;
  251. PUCHAR Destination = VideoVars.VideoMemoryInfo.FrameBufferBase;
  252. ULONG Index;
  253. for (Index=0; Index < VideoVars.VideoBufferSize; Index++) {
  254. WRITE_REGISTER_UCHAR(Destination + Index, *(Source + Index));
  255. }
  256. SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
  257. VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
  258. }
  259. }
  260. BOOLEAN
  261. FrameBufferSpecificInitPalette(
  262. VOID
  263. )
  264. {
  265. BOOLEAN rc;
  266. ULONG NumEntries;
  267. ULONG BufferSize;
  268. PVIDEO_CLUT clut;
  269. // NTSTATUS Status;
  270. // IO_STATUS_BLOCK IoStatusBlock;
  271. UCHAR i;
  272. rc = TRUE;
  273. //
  274. // For non-palette-driven displays, we construct a simple palette
  275. // for use w/ gamma correcting adapters.
  276. //
  277. if(!(VideoVars.VideoModeInfo.AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN)) {
  278. switch(BytesPerPixel) {
  279. case 1:
  280. NumEntries = 3;
  281. break;
  282. case 2:
  283. NumEntries = 32;
  284. break;
  285. default:
  286. NumEntries = 255;
  287. break;
  288. }
  289. BufferSize = sizeof(VIDEO_CLUT)+(sizeof(VIDEO_CLUTDATA)*NumEntries); // size is close enough
  290. clut = SpMemAlloc(BufferSize);
  291. clut->NumEntries = (USHORT)NumEntries;
  292. clut->FirstEntry = 0;
  293. for(i=0; i<NumEntries; i++) {
  294. clut->LookupTable[i].RgbArray.Red = i;
  295. clut->LookupTable[i].RgbArray.Green = i;
  296. clut->LookupTable[i].RgbArray.Blue = i;
  297. clut->LookupTable[i].RgbArray.Unused = 0;
  298. }
  299. // Status = ZwDeviceIoControlFile(
  300. // hDisplay,
  301. // NULL,
  302. // NULL,
  303. // NULL,
  304. // &IoStatusBlock,
  305. // IOCTL_VIDEO_SET_COLOR_REGISTERS,
  306. // clut,
  307. // BufferSize,
  308. // NULL,
  309. // 0
  310. // );
  311. SpMemFree(clut);
  312. // if(!NT_SUCCESS(Status)) {
  313. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set palette (status = %lx)\n",Status));
  314. // rc = FALSE;
  315. // }
  316. }
  317. return(rc);
  318. }
  319. VOID
  320. FrameBufferSpecificTerminate(
  321. VOID
  322. )
  323. /*++
  324. Routine Description:
  325. Perform frame buffer specific termination. This includes
  326. - unmapping the frame buffer from memory
  327. Arguments:
  328. None.
  329. Return Value:
  330. --*/
  331. {
  332. if(FrameBufferInitialized) {
  333. //
  334. // Be a good citizen and clear the screen. Important in Far East where
  335. // we switch screen modes on the fly as we go in and out of localized mode.
  336. //
  337. FrameBufferClearRegion(0,0,VideoVars.ScreenWidth,VideoVars.ScreenHeight,ATT_FG_BLACK|ATT_BG_BLACK);
  338. pSpvidMapVideoMemory(FALSE);
  339. FrameBufferInitialized = FALSE;
  340. SpMemFree(GlyphMap);
  341. if (VideoVars.VideoBuffer && VideoVars.VideoBufferSize) {
  342. SpMemFree(VideoVars.VideoBuffer);
  343. VideoVars.VideoBuffer = NULL;
  344. VideoVars.VideoBufferSize = 0;
  345. }
  346. }
  347. }
  348. VOID
  349. FrameBufferDisplayString(
  350. IN PSTR String,
  351. IN UCHAR Attribute,
  352. IN ULONG X, // 0-based coordinates (character units)
  353. IN ULONG Y
  354. )
  355. /*++
  356. Routine Description:
  357. Write a string of characters to the display.
  358. Arguments:
  359. Character - supplies a string in the OEM character set, to be displayed
  360. at the given position.
  361. Attribute - supplies the attributes for the character.
  362. X,Y - specify the character-based (0-based) position of the output.
  363. Return Value:
  364. None.
  365. --*/
  366. {
  367. ULONG BgColorValue;
  368. ULONG FgColorValue;
  369. PUCHAR Destination;
  370. ULONG I;
  371. ULONG J;
  372. ULONG K;
  373. ULONG Length;
  374. PUCHAR Origin;
  375. ULONG Pixel;
  376. ULONG PixelMap;
  377. ULONG RealHeight;
  378. ASSERT(X < VideoVars.ScreenWidth);
  379. ASSERT(Y < VideoVars.ScreenHeight);
  380. //
  381. // Calculate the bit patterns that yield the foreground and background
  382. // attributes when poked into the frame buffer.
  383. //
  384. FgColorValue = VideoVars.AttributeToColorValue[Attribute & 0x0f];
  385. BgColorValue = VideoVars.AttributeToColorValue[(Attribute >> 4) & 0x0f];
  386. //
  387. // Calculate the address of the upper left pixel of the first character
  388. // to be displayed.
  389. //
  390. Origin = (PUCHAR)VideoVars.ActiveVideoBuffer
  391. + (Y * CharRowDelta)
  392. + (X * ScaledCharWidth);
  393. RealHeight = FontCharacterHeight * HeightIterations;
  394. //
  395. // Output the character string by generating a complete scanline into
  396. // a temporary buffer using glyph segments from each character, then
  397. // copy the scanline to the frame buffer.
  398. //
  399. Length = strlen(String);
  400. for (I = 0; I < RealHeight; I += 1) {
  401. Destination = Origin;
  402. for (J = 0; J < Length; J += 1) {
  403. PixelMap = *(GlyphMap + (((UCHAR)String[J] * RealHeight) + I));
  404. for (K = 0; K < FontCharacterWidth; K += 1) {
  405. Pixel = (PixelMap >> 31) ? FgColorValue : BgColorValue;
  406. switch(BytesPerPixel) {
  407. case 1:
  408. *Destination++ = (UCHAR)Pixel;
  409. if(DoubleCharWidth) {
  410. *Destination++ = (UCHAR)Pixel;
  411. }
  412. break;
  413. case 2:
  414. *(PUSHORT)Destination = (USHORT)Pixel;
  415. Destination += 2;
  416. if(DoubleCharWidth) {
  417. *(PUSHORT)Destination = (USHORT)Pixel;
  418. Destination += 2;
  419. }
  420. break;
  421. case 4:
  422. *(PULONG)Destination = Pixel;
  423. Destination += 4;
  424. if(DoubleCharWidth) {
  425. *(PULONG)Destination = Pixel;
  426. Destination += 4;
  427. }
  428. break;
  429. }
  430. PixelMap <<= 1;
  431. }
  432. }
  433. Origin += VideoVars.VideoModeInfo.ScreenStride;
  434. }
  435. }
  436. VOID
  437. FrameBufferClearRegion(
  438. IN ULONG X,
  439. IN ULONG Y,
  440. IN ULONG W,
  441. IN ULONG H,
  442. IN UCHAR Attribute
  443. )
  444. /*++
  445. Routine Description:
  446. Clear out a screen region to a specific attribute.
  447. Arguments:
  448. X,Y,W,H - specify rectangle in 0-based character coordinates.
  449. Attribute - Low nibble specifies attribute to be filled in the rectangle
  450. (ie, the background color to be cleared to).
  451. Return Value:
  452. None.
  453. --*/
  454. {
  455. PUCHAR Destination;
  456. ULONG Fill;
  457. ULONG i;
  458. ULONG FillLength;
  459. ULONG x;
  460. ULONG Iterations;
  461. ASSERT(X+W <= VideoVars.ScreenWidth);
  462. ASSERT(Y+H <= VideoVars.ScreenHeight);
  463. if(X+W > VideoVars.ScreenWidth) {
  464. W = VideoVars.ScreenWidth-X;
  465. }
  466. if(Y+H > VideoVars.ScreenHeight) {
  467. H = VideoVars.ScreenHeight-Y;
  468. }
  469. Fill = VideoVars.AttributeToColorValue[Attribute & 0x0f];
  470. Destination = (PUCHAR)VideoVars.ActiveVideoBuffer
  471. + (Y * CharRowDelta)
  472. + (X * ScaledCharWidth);
  473. FillLength = W * ScaledCharWidth;
  474. Iterations = H * FontCharacterHeight * HeightIterations;
  475. switch(BytesPerPixel) {
  476. case 1:
  477. for(i=0; i<Iterations; i++) {
  478. for(x=0; x<FillLength; x++) {
  479. ((PUCHAR)Destination)[x] = (UCHAR)Fill;
  480. }
  481. Destination += VideoVars.VideoModeInfo.ScreenStride;
  482. }
  483. break;
  484. case 2:
  485. for(i=0; i<Iterations; i++) {
  486. for(x=0; x<FillLength/2; x++) {
  487. ((PUSHORT)Destination)[x] = (USHORT)Fill;
  488. }
  489. Destination += VideoVars.VideoModeInfo.ScreenStride;
  490. }
  491. break;
  492. case 4:
  493. for(i=0; i<Iterations; i++) {
  494. for(x=0; x<FillLength/4; x++) {
  495. ((PULONG)Destination)[x] = (ULONG)Fill;
  496. }
  497. Destination += VideoVars.VideoModeInfo.ScreenStride;
  498. }
  499. break;
  500. }
  501. }
  502. BOOLEAN
  503. FrameBufferSpecificScrollUp(
  504. IN ULONG TopLine,
  505. IN ULONG BottomLine,
  506. IN ULONG LineCount,
  507. IN UCHAR FillAttribute
  508. )
  509. {
  510. PUCHAR Source,Target;
  511. ULONG Count;
  512. Target = (PUCHAR)VideoVars.ActiveVideoBuffer
  513. + (TopLine * CharRowDelta);
  514. Source = Target + (LineCount * CharRowDelta);
  515. Count = (((BottomLine - TopLine) + 1) - LineCount) * CharRowDelta;
  516. RtlMoveMemory(Target,Source,Count);
  517. FrameBufferClearRegion(
  518. 0,
  519. (BottomLine - LineCount) + 1,
  520. VideoVars.ScreenWidth,
  521. LineCount,
  522. FillAttribute
  523. );
  524. return(TRUE);
  525. }
  526. VOID
  527. pFrameBufferInitGlyphs(
  528. VOID
  529. )
  530. {
  531. ULONG I,J,z,FontValue;
  532. UCHAR Character;
  533. USHORT chr;
  534. PUCHAR Glyph;
  535. PULONG dest;
  536. if (!GlyphMap) {
  537. GlyphMap = SpMemAlloc(sizeof(ULONG)*256*FontCharacterHeight*HeightIterations);
  538. }
  539. dest = GlyphMap;
  540. for(chr=0; chr<256; chr++) {
  541. Character = (UCHAR)chr;
  542. if((Character < FontHeader->FirstCharacter)
  543. || (Character > FontHeader->LastCharacter))
  544. {
  545. Character = FontHeader->DefaultCharacter;
  546. }
  547. Character -= FontHeader->FirstCharacter;
  548. Glyph = (PUCHAR)FontHeader + FontHeader->Map[Character].Offset;
  549. for (I = 0; I < FontCharacterHeight; I++) {
  550. //
  551. // Build up a bitmap of pixels that comprise the row of the glyph
  552. // we are drawing.
  553. //
  554. FontValue = 0;
  555. for (J = 0; J < FontBytesPerRow; J++) {
  556. FontValue |= *(Glyph + (J * FontCharacterHeight)) << (24 - (J * 8));
  557. }
  558. Glyph++;
  559. for(z=0; z<HeightIterations; z++) {
  560. *dest++ = FontValue;
  561. }
  562. }
  563. }
  564. }
  565. PVIDEO_MODE_INFORMATION
  566. pFrameBufferLocateMode(
  567. IN PVIDEO_MODE_INFORMATION VideoModes,
  568. IN ULONG NumberOfModes,
  569. IN ULONG ModeSize,
  570. IN ULONG X,
  571. IN ULONG Y,
  572. IN ULONG Bpp,
  573. IN ULONG VRefresh
  574. )
  575. {
  576. ULONG modenum;
  577. PVIDEO_MODE_INFORMATION pVideoMode = &VideoModes[0];
  578. for(modenum=0; modenum<NumberOfModes; modenum++) {
  579. if((pVideoMode->AttributeFlags & VIDEO_MODE_GRAPHICS)
  580. && (pVideoMode->VisScreenWidth == X)
  581. && (pVideoMode->VisScreenHeight == Y)
  582. && (((Bpp == (ULONG)(-1)) && (pVideoMode->BitsPerPlane >= 8)) || (pVideoMode->BitsPerPlane == Bpp))
  583. && ((VRefresh == (ULONG)(-1)) || (pVideoMode->Frequency == VRefresh)))
  584. {
  585. return(pVideoMode);
  586. }
  587. pVideoMode = (PVIDEO_MODE_INFORMATION) (((PUCHAR) pVideoMode) + ModeSize);
  588. }
  589. return(0);
  590. }
  591. PVIDEO_MODE_INFORMATION
  592. pFrameBufferDetermineModeToUse(
  593. IN PVIDEO_MODE_INFORMATION VideoModes,
  594. IN ULONG NumberOfModes,
  595. IN ULONG ModeSize
  596. )
  597. {
  598. PCHAR p,q,end;
  599. ULONG X,Y;
  600. PVIDEO_MODE_INFORMATION mode;
  601. ULONG i; //NEC98
  602. //return(2); //TEDM
  603. if(!NumberOfModes) {
  604. return(0);
  605. }
  606. X = Y = 0;
  607. //
  608. // Get x and y resolution. If we have a monitor id string
  609. // in the form XxY, then it is the resolution to use.
  610. //
  611. if((p=MonitorFirmwareIdString) && (q=strchr(p+3,'x')) && (strlen(q+1) >= 3)) {
  612. *q++ = 0;
  613. //
  614. // Now p points to the x resolution and q to the y resolution.
  615. //
  616. X = SpMultiByteStringToUnsigned(p,&end);
  617. if(X && (end == (q-1))) {
  618. Y = SpMultiByteStringToUnsigned(q,&end);
  619. if(end != (q+strlen(q))) {
  620. Y = 0;
  621. }
  622. } else {
  623. X = 0;
  624. }
  625. }
  626. //
  627. // If we don't have x or y resolution yet, look in the
  628. // monitor config data.
  629. //
  630. if((!X || !Y) && MonitorConfigData) {
  631. X = (ULONG)MonitorConfigData->HorizontalResolution;
  632. Y = (ULONG)MonitorConfigData->VerticalResolution;
  633. }
  634. if(X && Y) {
  635. //
  636. // We found what seems like a reasonable resolution.
  637. // Now try to locate a mode that uses it.
  638. //
  639. //
  640. // Find a mode of 8bpp with the x and y resolution at 60 Hz.
  641. //
  642. mode = pFrameBufferLocateMode(VideoModes,NumberOfModes,ModeSize,X,Y,8,60);
  643. if (mode) {
  644. return(mode);
  645. }
  646. //
  647. // Couldn't find an 8bpp mode @ 60Hz; find any mode with that resolution at 8bpp.
  648. //
  649. mode = pFrameBufferLocateMode(VideoModes,NumberOfModes,ModeSize,X,Y,8,(ULONG)(-1));
  650. if(mode) {
  651. return(mode);
  652. }
  653. }
  654. //
  655. // Can't find a mode so far. See if mode 0 is acceptable.
  656. //
  657. // First video mode in list is not for VGA on NEC98,
  658. // so make a loop to check VGA mode.
  659. // (First video mode in list is for VGA on PC/AT.)
  660. //
  661. for(i=0;
  662. i<((!IsNEC_98) ? 1 : NumberOfModes);
  663. i++, VideoModes=(PVIDEO_MODE_INFORMATION)(((PUCHAR)VideoModes)+ModeSize))
  664. {
  665. if((VideoModes->AttributeFlags & VIDEO_MODE_GRAPHICS)
  666. && (VideoModes->BitsPerPlane >= 8)
  667. && (VideoModes->VisScreenWidth >= 640)
  668. && (VideoModes->VisScreenHeight >= 480))
  669. {
  670. return(VideoModes);
  671. }
  672. } //NEC98
  673. //
  674. // Give up.
  675. //
  676. return(0);
  677. }