Source code of Windows XP (NT5)
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.

1834 lines
50 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. vesa.c
  5. Abstract:
  6. This module implements VESA support.
  7. Author:
  8. Erick Smith (ericks) Sep. 2000
  9. Environment:
  10. kernel mode only
  11. Revision History:
  12. --*/
  13. #include "dderror.h"
  14. #include "devioctl.h"
  15. #include "miniport.h"
  16. #include "ntddvdeo.h"
  17. #include "video.h"
  18. #include "vga.h"
  19. #include "vesa.h"
  20. #if defined(ALLOC_PRAGMA)
  21. #pragma alloc_text(PAGE,ValidateVbeInfo)
  22. #pragma alloc_text(PAGE,InitializeModeTable)
  23. #pragma alloc_text(PAGE,UpdateRegistry)
  24. #pragma alloc_text(PAGE,VgaSaveHardwareState)
  25. #pragma alloc_text(PAGE,VesaSaveHardwareState)
  26. #pragma alloc_text(PAGE,GetVideoMemoryBaseAddress)
  27. #pragma alloc_text(PAGE,RaiseToPower2)
  28. #pragma alloc_text(PAGE,RaiseToPower2Ulong)
  29. #pragma alloc_text(PAGE,IsPower2)
  30. #pragma alloc_text(PAGE,VBESetMode)
  31. #pragma alloc_text(PAGE,VBEGetMode)
  32. #pragma alloc_text(PAGE,VBEGetModeInfo)
  33. #pragma alloc_text(PAGE,VBESaveState)
  34. #pragma alloc_text(PAGE,VBERestoreState)
  35. #pragma alloc_text(PAGE,VBESetDisplayWindow)
  36. #pragma alloc_text(PAGE,VBEGetDisplayWindow)
  37. #pragma alloc_text(PAGE,VBEGetScanLineLength)
  38. #pragma alloc_text(PAGE,IsSavedModeVesa)
  39. #pragma alloc_text(PAGE,VesaSaveHardwareState)
  40. #pragma alloc_text(PAGE,VesaRestoreHardwareState)
  41. #pragma alloc_text(PAGE,SaveFrameBuffer)
  42. #pragma alloc_text(PAGE,RestoreFrameBuffer)
  43. #endif
  44. USHORT
  45. RaiseToPower2(
  46. USHORT x
  47. )
  48. {
  49. USHORT Mask = x;
  50. if (Mask & (Mask - 1)) {
  51. Mask = 1;
  52. while (Mask < x && Mask != 0) {
  53. Mask <<= 1;
  54. }
  55. }
  56. return Mask;
  57. }
  58. ULONG
  59. RaiseToPower2Ulong(
  60. ULONG x
  61. )
  62. {
  63. ULONG Mask = x;
  64. if (Mask & (Mask - 1)) {
  65. Mask = 1;
  66. while (Mask < x && Mask != 0) {
  67. Mask <<= 1;
  68. }
  69. }
  70. return Mask;
  71. }
  72. BOOLEAN
  73. IsPower2(
  74. USHORT x
  75. )
  76. {
  77. return( !(x & (x- 1)) );
  78. }
  79. VOID
  80. UpdateRegistry(
  81. PHW_DEVICE_EXTENSION hwDeviceExtension,
  82. PWSTR ValueName,
  83. PUCHAR Value
  84. )
  85. /*++
  86. --*/
  87. {
  88. ULONG Len = (strlen(Value) + 1) * 2;
  89. PWSTR WideString;
  90. WideString = VideoPortAllocatePool(hwDeviceExtension,
  91. VpPagedPool,
  92. Len,
  93. ' agV');
  94. if (WideString) {
  95. PWSTR ptr = WideString;
  96. while(*Value) {
  97. *ptr++ = (WCHAR) *Value++;
  98. }
  99. *ptr = 0;
  100. VideoPortSetRegistryParameters(hwDeviceExtension,
  101. ValueName,
  102. WideString,
  103. Len);
  104. VideoPortFreePool(hwDeviceExtension, WideString);
  105. }
  106. }
  107. BOOLEAN
  108. IsVesaBiosOk(
  109. PVIDEO_PORT_INT10_INTERFACE pInt10,
  110. USHORT OemSoftwareRev,
  111. PUCHAR OemVendorName,
  112. PUCHAR OemProductName,
  113. PUCHAR OemProductRev
  114. )
  115. {
  116. VideoDebugPrint((1, "OemSoftwareRev = %d\n", OemSoftwareRev));
  117. VideoDebugPrint((1, "OemVendorName = '%s'\n", OemVendorName));
  118. VideoDebugPrint((1, "OemProductName = '%s'\n", OemProductName));
  119. VideoDebugPrint((1, "OemProductRev = '%s'\n", OemProductRev));
  120. //
  121. // The ATI ArtX boxes currently have a VESA Bios bug where
  122. // they indicate they support linear mode access when
  123. // they don't. Fail these boards.
  124. //
  125. if ((strcmp(OemProductName, "ATI S1-370TL") == 0) ||
  126. (strcmp(OemProductName, "ArtX I") == 0)) {
  127. return FALSE;
  128. }
  129. //
  130. // Several 3dfx boards have buggy vesa bioses. The mode set
  131. // works, but the display is corrupted.
  132. //
  133. if ((strcmp(OemProductName, "Voodoo4 4500 ") == 0) ||
  134. (strcmp(OemProductName, "Voodoo3 3000 LC ") == 0) ||
  135. (strcmp(OemProductName, "Voodoo3 2000 LC ") == 0) ||
  136. (strcmp(OemProductName, "3Dfx Banshee") == 0)) {
  137. return FALSE;
  138. }
  139. //
  140. // Matrox G100 boards with rev 1.05 bioses can't set vesa modes.
  141. // We hang in the bios.
  142. //
  143. if ((strcmp(OemProductName, "MGA-G100") == 0) &&
  144. (OemSoftwareRev == 0x105)) {
  145. //
  146. // We must also disable 800x600x16 color mode for this
  147. // device. This makes the assumption that the mode we
  148. // are deleting is the last mode in our table.
  149. //
  150. NumVideoModes--;
  151. return FALSE;
  152. }
  153. //
  154. // We have seen at least on SIS 5597 part which returns a bad
  155. // linear address. Lets disable these parts.
  156. //
  157. if (strcmp(OemProductName, "SiS 5597") == 0) {
  158. return FALSE;
  159. }
  160. //
  161. // We found a bad nVidia GeForce MX part. It hangs in the bios
  162. // on boot.
  163. //
  164. if ((strcmp(OemVendorName, "NVidia Corporation") == 0) &&
  165. (strcmp(OemProductName, "NV11 (GeForce2) Board") == 0) &&
  166. (strcmp(OemProductRev, "Chip Rev B2") == 0) &&
  167. (OemSoftwareRev == 0x311)) {
  168. //
  169. // This bios "may" be buggy, but in an effort to not kill
  170. // vesa support on all GeForce MX boards, lets also look at
  171. // the version string embedded in the bios.
  172. //
  173. // We know the bad bios's have the following string at location
  174. // c000:0159:
  175. //
  176. // "Version 3.11.01.24N16"
  177. //
  178. // Lets read from this location and try to match on this string
  179. //
  180. UCHAR Version[22];
  181. pInt10->Int10ReadMemory(pInt10->Context,
  182. (USHORT)0xC000,
  183. (USHORT)0x0159,
  184. Version,
  185. 21);
  186. Version[21] = 0;
  187. if (strcmp(Version, "Version 3.11.01.24N16") == 0) {
  188. return FALSE;
  189. }
  190. }
  191. return TRUE;
  192. }
  193. BOOLEAN
  194. ValidateVbeInfo(
  195. PHW_DEVICE_EXTENSION hwDeviceExtension,
  196. PVGA_INFO_BLOCK InfoBlock
  197. )
  198. /*++
  199. Notes:
  200. This routine makes the assumption that the InfoBlock is still
  201. valid in the VDM transfer area.
  202. --*/
  203. {
  204. PVIDEO_PORT_INT10_INTERFACE pInt10;
  205. BOOLEAN UseVesa = FALSE;
  206. pInt10 = &hwDeviceExtension->Int10;
  207. if (InfoBlock->VesaSignature == 'ASEV') {
  208. PUCHAR OemString;
  209. UCHAR OemStringBuffer[80];
  210. ULONG MemorySize;
  211. //
  212. // Capture OEM String
  213. //
  214. pInt10->Int10ReadMemory(pInt10->Context,
  215. (USHORT)SEG(InfoBlock->OemStringPtr),
  216. (USHORT)OFF(InfoBlock->OemStringPtr),
  217. OemStringBuffer,
  218. 80);
  219. OemString = OemStringBuffer;
  220. VideoDebugPrint((1, "*********************************************\n"));
  221. VideoDebugPrint((1, " VBE Signature: VESA\n"));
  222. VideoDebugPrint((1, " VBE Version: %d.%02d\n",
  223. InfoBlock->VbeVersion >> 8,
  224. InfoBlock->VbeVersion & 0xff));
  225. VideoDebugPrint((1, " OEM String: %s\n",
  226. OemString));
  227. if (InfoBlock->TotalMemory < 16) {
  228. //
  229. // If less than 1 meg, display in KB
  230. //
  231. VideoDebugPrint((1, " Total Memory: %dKB\n",
  232. InfoBlock->TotalMemory * 64));
  233. } else {
  234. //
  235. // Else display in MB
  236. //
  237. VideoDebugPrint((1, " Total Memory: %dMB\n",
  238. InfoBlock->TotalMemory / 16));
  239. }
  240. if (InfoBlock->VbeVersion >= 0x102) {
  241. UCHAR OemVendorName[80];
  242. UCHAR OemProductName[80];
  243. UCHAR OemProductRev[80];
  244. pInt10->Int10ReadMemory(pInt10->Context,
  245. (USHORT)SEG(InfoBlock->OemVendorNamePtr),
  246. (USHORT)OFF(InfoBlock->OemVendorNamePtr),
  247. OemVendorName,
  248. 80);
  249. pInt10->Int10ReadMemory(pInt10->Context,
  250. (USHORT)SEG(InfoBlock->OemProductNamePtr),
  251. (USHORT)OFF(InfoBlock->OemProductNamePtr),
  252. OemProductName,
  253. 80);
  254. pInt10->Int10ReadMemory(pInt10->Context,
  255. (USHORT)SEG(InfoBlock->OemProductRevPtr),
  256. (USHORT)OFF(InfoBlock->OemProductRevPtr),
  257. OemProductRev,
  258. 80);
  259. OemVendorName[79] = 0;
  260. OemProductName[79] = 0;
  261. OemProductRev[79] = 0;
  262. VideoDebugPrint((1, " OEM Software Rev: %d.%02d\n",
  263. InfoBlock->OemSoftwareRev >> 8,
  264. InfoBlock->OemSoftwareRev & 0xff));
  265. VideoDebugPrint((1, " OEM Vendor Name: %s\n", OemVendorName));
  266. VideoDebugPrint((1, " OEM Product Name: %s\n", OemProductName));
  267. VideoDebugPrint((1, " OEM Product Rev: %s\n", OemProductRev));
  268. UseVesa = IsVesaBiosOk(pInt10,
  269. InfoBlock->OemSoftwareRev,
  270. OemVendorName,
  271. OemProductName,
  272. OemProductRev);
  273. }
  274. VideoDebugPrint((1, "*********************************************\n"));
  275. #if 0
  276. //
  277. // It would be nice if we could dump the following info into the
  278. // registry. But as the GDI code currently stands, if we add
  279. // ChipType or AdapterString info into the registry, we lose
  280. // fullscreen support. This has to do with the way GDI currently
  281. // determines the fullscreen device.
  282. //
  283. // For now, lets just not add this registry info.
  284. //
  285. UpdateRegistry(hwDeviceExtension,
  286. L"HardwareInformation.ChipType",
  287. OemString);
  288. //
  289. // Adapter String MUST be VGA. Without it, the system won't
  290. // recognize this driver as the VGA driver.
  291. //
  292. UpdateRegistry(hwDeviceExtension,
  293. L"HardwareInformation.AdapterString",
  294. "VGA");
  295. UpdateRegistry(hwDeviceExtension,
  296. L"HardwareInformation.DacType",
  297. (InfoBlock->Capabilities & VBE_CAP_DAC_WIDTH_8BPP)
  298. ? "8 bit" : "6 bit");
  299. UpdateRegistry(hwDeviceExtension,
  300. L"HardwareInformation.BiosString",
  301. OemProductRev);
  302. //
  303. // Store memory size in registry
  304. //
  305. MemorySize = InfoBlock->TotalMemory << 16;
  306. VideoPortSetRegistryParameters(hwDeviceExtension,
  307. L"HardwareInformation.MemorySize",
  308. &MemorySize,
  309. sizeof(ULONG));
  310. #endif
  311. } else {
  312. VideoDebugPrint((0, "Invalid VBE Info Block.\n"));
  313. }
  314. return UseVesa;
  315. }
  316. VOID
  317. InitializeModeTable(
  318. PVOID HwDeviceExtension
  319. )
  320. /*++
  321. Routine Description:
  322. This routine does one time initialization of the device.
  323. Arguments:
  324. HwDeviceExtension - Pointer to the miniport driver's adapter information.
  325. Return Value:
  326. None.
  327. --*/
  328. {
  329. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  330. INT10_BIOS_ARGUMENTS BiosArguments;
  331. PVGA_INFO_BLOCK InfoBlock;
  332. PMODE_INFO_BLOCK ModeBlock;
  333. PUSHORT ModeTable;
  334. PUSHORT ModePtr;
  335. ULONG NumVesaModes;
  336. PVIDEOMODE VideoModePtr;
  337. LONG TotalMemory;
  338. ULONG VideoMemoryRequired;
  339. USHORT VbeVersion;
  340. PULONG Memory;
  341. ULONG AdditionalModes = 0;
  342. USHORT VdmSeg, VdmOff;
  343. VP_STATUS Status;
  344. PVIDEO_PORT_INT10_INTERFACE pInt10;
  345. ULONG Length = 0x1000;
  346. BOOLEAN LinearModeSupported;
  347. BOOLEAN ModeValid;
  348. hwDeviceExtension->Int10.Size = sizeof(VIDEO_PORT_INT10_INTERFACE);
  349. hwDeviceExtension->Int10.Version = 1;
  350. Status = VideoPortQueryServices(hwDeviceExtension,
  351. VideoPortServicesInt10,
  352. (PINTERFACE)&hwDeviceExtension->Int10);
  353. VgaModeList = ModesVGA;
  354. if (Status == NO_ERROR) {
  355. pInt10 = &hwDeviceExtension->Int10;
  356. pInt10->InterfaceReference(pInt10->Context);
  357. //
  358. // Get a chunk of memory in VDM area to use for buffers.
  359. //
  360. Status = pInt10->Int10AllocateBuffer(pInt10->Context,
  361. &VdmSeg,
  362. &VdmOff,
  363. &Length);
  364. if ((Status != NO_ERROR) || (Length < 0x1000)) {
  365. ASSERT(FALSE);
  366. }
  367. hwDeviceExtension->VdmSeg = VdmSeg;
  368. hwDeviceExtension->VdmOff = VdmOff;
  369. //
  370. // Allocate Memory
  371. //
  372. InfoBlock = VideoPortAllocatePool(hwDeviceExtension,
  373. VpPagedPool,
  374. sizeof(VGA_INFO_BLOCK) +
  375. sizeof(MODE_INFO_BLOCK) +
  376. 256 +
  377. 2, // space for a 0xffff terminator
  378. ' agV');
  379. if (InfoBlock) {
  380. ModeBlock = (PMODE_INFO_BLOCK)((ULONG_PTR)InfoBlock + sizeof(VGA_INFO_BLOCK));
  381. ModeTable = (PUSHORT)((ULONG_PTR)ModeBlock + sizeof(MODE_INFO_BLOCK));
  382. ModeTable[128] = 0xffff; // make sure we have a mode terminator
  383. //
  384. // Get VESA mode information
  385. //
  386. InfoBlock->VesaSignature = '2EBV';
  387. pInt10->Int10WriteMemory(pInt10->Context,
  388. VdmSeg,
  389. VdmOff,
  390. InfoBlock,
  391. sizeof(VGA_INFO_BLOCK));
  392. //
  393. // Get SuperVGA support info
  394. //
  395. BiosArguments.Eax = 0x4f00;
  396. BiosArguments.Edi = VdmOff;
  397. BiosArguments.SegEs = VdmSeg;
  398. pInt10->Int10CallBios(pInt10->Context, &BiosArguments);
  399. pInt10->Int10ReadMemory(pInt10->Context,
  400. VdmSeg,
  401. VdmOff,
  402. InfoBlock,
  403. sizeof(VGA_INFO_BLOCK));
  404. TotalMemory = InfoBlock->TotalMemory * 0x10000;
  405. VbeVersion = InfoBlock->VbeVersion;
  406. //
  407. // NOTE: We must call ValidateVbeInfo while the info block
  408. // is still in the transfer area.
  409. //
  410. if (ValidateVbeInfo(hwDeviceExtension, InfoBlock)) {
  411. //
  412. // Capture the list of mode numbers
  413. //
  414. pInt10->Int10ReadMemory(pInt10->Context,
  415. (USHORT)(InfoBlock->VideoModePtr >> 16),
  416. (USHORT)(InfoBlock->VideoModePtr & 0xffff),
  417. ModeTable,
  418. 256);
  419. //
  420. // Count the number of VESA modes, and allocate memory for the
  421. // mode list. The mode list is terminated by a -1.
  422. //
  423. ModePtr = ModeTable;
  424. NumVesaModes = 0;
  425. while (*ModePtr != 0xffff) {
  426. NumVesaModes++;
  427. ModePtr++;
  428. }
  429. if (NumVesaModes == 128) {
  430. //
  431. // Something is wrong. We hit our hard coded terminator.
  432. // Don't try to use vesa modes.
  433. //
  434. return;
  435. }
  436. VgaModeList = VideoPortAllocatePool(hwDeviceExtension,
  437. VpPagedPool,
  438. (NumVesaModes + NumVideoModes) *
  439. sizeof(VIDEOMODE),
  440. ' agV');
  441. if (VgaModeList == NULL) {
  442. VideoDebugPrint((0, "failed to allocate %d bytes.\n",
  443. (NumVesaModes + NumVideoModes) * sizeof(VIDEOMODE)));
  444. VgaModeList = ModesVGA;
  445. //
  446. // Perform clean up.
  447. //
  448. VideoPortFreePool(hwDeviceExtension, InfoBlock);
  449. return;
  450. }
  451. //
  452. // Copy the existing constant VGA modes into our mode list table.
  453. //
  454. memmove(VgaModeList, ModesVGA, sizeof(VIDEOMODE) * NumVideoModes);
  455. //
  456. // Now populate the rest of the table based on the VESA mode
  457. // table.
  458. //
  459. VideoModePtr = VgaModeList + NumVideoModes;
  460. ModePtr = ModeTable;
  461. while (NumVesaModes--) {
  462. ModeValid = FALSE;
  463. //
  464. // Get info about the VESA mode.
  465. //
  466. BiosArguments.Eax = 0x4f01;
  467. BiosArguments.Ecx = *ModePtr;
  468. BiosArguments.Edi = VdmOff;
  469. BiosArguments.SegEs = VdmSeg;
  470. pInt10->Int10CallBios(pInt10->Context, &BiosArguments);
  471. if ((BiosArguments.Eax & 0xffff) == VESA_STATUS_SUCCESS) {
  472. //
  473. // Copy the mode information out of the csrss process
  474. //
  475. pInt10->Int10ReadMemory(pInt10->Context,
  476. VdmSeg,
  477. VdmOff,
  478. ModeBlock,
  479. sizeof(MODE_INFO_BLOCK));
  480. //
  481. // Make sure that this is a graphics mode, and
  482. // that it is supported by this hardware.
  483. //
  484. if ((ModeBlock->ModeAttributes & 0x11) == 0x11) {
  485. if ((VbeVersion >= 0x200) &&
  486. (ModeBlock->PhysBasePtr) &&
  487. (ModeBlock->ModeAttributes & 0x80)) {
  488. LinearModeSupported = TRUE;
  489. } else {
  490. //
  491. // Make sure banked modes are supported
  492. //
  493. ASSERT((ModeBlock->ModeAttributes & 0x40) == 0);
  494. LinearModeSupported = FALSE;
  495. }
  496. //
  497. // Only include this mode if the following are true:
  498. //
  499. // 1. The mode is an 8bpp or higher mode
  500. // 2. The resolution is 640x480 or greater
  501. //
  502. if ((ModeBlock->XResolution >= 640) &&
  503. (ModeBlock->YResolution >= 480) &&
  504. (ModeBlock->NumberOfPlanes != 0) &&
  505. (ModeBlock->BitsPerPixel >= 8)) {
  506. //
  507. // Fill in the video mode structure.
  508. //
  509. memset(VideoModePtr, 0, sizeof(VIDEOMODE));
  510. if (ModeBlock->ModeAttributes & 0x08) {
  511. VideoModePtr->fbType |= VIDEO_MODE_COLOR;
  512. }
  513. if (ModeBlock->ModeAttributes & 0x10) {
  514. VideoModePtr->fbType |= VIDEO_MODE_GRAPHICS;
  515. }
  516. VideoModePtr->numPlanes = ModeBlock->NumberOfPlanes;
  517. VideoModePtr->bitsPerPlane = ModeBlock->BitsPerPixel /
  518. ModeBlock->NumberOfPlanes;
  519. if (VideoModePtr->bitsPerPlane == 16) {
  520. //
  521. // Check to see if this is really a 15 bpp mode
  522. //
  523. if (ModeBlock->GreenMaskSize == 5) {
  524. VideoModePtr->bitsPerPlane = 15;
  525. }
  526. }
  527. if (ModeBlock->XCharSize) {
  528. VideoModePtr->col = ModeBlock->XResolution / ModeBlock->XCharSize;
  529. } else {
  530. VideoModePtr->col = 80;
  531. }
  532. if (ModeBlock->YCharSize) {
  533. VideoModePtr->row = ModeBlock->YResolution / ModeBlock->YCharSize;
  534. } else {
  535. VideoModePtr->row = 25;
  536. }
  537. VideoModePtr->hres = ModeBlock->XResolution;
  538. VideoModePtr->vres = ModeBlock->YResolution;
  539. VideoModePtr->frequency = 1;
  540. VideoModePtr->Int10ModeNumber = (((ULONG)*ModePtr) << 16) | 0x00004f02;
  541. VideoModePtr->Granularity = ModeBlock->WinGranularity << 10;
  542. VideoModePtr->NonVgaHardware = (ModeBlock->ModeAttributes & 0x20) ? TRUE : FALSE;
  543. if (LinearModeSupported) {
  544. if (VbeVersion >= 0x300) {
  545. VideoModePtr->wbytes = ModeBlock->LinBytesPerScanLine;
  546. } else {
  547. VideoModePtr->wbytes = ModeBlock->BytesPerScanLine;
  548. }
  549. //
  550. // We first try to round up VideoMemoryRequired
  551. // to power of 2 so that we'll have a better
  552. // chance to get it mapped as write combined
  553. // on systems where MTRR is the only mechanism
  554. // for such mappings. If the rounded up value
  555. // is larger than the size of on-board memory
  556. // we'll at least round it up to page boundary
  557. //
  558. VideoMemoryRequired = RaiseToPower2Ulong(VideoModePtr->wbytes * VideoModePtr->vres);
  559. if(VideoMemoryRequired > (ULONG)TotalMemory) {
  560. VideoMemoryRequired =
  561. (VideoModePtr->wbytes * VideoModePtr->vres + 0x1000 - 1) & ~(0x1000 - 1);
  562. }
  563. VideoModePtr->sbytes = VideoMemoryRequired;
  564. VideoModePtr->PixelsPerScan = VideoModePtr->hres;
  565. VideoModePtr->banktype = NoBanking;
  566. VideoModePtr->Int10ModeNumber |= 0x40000000;
  567. VideoModePtr->MemoryBase = ModeBlock->PhysBasePtr;
  568. VideoModePtr->MemoryLength = VideoMemoryRequired;
  569. VideoModePtr->FrameOffset = 0;
  570. VideoModePtr->FrameLength = VideoMemoryRequired;
  571. VideoModePtr->fbType |= VIDEO_MODE_LINEAR;
  572. } else {
  573. VideoModePtr->wbytes = RaiseToPower2(ModeBlock->BytesPerScanLine);
  574. //
  575. // Round up to bank boundary if possible.
  576. //
  577. VideoMemoryRequired =
  578. (VideoModePtr->wbytes * VideoModePtr->vres + 0x10000 - 1) & ~(0x10000 - 1);
  579. if(VideoMemoryRequired > (ULONG)TotalMemory) {
  580. //
  581. // Round up to page boundary.
  582. //
  583. VideoMemoryRequired =
  584. (VideoModePtr->wbytes * VideoModePtr->vres + 0x1000 - 1) & ~(0x1000 - 1);
  585. }
  586. VideoModePtr->sbytes = VideoMemoryRequired;
  587. VideoModePtr->PixelsPerScan = RaiseToPower2(VideoModePtr->hres);
  588. VideoModePtr->banktype = VideoBanked1RW;
  589. VideoModePtr->MemoryBase = 0xa0000;
  590. VideoModePtr->MemoryLength = 0x10000;
  591. VideoModePtr->FrameOffset = 0;
  592. VideoModePtr->FrameLength = 0x10000;
  593. VideoModePtr->fbType |= VIDEO_MODE_BANKED;
  594. }
  595. if (ModeBlock->ModeAttributes & 0x40) {
  596. VideoModePtr->banktype = NormalBanking;
  597. }
  598. //
  599. // Make sure there is enough memory for the mode
  600. //
  601. if ((VideoModePtr->wbytes * VideoModePtr->vres) <= TotalMemory) {
  602. ModeValid = TRUE;
  603. }
  604. }
  605. }
  606. }
  607. if (ModeValid) {
  608. VideoDebugPrint((1, "Supported: %dx%dx%dbpp\n",
  609. VideoModePtr->hres,
  610. VideoModePtr->vres,
  611. VideoModePtr->bitsPerPlane));
  612. VideoModePtr++;
  613. AdditionalModes++;
  614. } else {
  615. VideoDebugPrint((1, "Rejecting: %dx%dx%dbpp\n",
  616. ModeBlock->XResolution,
  617. ModeBlock->YResolution,
  618. ModeBlock->BitsPerPixel));
  619. }
  620. ModePtr++;
  621. }
  622. //
  623. // Lets check to see if we can map the memory for one of these modes.
  624. // If not, don't support the extended modes.
  625. //
  626. // Note: this is a temporary hack, until I can implent the correct
  627. // fix.
  628. //
  629. VideoModePtr--;
  630. if (IS_LINEAR_MODE(VideoModePtr)) {
  631. PHYSICAL_ADDRESS Address;
  632. UCHAR inIoSpace = 0;
  633. Address.LowPart = VideoModePtr->MemoryBase;
  634. Address.HighPart = 0;
  635. #if defined(PLUG_AND_PLAY)
  636. inIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  637. #endif
  638. Memory = VideoPortGetDeviceBase(hwDeviceExtension,
  639. Address,
  640. 0x1000,
  641. inIoSpace);
  642. if (Memory) {
  643. VideoPortFreeDeviceBase(hwDeviceExtension, Memory);
  644. } else {
  645. //
  646. // We can't map the memory, so don't expose the extra modes.
  647. //
  648. VideoDebugPrint((0, "vga.sys: Mapping 0x%x failed\n", VideoModePtr->MemoryBase));
  649. AdditionalModes = 0;
  650. }
  651. }
  652. }
  653. VideoPortFreePool(hwDeviceExtension, InfoBlock);
  654. }
  655. }
  656. NumVideoModes += AdditionalModes;
  657. } // VgaInitialize()
  658. ULONG
  659. GetVideoMemoryBaseAddress(
  660. PHW_DEVICE_EXTENSION hwDeviceExtension,
  661. PVIDEOMODE pRequestedMode
  662. )
  663. /*++
  664. Routine Description:
  665. This routine get the base address of the framebuffer of a given mode
  666. Return Value:
  667. Base address of framebuffer
  668. --*/
  669. {
  670. PMODE_INFO_BLOCK ModeBlock;
  671. ULONG Length = 0x1000;
  672. INT10_BIOS_ARGUMENTS BiosArguments;
  673. PVIDEO_PORT_INT10_INTERFACE pInt10;
  674. ULONG RetValue;
  675. //
  676. // If this is not a vesa mode, just return the saved base address
  677. //
  678. if (pRequestedMode->fbType & VIDEO_MODE_BANKED) {
  679. return 0;
  680. }
  681. pInt10 = &hwDeviceExtension->Int10;
  682. if(!(pInt10->Size))
  683. {
  684. //
  685. // This structure should be initialized in VgaInitialize
  686. // If this function get called before VgaInitialize, just return 0;
  687. //
  688. return 0;
  689. }
  690. ModeBlock = VideoPortAllocatePool(hwDeviceExtension,
  691. VpPagedPool,
  692. sizeof(MODE_INFO_BLOCK),
  693. ' agV');
  694. if(!ModeBlock) {
  695. return 0;
  696. }
  697. //
  698. // Get info about the VESA mode.
  699. //
  700. BiosArguments.Eax = 0x4f01;
  701. BiosArguments.Ecx = pRequestedMode->Int10ModeNumber >> 16;
  702. BiosArguments.Edi = hwDeviceExtension->VdmOff;
  703. BiosArguments.SegEs = hwDeviceExtension->VdmSeg;
  704. pInt10->Int10CallBios(pInt10->Context, &BiosArguments);
  705. if ((BiosArguments.Eax & 0xffff) == VESA_STATUS_SUCCESS) {
  706. //
  707. // Copy the mode information out of the csrss process
  708. //
  709. pInt10->Int10ReadMemory(pInt10->Context,
  710. hwDeviceExtension->VdmSeg,
  711. hwDeviceExtension->VdmOff,
  712. ModeBlock,
  713. sizeof(MODE_INFO_BLOCK));
  714. RetValue = ModeBlock->PhysBasePtr;
  715. } else {
  716. RetValue = 0;
  717. }
  718. VideoPortFreePool(hwDeviceExtension, ModeBlock);
  719. return( RetValue );
  720. }
  721. VP_STATUS
  722. VBEGetModeInfo(
  723. PHW_DEVICE_EXTENSION hwDeviceExtension,
  724. USHORT ModeNumber,
  725. PMODE_INFO_BLOCK ModeInfoBlock
  726. )
  727. {
  728. INT10_BIOS_ARGUMENTS Int10BiosArguments;
  729. PVIDEO_PORT_INT10_INTERFACE pInt10;
  730. VP_STATUS status;
  731. pInt10 = &hwDeviceExtension->Int10;
  732. Int10BiosArguments.Eax = VBE_GET_MODE_INFO;
  733. Int10BiosArguments.Ecx = ModeNumber;
  734. Int10BiosArguments.Edi = hwDeviceExtension->VdmOff;
  735. Int10BiosArguments.SegEs = hwDeviceExtension->VdmSeg;
  736. status = pInt10->Int10CallBios(pInt10->Context, &Int10BiosArguments);
  737. if (status == NO_ERROR &&
  738. (Int10BiosArguments.Eax & 0xffff) == VESA_STATUS_SUCCESS) {
  739. //
  740. // Copy the mode information out of the csrss process
  741. //
  742. status = pInt10->Int10ReadMemory(pInt10->Context,
  743. hwDeviceExtension->VdmSeg,
  744. hwDeviceExtension->VdmOff,
  745. ModeInfoBlock,
  746. sizeof(MODE_INFO_BLOCK));
  747. if (status == NO_ERROR) {
  748. return NO_ERROR;
  749. }
  750. }
  751. return ERROR_INVALID_PARAMETER;
  752. }
  753. VP_STATUS
  754. VBESetMode(
  755. PHW_DEVICE_EXTENSION HwDeviceExtension,
  756. USHORT VesaModeNumber
  757. )
  758. {
  759. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  760. VP_STATUS status;
  761. biosArguments.Eax = VBE_SET_MODE;
  762. biosArguments.Ebx = VesaModeNumber;
  763. status = VideoPortInt10(HwDeviceExtension, &biosArguments);
  764. if ((status == NO_ERROR) &&
  765. ((biosArguments.Eax & 0x0000FFFF) == VESA_STATUS_SUCCESS)) {
  766. return NO_ERROR;
  767. }
  768. return ERROR_INVALID_PARAMETER;
  769. }
  770. USHORT
  771. VBEGetMode(
  772. PHW_DEVICE_EXTENSION HwDeviceExtension
  773. )
  774. {
  775. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  776. VP_STATUS status;
  777. biosArguments.Eax = VBE_GET_MODE;
  778. status = VideoPortInt10(HwDeviceExtension, &biosArguments);
  779. if ((status == NO_ERROR) &&
  780. ((biosArguments.Eax & 0x0000FFFF) == VESA_STATUS_SUCCESS)) {
  781. return (USHORT)(biosArguments.Ebx & 0x0000FFFF) ;
  782. } else {
  783. return 0;
  784. }
  785. }
  786. ULONG
  787. VBESaveState(
  788. PHW_DEVICE_EXTENSION hwDeviceExtension,
  789. PCHAR StateBuffer
  790. )
  791. {
  792. INT10_BIOS_ARGUMENTS Int10BiosArguments;
  793. PVIDEO_PORT_INT10_INTERFACE pInt10;
  794. VP_STATUS status;
  795. ULONG Size;
  796. pInt10 = &hwDeviceExtension->Int10;
  797. Int10BiosArguments.Eax = VBE_SAVE_RESTORE_STATE;
  798. Int10BiosArguments.Edx = 0x0;
  799. //
  800. // Save all the state
  801. //
  802. Int10BiosArguments.Ecx = 0x0F;
  803. status = pInt10->Int10CallBios(pInt10->Context, &Int10BiosArguments);
  804. if (status != NO_ERROR ||
  805. (Int10BiosArguments.Eax & 0xffff) != VESA_STATUS_SUCCESS) {
  806. return 0;
  807. }
  808. Size = (Int10BiosArguments.Ebx & 0xffff) << 6 ;
  809. //
  810. // if StateBuffer is NULL, the caller is only want to know the size
  811. // of the buffer needed to store the state
  812. //
  813. if (StateBuffer == NULL) {
  814. return Size;
  815. }
  816. Int10BiosArguments.Eax = VBE_SAVE_RESTORE_STATE;
  817. Int10BiosArguments.Edx = 0x1;
  818. Int10BiosArguments.Ecx = 0x0F;
  819. Int10BiosArguments.Ebx = hwDeviceExtension->VdmOff;
  820. Int10BiosArguments.SegEs = hwDeviceExtension->VdmSeg;
  821. status = pInt10->Int10CallBios(pInt10->Context, &Int10BiosArguments);
  822. if (status == NO_ERROR &&
  823. (Int10BiosArguments.Eax & 0xffff) == VESA_STATUS_SUCCESS) {
  824. //
  825. // Copy the state data of the csrss process
  826. //
  827. status = pInt10->Int10ReadMemory(pInt10->Context,
  828. hwDeviceExtension->VdmSeg,
  829. hwDeviceExtension->VdmOff,
  830. StateBuffer,
  831. Size);
  832. if (status == NO_ERROR) {
  833. return Size;
  834. }
  835. }
  836. return 0;
  837. }
  838. VP_STATUS
  839. VBERestoreState(
  840. PHW_DEVICE_EXTENSION hwDeviceExtension,
  841. PCHAR StateBuffer,
  842. ULONG Size
  843. )
  844. {
  845. INT10_BIOS_ARGUMENTS Int10BiosArguments;
  846. PVIDEO_PORT_INT10_INTERFACE pInt10;
  847. VP_STATUS status;
  848. pInt10 = &hwDeviceExtension->Int10;
  849. //
  850. // Copy the state data to the csrss process
  851. //
  852. status = pInt10->Int10WriteMemory(pInt10->Context,
  853. hwDeviceExtension->VdmSeg,
  854. hwDeviceExtension->VdmOff,
  855. StateBuffer,
  856. Size);
  857. if (status != NO_ERROR) {
  858. return ERROR_INVALID_PARAMETER;
  859. }
  860. Int10BiosArguments.Eax = VBE_SAVE_RESTORE_STATE;
  861. Int10BiosArguments.Edx = 0x2;
  862. Int10BiosArguments.Ecx = 0x0f;
  863. Int10BiosArguments.Ebx = hwDeviceExtension->VdmOff;
  864. Int10BiosArguments.SegEs = hwDeviceExtension->VdmSeg;
  865. status = pInt10->Int10CallBios(pInt10->Context, &Int10BiosArguments);
  866. if (status != NO_ERROR ||
  867. (Int10BiosArguments.Eax & 0xffff) != VESA_STATUS_SUCCESS) {
  868. return ERROR_INVALID_PARAMETER;
  869. }
  870. return NO_ERROR;
  871. }
  872. VP_STATUS
  873. VBESetDisplayWindow(
  874. PHW_DEVICE_EXTENSION hwDeviceExtension,
  875. UCHAR WindowSelect,
  876. USHORT WindowNumber
  877. )
  878. /*++
  879. Routine Description:
  880. This routine set the position of the specified window in the
  881. frame buffer memory
  882. Arguments:
  883. HwDeviceExtension
  884. Pointer to the miniport driver's adapter information.
  885. WindowSelect
  886. 0 for Window A and 1 for Window B
  887. WindowNumber
  888. Window number in video memory in window granularity units
  889. Return Value:
  890. VP_STATUS
  891. --*/
  892. {
  893. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  894. VP_STATUS status;
  895. biosArguments.Eax = VBE_WINDOW_CONTROL;
  896. biosArguments.Ebx = WindowSelect & 0x01;
  897. biosArguments.Edx = WindowNumber;
  898. status = VideoPortInt10(hwDeviceExtension, &biosArguments);
  899. if ((status != NO_ERROR) ||
  900. ((biosArguments.Eax & 0x0000FFFF) != VESA_STATUS_SUCCESS)) {
  901. return ERROR_INVALID_PARAMETER;
  902. }
  903. return NO_ERROR;
  904. }
  905. USHORT
  906. VBEGetDisplayWindow(
  907. PHW_DEVICE_EXTENSION hwDeviceExtension,
  908. UCHAR WindowSelect
  909. )
  910. /*++
  911. Routine Description:
  912. This routine set the position of the specified window in the
  913. frame buffer memory
  914. Arguments:
  915. HwDeviceExtension
  916. Pointer to the miniport driver's adapter information.
  917. WindowSelect
  918. 0 for Window A and 1 for Window B
  919. Return Value:
  920. Window number in video memory in window granularity units
  921. --*/
  922. {
  923. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  924. VP_STATUS status;
  925. biosArguments.Eax = VBE_WINDOW_CONTROL;
  926. biosArguments.Ebx = (WindowSelect & 0x1) | 0x100;
  927. status = VideoPortInt10(hwDeviceExtension, &biosArguments);
  928. if ((status != NO_ERROR) ||
  929. ((biosArguments.Eax & 0x0000FFFF) != VESA_STATUS_SUCCESS)) {
  930. return 0;
  931. }
  932. return ((USHORT)(biosArguments.Edx & 0xFFFF));
  933. }
  934. USHORT
  935. VBEGetScanLineLength(
  936. PHW_DEVICE_EXTENSION HwDeviceExtension
  937. )
  938. {
  939. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  940. VP_STATUS status;
  941. biosArguments.Eax = VBE_SCANLINE;
  942. biosArguments.Ebx = 0x1;
  943. status = VideoPortInt10(HwDeviceExtension, &biosArguments);
  944. if ((status == NO_ERROR) &&
  945. ((biosArguments.Eax & 0x0000FFFF) == VESA_STATUS_SUCCESS)) {
  946. return (USHORT)(biosArguments.Ebx & 0x0000FFFF) ;
  947. } else {
  948. return 0;
  949. }
  950. }
  951. VP_STATUS
  952. VesaSaveHardwareState(
  953. PHW_DEVICE_EXTENSION HwDeviceExtension,
  954. PVIDEO_HARDWARE_STATE HardwareState,
  955. ULONG HardwareStateSize,
  956. USHORT ModeNumber
  957. )
  958. {
  959. PVIDEO_HARDWARE_STATE_HEADER hardwareStateHeader;
  960. VP_STATUS status;
  961. ULONG FrameBufferSize;
  962. PMODE_INFO_BLOCK ModeInfoBlock;
  963. PVESA_INFO pVesaInfo;
  964. hardwareStateHeader =
  965. (PVIDEO_HARDWARE_STATE_HEADER) HardwareState->StateHeader;
  966. //
  967. // Zero out the structure
  968. //
  969. VideoPortZeroMemory((PVOID) hardwareStateHeader,
  970. sizeof(VIDEO_HARDWARE_STATE_HEADER));
  971. //
  972. // Set the Header field
  973. //
  974. hardwareStateHeader->Length = sizeof(VIDEO_HARDWARE_STATE_HEADER);
  975. hardwareStateHeader->VGAStateFlags |= VIDEO_STATE_UNEMULATED_VGA_STATE;
  976. hardwareStateHeader->VesaInfoOffset =
  977. (sizeof(VIDEO_HARDWARE_STATE_HEADER) + 7) & ~7;
  978. pVesaInfo = (PVESA_INFO)((PCHAR)hardwareStateHeader +
  979. hardwareStateHeader->VesaInfoOffset);
  980. //
  981. // Check the size needed to store hardware state
  982. //
  983. if (!(pVesaInfo->HardwareStateSize =
  984. VBESaveState(HwDeviceExtension, NULL))) {
  985. return ERROR_INVALID_FUNCTION;
  986. }
  987. //
  988. // In the case the size needed is too big just retrun failure
  989. // This should not happen in reality
  990. //
  991. if( VGA_TOTAL_STATE_SIZE < hardwareStateHeader->VesaInfoOffset +
  992. sizeof(VESA_INFO) +
  993. pVesaInfo->HardwareStateSize) {
  994. return ERROR_INVALID_FUNCTION;
  995. }
  996. //
  997. // Save hardware state
  998. //
  999. if (pVesaInfo->HardwareStateSize !=
  1000. VBESaveState(HwDeviceExtension, pVesaInfo->HardwareState)) {
  1001. return ERROR_INVALID_FUNCTION;
  1002. }
  1003. pVesaInfo->ModeNumber = ModeNumber;
  1004. ModeInfoBlock = &(pVesaInfo->ModeInfoBlock);
  1005. //
  1006. // Retrieve mode info
  1007. //
  1008. if( VBEGetModeInfo(HwDeviceExtension,
  1009. ModeNumber,
  1010. ModeInfoBlock) != NO_ERROR) {
  1011. return ERROR_INVALID_FUNCTION;
  1012. }
  1013. //
  1014. // Save framebuffer
  1015. //
  1016. hardwareStateHeader->FrameBufferData =
  1017. SaveFrameBuffer(HwDeviceExtension, pVesaInfo);
  1018. if(hardwareStateHeader->FrameBufferData) {
  1019. return NO_ERROR;
  1020. } else {
  1021. return ERROR_NOT_ENOUGH_MEMORY;
  1022. }
  1023. }
  1024. PCHAR
  1025. SaveFrameBuffer(
  1026. PHW_DEVICE_EXTENSION hwDeviceExtension,
  1027. PVESA_INFO pVesaInfo
  1028. )
  1029. {
  1030. ULONG FrameBufferSize, BankSize, CopySize, LeftSize, k;
  1031. USHORT i;
  1032. PCHAR FrameBufferData, pFrameBuffer;
  1033. PHYSICAL_ADDRESS FBPhysicalAddress;
  1034. PMODE_INFO_BLOCK ModeInfoBlock;
  1035. ModeInfoBlock = (PMODE_INFO_BLOCK) &(pVesaInfo->ModeInfoBlock);
  1036. //
  1037. // We'll try to get the current value of scanline size just in case a DOS
  1038. // app changed it. But we stay on the value we have if the vesa function
  1039. // is not supported or failed.
  1040. //
  1041. i = VBEGetScanLineLength(hwDeviceExtension);
  1042. if(i) {
  1043. ModeInfoBlock->BytesPerScanLine = i;
  1044. }
  1045. //
  1046. // 1) Calculate Framebuffer size
  1047. //
  1048. //
  1049. // Check if it is graphics or text mode. For text mode we simply
  1050. // assume a size of 32k
  1051. //
  1052. if (ModeInfoBlock->ModeAttributes & 0x10) {
  1053. FrameBufferSize = ModeInfoBlock->BytesPerScanLine *
  1054. ModeInfoBlock->YResolution;
  1055. } else {
  1056. FrameBufferSize = 0x8000;
  1057. }
  1058. pVesaInfo->FrameBufferSize = FrameBufferSize;
  1059. //
  1060. // 2) Determine the location and the size to be mapped and map it
  1061. //
  1062. if (!(ModeInfoBlock->ModeAttributes & 0x10)) {
  1063. //
  1064. // This is a text mode
  1065. //
  1066. FBPhysicalAddress.HighPart = 0;
  1067. FBPhysicalAddress.LowPart = ModeInfoBlock->WinASegment << 4;
  1068. if( FBPhysicalAddress.LowPart == 0) {
  1069. FBPhysicalAddress.LowPart = 0xB8000;
  1070. }
  1071. BankSize = 0x8000;
  1072. } else if (pVesaInfo->ModeNumber & 0x4000) {
  1073. //
  1074. // Linear framebuffer can be viewed as one large bank
  1075. //
  1076. FBPhysicalAddress.LowPart = ModeInfoBlock->PhysBasePtr;
  1077. FBPhysicalAddress.HighPart = 0;
  1078. BankSize = FrameBufferSize;
  1079. } else {
  1080. //
  1081. // This is a banked mode
  1082. //
  1083. FBPhysicalAddress.HighPart = 0;
  1084. FBPhysicalAddress.LowPart = ModeInfoBlock->WinASegment << 4;
  1085. if( FBPhysicalAddress.LowPart == 0) {
  1086. FBPhysicalAddress.LowPart = 0xA0000;
  1087. }
  1088. BankSize = 1024 * ModeInfoBlock->WinSize;
  1089. //
  1090. // The bank size shouldn't exceed 64k. But we'd better guard
  1091. // the bad BIOS
  1092. //
  1093. if(BankSize > 0x10000 || BankSize == 0) {
  1094. return NULL;
  1095. }
  1096. //
  1097. // k will be used later to translate the window number
  1098. // in the unit of WinSize to the window number in the
  1099. // unit of WinGranularity
  1100. //
  1101. if (ModeInfoBlock->WinGranularity) {
  1102. k = ModeInfoBlock->WinSize/ModeInfoBlock->WinGranularity;
  1103. } else {
  1104. k = 1;
  1105. }
  1106. }
  1107. if(( pFrameBuffer = VideoPortGetDeviceBase(hwDeviceExtension,
  1108. FBPhysicalAddress,
  1109. BankSize,
  1110. FALSE)) == NULL ) {
  1111. return NULL;
  1112. }
  1113. //
  1114. // 3) Allocate memory for framebuffer data
  1115. //
  1116. if((FrameBufferData = VideoPortAllocatePool(hwDeviceExtension,
  1117. VpPagedPool,
  1118. FrameBufferSize,
  1119. ' agV')) == NULL) {
  1120. VideoPortFreeDeviceBase(hwDeviceExtension, pFrameBuffer);
  1121. return NULL;
  1122. }
  1123. //
  1124. // 4) Save famebuffer data
  1125. //
  1126. LeftSize = FrameBufferSize;
  1127. for ( i = 0; LeftSize > 0; i++ ) {
  1128. if (!(pVesaInfo->ModeNumber & 0x4000)) {
  1129. //
  1130. // If this is a banked mode, switch to the right bank.
  1131. // We set both Window A and B, as some VBEs have these
  1132. // set as separately available read and write windows.
  1133. //
  1134. VBESetDisplayWindow(hwDeviceExtension, 0, i * (USHORT)k);
  1135. VBESetDisplayWindow(hwDeviceExtension, 1, i * (USHORT)k);
  1136. }
  1137. CopySize = (LeftSize < BankSize) ? LeftSize : BankSize;
  1138. VideoPortMoveMemory(FrameBufferData + i * BankSize,
  1139. pFrameBuffer,
  1140. CopySize);
  1141. LeftSize -= CopySize;
  1142. }
  1143. //
  1144. // 5) Relese resource
  1145. //
  1146. VideoPortFreeDeviceBase(hwDeviceExtension, pFrameBuffer);
  1147. return FrameBufferData;
  1148. }
  1149. BOOLEAN
  1150. IsSavedModeVesa(
  1151. PVIDEO_HARDWARE_STATE HardwareState
  1152. )
  1153. {
  1154. PVIDEO_HARDWARE_STATE_HEADER hardwareStateHeader;
  1155. hardwareStateHeader =
  1156. (PVIDEO_HARDWARE_STATE_HEADER) HardwareState->StateHeader;
  1157. if (hardwareStateHeader->Length == sizeof(VIDEO_HARDWARE_STATE_HEADER) &&
  1158. hardwareStateHeader->VesaInfoOffset ) {
  1159. return TRUE;
  1160. } else {
  1161. return FALSE;
  1162. }
  1163. }
  1164. VP_STATUS
  1165. VesaRestoreHardwareState(
  1166. PHW_DEVICE_EXTENSION HwDeviceExtension,
  1167. PVIDEO_HARDWARE_STATE HardwareState,
  1168. ULONG HardwareStateSize
  1169. )
  1170. {
  1171. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  1172. PVIDEO_HARDWARE_STATE_HEADER hardwareStateHeader;
  1173. PMODE_INFO_BLOCK ModeInfoBlock;
  1174. PVESA_INFO pVesaInfo;
  1175. VP_STATUS status;
  1176. hardwareStateHeader =
  1177. (PVIDEO_HARDWARE_STATE_HEADER) HardwareState->StateHeader;
  1178. pVesaInfo = (PVESA_INFO)((PCHAR)hardwareStateHeader +
  1179. hardwareStateHeader->VesaInfoOffset);
  1180. //
  1181. //
  1182. // 1) set the original mode
  1183. // 2) restore hardware state
  1184. //
  1185. // Please note that both steps are necessary
  1186. //
  1187. //
  1188. // We always use default CRTC value
  1189. //
  1190. VBESetMode (HwDeviceExtension, pVesaInfo->ModeNumber & (~0x800));
  1191. if ( VBERestoreState(HwDeviceExtension,
  1192. pVesaInfo->HardwareState,
  1193. pVesaInfo->HardwareStateSize) != NO_ERROR ) {
  1194. return ERROR_INVALID_FUNCTION;
  1195. }
  1196. ModeInfoBlock = (PMODE_INFO_BLOCK) &(pVesaInfo->ModeInfoBlock);
  1197. //
  1198. // Restore framebuffer data
  1199. //
  1200. if(RestoreFrameBuffer(HwDeviceExtension,
  1201. pVesaInfo,
  1202. hardwareStateHeader->FrameBufferData)) {
  1203. hardwareStateHeader->FrameBufferData = 0;
  1204. return NO_ERROR;
  1205. } else {
  1206. return ERROR_INVALID_PARAMETER;
  1207. }
  1208. }
  1209. ULONG
  1210. RestoreFrameBuffer(
  1211. PHW_DEVICE_EXTENSION HwDeviceExtension,
  1212. PVESA_INFO pVesaInfo,
  1213. PCHAR FrameBufferData
  1214. )
  1215. {
  1216. ULONG FrameBufferSize, BankSize, CopySize, LeftSize, k;
  1217. PHYSICAL_ADDRESS FBPhysicalAddress;
  1218. USHORT i, WinA, WinB;
  1219. PCHAR pFrameBuffer;
  1220. PMODE_INFO_BLOCK ModeInfoBlock;
  1221. if(!FrameBufferData) {
  1222. return 0;
  1223. }
  1224. ModeInfoBlock = (PMODE_INFO_BLOCK) &(pVesaInfo->ModeInfoBlock);
  1225. //
  1226. // 1) Get Framebuffer size
  1227. //
  1228. FrameBufferSize = pVesaInfo->FrameBufferSize;
  1229. if (!FrameBufferSize) {
  1230. return 0;
  1231. }
  1232. //
  1233. // 2) Determine the location and the size to be mapped and map it
  1234. //
  1235. if (!(ModeInfoBlock->ModeAttributes & 0x10)) {
  1236. //
  1237. // This is a text mode
  1238. //
  1239. FBPhysicalAddress.HighPart = 0;
  1240. FBPhysicalAddress.LowPart = ModeInfoBlock->WinASegment << 4;
  1241. if( FBPhysicalAddress.LowPart == 0) {
  1242. FBPhysicalAddress.LowPart = 0xB8000;
  1243. }
  1244. BankSize = 0x8000;
  1245. } else if (pVesaInfo->ModeNumber & 0x4000) {
  1246. //
  1247. // Linear framebuffer can be viewed as one large bank
  1248. //
  1249. FBPhysicalAddress.LowPart = ModeInfoBlock->PhysBasePtr;
  1250. FBPhysicalAddress.HighPart = 0;
  1251. BankSize = FrameBufferSize;
  1252. } else {
  1253. //
  1254. // This is a banked mode
  1255. //
  1256. FBPhysicalAddress.HighPart = 0;
  1257. FBPhysicalAddress.LowPart = ModeInfoBlock->WinASegment << 4;
  1258. if( FBPhysicalAddress.LowPart == 0) {
  1259. FBPhysicalAddress.LowPart = 0xA0000;
  1260. }
  1261. BankSize = 1024 * ModeInfoBlock->WinSize;
  1262. //
  1263. // The bank size shouldn't exceed 64k. But we'd better guard
  1264. // the bad BIOS
  1265. //
  1266. if(BankSize > 0x10000 || BankSize == 0) {
  1267. return 0;
  1268. }
  1269. //
  1270. // k will be used later to translate the window number
  1271. // in the unit of WinSize to the window number in the
  1272. // unit of WinGranularity
  1273. //
  1274. if (ModeInfoBlock->WinGranularity) {
  1275. k = ModeInfoBlock->WinSize/ModeInfoBlock->WinGranularity;
  1276. } else {
  1277. k = 1;
  1278. }
  1279. }
  1280. if((pFrameBuffer = VideoPortGetDeviceBase(HwDeviceExtension,
  1281. FBPhysicalAddress,
  1282. FrameBufferSize,
  1283. FALSE)) == NULL) {
  1284. return 0;
  1285. }
  1286. //
  1287. // 3) Restore framebuffer data
  1288. //
  1289. //
  1290. // For banked mode we need to save the current bank number before
  1291. // we change it.
  1292. //
  1293. if (!(pVesaInfo->ModeNumber & 0x4000)) {
  1294. //
  1295. // We need to save the curren window number for banked mode
  1296. //
  1297. WinA = VBEGetDisplayWindow(HwDeviceExtension, 0);
  1298. WinB = VBEGetDisplayWindow(HwDeviceExtension, 1);
  1299. }
  1300. LeftSize = FrameBufferSize;
  1301. for (i = 0; LeftSize > 0; i++) {
  1302. if (!(pVesaInfo->ModeNumber & 0x4000)) {
  1303. //
  1304. // This is a banked mode.
  1305. //
  1306. // We need set both Window A and B, as some VBEs have these
  1307. // set as separately available read and write windows.
  1308. //
  1309. VBESetDisplayWindow(HwDeviceExtension, 0, i * (USHORT)k);
  1310. VBESetDisplayWindow(HwDeviceExtension, 1, i * (USHORT)k);
  1311. }
  1312. CopySize = (LeftSize < BankSize) ? LeftSize : BankSize;
  1313. VideoPortMoveMemory(pFrameBuffer,
  1314. FrameBufferData + i * BankSize,
  1315. CopySize);
  1316. LeftSize -= CopySize;
  1317. }
  1318. if (!(pVesaInfo->ModeNumber & 0x4000)) {
  1319. //
  1320. // For banked mode we need to restore the window number after
  1321. // we changed it.
  1322. //
  1323. VBESetDisplayWindow(HwDeviceExtension, 0, WinA);
  1324. VBESetDisplayWindow(HwDeviceExtension, 1, WinB);
  1325. }
  1326. //
  1327. // 4) Relese resource
  1328. //
  1329. VideoPortFreeDeviceBase(HwDeviceExtension, pFrameBuffer);
  1330. VideoPortFreePool(HwDeviceExtension, FrameBufferData);
  1331. return FrameBufferSize;
  1332. }