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.

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