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.

6226 lines
179 KiB

  1. /*++
  2. Copyright (c) 1990-1997 Microsoft Corporation
  3. Module Name:
  4. s3.c
  5. Abstract:
  6. This module contains the code that implements the S3 miniport driver.
  7. Environment:
  8. Kernel mode
  9. Revision History:
  10. --*/
  11. #include "s3.h"
  12. #include "cmdcnst.h"
  13. #if defined(ALLOC_PRAGMA)
  14. #pragma alloc_text(PAGE,DriverEntry)
  15. #pragma alloc_text(PAGE,S3FindAdapter)
  16. #pragma alloc_text(PAGE,S3RegistryCallback)
  17. #pragma alloc_text(PAGE,S3Initialize)
  18. #pragma alloc_text(PAGE,S3StartIO)
  19. #pragma alloc_text(PAGE,S3SetColorLookup)
  20. #pragma alloc_text(PAGE,CompareRom)
  21. #pragma alloc_text(PAGE,LockExtendedRegs)
  22. #pragma alloc_text(PAGE,UnlockExtendedRegs)
  23. #pragma alloc_text(PAGE,S3RecordChipType)
  24. #pragma alloc_text(PAGE,S3IsaDetection)
  25. #pragma alloc_text(PAGE,S3GetInfo)
  26. #pragma alloc_text(PAGE,S3DetermineFrequencyTable)
  27. #pragma alloc_text(PAGE,S3DetermineDACType)
  28. #pragma alloc_text(PAGE,S3DetermineMemorySize)
  29. #pragma alloc_text(PAGE,S3ValidateModes)
  30. #pragma alloc_text(PAGE,AlphaDetermineMemoryUsage)
  31. #pragma alloc_text(PAGE, Set_Oem_Clock)
  32. #pragma alloc_text(PAGE,Set864MemoryTiming)
  33. #pragma alloc_text(PAGE,QueryStreamsParameters)
  34. /*****************************************************************************
  35. *
  36. * IMPORTANT:
  37. *
  38. * SetHWMode is called from within S3ResetHw. Paging will be disabled during
  39. * calls to S3ResetHw. Because of this S3ResetHw and all of the routines
  40. * it calls can not be pageable.
  41. *
  42. ****************************************************************************/
  43. // #pragma alloc_text(PAGE, S3ResetHW)
  44. // #pragma alloc_text(PAGE, ZeroMemAndDac)
  45. // #pragma alloc_text(PAGE, SetHWMode)
  46. // #pragma alloc_text(PAGE, Wait_Vsync)
  47. #if (_WIN32_WINNT >= 0x500)
  48. #pragma alloc_text(PAGE, S3GetChildDescriptor)
  49. #pragma alloc_text(PAGE, S3GetPowerState)
  50. #pragma alloc_text(PAGE, S3SetPowerState)
  51. #endif
  52. #endif
  53. #define QUERY_MONITOR_ID 0x22446688
  54. #define QUERY_NONDDC_MONITOR_ID 0x11223344
  55. ULONG
  56. DriverEntry (
  57. PVOID Context1,
  58. PVOID Context2
  59. )
  60. /*++
  61. Routine Description:
  62. Installable driver initialization entry point.
  63. This entry point is called directly by the I/O system.
  64. Arguments:
  65. Context1 - First context value passed by the operating system. This is
  66. the value with which the miniport driver calls VideoPortInitialize().
  67. Context2 - Second context value passed by the operating system. This is
  68. the value with which the miniport driver calls VideoPortInitialize().
  69. Return Value:
  70. Status from VideoPortInitialize()
  71. --*/
  72. {
  73. VIDEO_HW_INITIALIZATION_DATA hwInitData;
  74. ULONG initializationStatus;
  75. ULONG status;
  76. //
  77. // Zero out structure.
  78. //
  79. VideoPortZeroMemory(&hwInitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));
  80. //
  81. // Specify sizes of structure and extension.
  82. //
  83. hwInitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
  84. //
  85. // Set entry points.
  86. //
  87. hwInitData.HwFindAdapter = S3FindAdapter;
  88. hwInitData.HwInitialize = S3Initialize;
  89. hwInitData.HwInterrupt = NULL;
  90. hwInitData.HwStartIO = S3StartIO;
  91. hwInitData.HwResetHw = S3ResetHw;
  92. //
  93. // New NT 5.0 EntryPoint
  94. //
  95. #if (_WIN32_WINNT >= 0x500)
  96. hwInitData.HwGetVideoChildDescriptor = S3GetChildDescriptor;
  97. hwInitData.HwGetPowerState = S3GetPowerState;
  98. hwInitData.HwSetPowerState = S3SetPowerState;
  99. hwInitData.HwLegacyResourceList = S3AccessRanges;
  100. hwInitData.HwLegacyResourceCount = NUM_S3_ACCESS_RANGES;
  101. #endif
  102. //
  103. // Determine the size we require for the device extension.
  104. //
  105. hwInitData.HwDeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
  106. //
  107. // Always start with parameters for device0 in this case.
  108. //
  109. // hwInitData.StartingDeviceNumber = 0;
  110. //
  111. // Once all the relevant information has been stored, call the video
  112. // port driver to do the initialization.
  113. // For this device we will repeat this call four times, for ISA, EISA
  114. // Internal and PCI.
  115. // We will return the minimum of all return values.
  116. //
  117. //
  118. // We will try the PCI bus first so that our ISA detection does'nt claim
  119. // PCI cards.
  120. //
  121. //
  122. // NOTE: since this driver only supports one adapter, we will return
  123. // as soon as we find a device, without going on to the following buses.
  124. // Normally one would call for each bus type and return the smallest
  125. // value.
  126. //
  127. hwInitData.AdapterInterfaceType = PCIBus;
  128. initializationStatus = VideoPortInitialize(Context1,
  129. Context2,
  130. &hwInitData,
  131. NULL);
  132. if (initializationStatus == NO_ERROR)
  133. {
  134. return initializationStatus;
  135. }
  136. hwInitData.AdapterInterfaceType = MicroChannel;
  137. initializationStatus = VideoPortInitialize(Context1,
  138. Context2,
  139. &hwInitData,
  140. NULL);
  141. //
  142. // Return immediately instead of checkin for smallest return code.
  143. //
  144. if (initializationStatus == NO_ERROR)
  145. {
  146. return initializationStatus;
  147. }
  148. hwInitData.AdapterInterfaceType = Isa;
  149. initializationStatus = VideoPortInitialize(Context1,
  150. Context2,
  151. &hwInitData,
  152. NULL);
  153. //
  154. // Return immediately instead of checkin for smallest return code.
  155. //
  156. if (initializationStatus == NO_ERROR)
  157. {
  158. return initializationStatus;
  159. }
  160. hwInitData.AdapterInterfaceType = Eisa;
  161. initializationStatus = VideoPortInitialize(Context1,
  162. Context2,
  163. &hwInitData,
  164. NULL);
  165. //
  166. // Return immediately instead of checkin for smallest return code.
  167. //
  168. if (initializationStatus == NO_ERROR)
  169. {
  170. return initializationStatus;
  171. }
  172. hwInitData.AdapterInterfaceType = Internal;
  173. initializationStatus = VideoPortInitialize(Context1,
  174. Context2,
  175. &hwInitData,
  176. NULL);
  177. return initializationStatus;
  178. } // end DriverEntry()
  179. ULONG
  180. S3GetChildDescriptor(
  181. PVOID HwDeviceExtension,
  182. PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
  183. PVIDEO_CHILD_TYPE pChildType,
  184. PVOID pvChildDescriptor,
  185. PULONG pHwId,
  186. PULONG pUnused
  187. )
  188. /*++
  189. Routine Description:
  190. Enumerate all devices controlled by the ATI graphics chip.
  191. This includes DDC monitors attached to the board, as well as other devices
  192. which may be connected to a proprietary bus.
  193. Arguments:
  194. HwDeviceExtension - Pointer to our hardware device extension structure.
  195. ChildIndex - Index of the child the system wants informaion for.
  196. pChildType - Type of child we are enumerating - monitor, I2C ...
  197. pChildDescriptor - Identification structure of the device (EDID, string)
  198. ppHwId - Private unique 32 bit ID to passed back to the miniport
  199. pMoreChildren - Should the miniport be called
  200. Return Value:
  201. TRUE if the child device existed, FALSE if it did not.
  202. Note:
  203. In the event of a failure return, none of the fields are valid except for
  204. the return value and the pMoreChildren field.
  205. --*/
  206. {
  207. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  208. ULONG Status;
  209. switch (ChildEnumInfo->ChildIndex) {
  210. case 0:
  211. //
  212. // Case 0 is used to enumerate devices found by the ACPI firmware.
  213. //
  214. // Since we do not support ACPI devices yet, we must return failure.
  215. //
  216. Status = ERROR_NO_MORE_DEVICES;
  217. break;
  218. case 1:
  219. //
  220. // This is the last device we enumerate. Tell the system we don't
  221. // have any more.
  222. //
  223. *pChildType = Monitor;
  224. //
  225. // Obtain the EDID structure via DDC.
  226. //
  227. if (GetDdcInformation(HwDeviceExtension,
  228. pvChildDescriptor,
  229. ChildEnumInfo->ChildDescriptorSize))
  230. {
  231. *pHwId = QUERY_MONITOR_ID;
  232. VideoDebugPrint((1, "S3GetChildDescriptor - successfully read EDID structure\n"));
  233. } else {
  234. //
  235. // Alway return TRUE, since we always have a monitor output
  236. // on the card and it just may not be a detectable device.
  237. //
  238. *pHwId = QUERY_NONDDC_MONITOR_ID;
  239. VideoDebugPrint((1, "S3GetChildDescriptor - DDC not supported\n"));
  240. }
  241. Status = ERROR_MORE_DATA;
  242. break;
  243. case DISPLAY_ADAPTER_HW_ID:
  244. //
  245. // Special ID to handle return legacy PnP IDs for root enumerated
  246. // devices.
  247. //
  248. *pChildType = VideoChip;
  249. *pHwId = DISPLAY_ADAPTER_HW_ID;
  250. if ( (hwDeviceExtension->ChipID == S3_911) ||
  251. (hwDeviceExtension->ChipID == S3_928) )
  252. {
  253. memcpy(pvChildDescriptor, L"*PNP0909", sizeof(L"*PNP0909"));
  254. }
  255. else
  256. {
  257. memcpy(pvChildDescriptor, L"*PNP0913", sizeof(L"*PNP0913"));
  258. }
  259. Status = ERROR_MORE_DATA;
  260. break;
  261. default:
  262. Status = ERROR_NO_MORE_DEVICES;
  263. break;
  264. }
  265. return Status;
  266. }
  267. VP_STATUS
  268. S3GetPowerState(
  269. PHW_DEVICE_EXTENSION HwDeviceExtension,
  270. ULONG HwDeviceId,
  271. PVIDEO_POWER_MANAGEMENT VideoPowerManagement
  272. )
  273. /*++
  274. Routine Description:
  275. This function is called to see if a given device can go into a given
  276. power state.
  277. Arguments:
  278. HwDeviceExtension - Pointer to our hardware device extension structure.
  279. HwDeviceId - Private unique 32 bit ID identifing the device.
  280. 0xFFFFFFFF indicates the S3 card itself.
  281. VideoPowerManagement - Pointer to the power management structure which
  282. indicates the power state in question.
  283. Return Value:
  284. NO_ERROR if the device can go into the requested power state,
  285. otherwise an appropriate error code is returned.
  286. --*/
  287. {
  288. //
  289. // We only support power setting for the monitor. Make sure the
  290. // HwDeviceId matches one the the monitors we could report.
  291. //
  292. if ((HwDeviceId == QUERY_NONDDC_MONITOR_ID) ||
  293. (HwDeviceId == QUERY_MONITOR_ID)) {
  294. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  295. //
  296. // We are querying the power support for the monitor.
  297. //
  298. if ((VideoPowerManagement->PowerState == VideoPowerOn) ||
  299. (VideoPowerManagement->PowerState == VideoPowerHibernate) ||
  300. (VideoPowerManagement->PowerState == VideoPowerShutdown)) {
  301. return NO_ERROR;
  302. }
  303. VideoPortZeroMemory(&biosArguments, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
  304. biosArguments.Eax = VESA_POWER_FUNCTION;
  305. biosArguments.Ebx = VESA_GET_POWER_FUNC;
  306. VideoPortInt10(HwDeviceExtension, &biosArguments);
  307. if ((biosArguments.Eax & 0xffff) == VESA_STATUS_SUCCESS) {
  308. switch (VideoPowerManagement->PowerState) {
  309. case VideoPowerStandBy:
  310. return (biosArguments.Ebx & VESA_POWER_STANDBY) ?
  311. NO_ERROR : ERROR_INVALID_FUNCTION;
  312. case VideoPowerSuspend:
  313. return (biosArguments.Ebx & VESA_POWER_SUSPEND) ?
  314. NO_ERROR : ERROR_INVALID_FUNCTION;
  315. case VideoPowerOff:
  316. return (biosArguments.Ebx & VESA_POWER_OFF) ?
  317. NO_ERROR : ERROR_INVALID_FUNCTION;
  318. default:
  319. break;
  320. }
  321. }
  322. VideoDebugPrint((1, "This device does not support Power Management.\n"));
  323. return ERROR_INVALID_FUNCTION;
  324. } else if (HwDeviceId == DISPLAY_ADAPTER_HW_ID) {
  325. //
  326. // We are querying power support for the graphics card.
  327. //
  328. switch (VideoPowerManagement->PowerState) {
  329. case VideoPowerStandBy:
  330. case VideoPowerOn:
  331. case VideoPowerHibernate:
  332. case VideoPowerShutdown:
  333. return NO_ERROR;
  334. case VideoPowerOff:
  335. case VideoPowerSuspend:
  336. //
  337. // Indicate that we can't do VideoPowerOff, because
  338. // we have no way of coming back when power is re-applied
  339. // to the card.
  340. //
  341. return ERROR_INVALID_FUNCTION;
  342. default:
  343. ASSERT(FALSE);
  344. return ERROR_INVALID_PARAMETER;
  345. }
  346. } else {
  347. VideoDebugPrint((1, "Unknown HwDeviceId"));
  348. ASSERT(FALSE);
  349. return ERROR_INVALID_PARAMETER;
  350. }
  351. }
  352. VP_STATUS
  353. S3SetPowerState(
  354. PHW_DEVICE_EXTENSION HwDeviceExtension,
  355. ULONG HwDeviceId,
  356. PVIDEO_POWER_MANAGEMENT VideoPowerManagement
  357. )
  358. /*++
  359. Routine Description:
  360. Set the power state for a given device.
  361. Arguments:
  362. HwDeviceExtension - Pointer to our hardware device extension structure.
  363. HwDeviceId - Private unique 32 bit ID identifing the device.
  364. VideoPowerManagement - Power state information.
  365. Return Value:
  366. TRUE if power state can be set,
  367. FALSE otherwise.
  368. --*/
  369. {
  370. //
  371. // Make sure we recognize the device.
  372. //
  373. if ((HwDeviceId == QUERY_NONDDC_MONITOR_ID) ||
  374. (HwDeviceId == QUERY_MONITOR_ID)) {
  375. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  376. VideoPortZeroMemory(&biosArguments, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
  377. biosArguments.Eax = VESA_POWER_FUNCTION;
  378. biosArguments.Ebx = VESA_SET_POWER_FUNC;
  379. switch (VideoPowerManagement->PowerState) {
  380. case VideoPowerOn:
  381. case VideoPowerHibernate:
  382. biosArguments.Ebx |= VESA_POWER_ON;
  383. break;
  384. case VideoPowerStandBy:
  385. biosArguments.Ebx |= VESA_POWER_STANDBY;
  386. break;
  387. case VideoPowerSuspend:
  388. biosArguments.Ebx |= VESA_POWER_SUSPEND;
  389. break;
  390. case VideoPowerOff:
  391. biosArguments.Ebx |= VESA_POWER_OFF;
  392. break;
  393. case VideoPowerShutdown:
  394. return NO_ERROR;
  395. default:
  396. VideoDebugPrint((1, "Unknown power state.\n"));
  397. ASSERT(FALSE);
  398. return ERROR_INVALID_PARAMETER;
  399. }
  400. VideoPortInt10(HwDeviceExtension, &biosArguments);
  401. return NO_ERROR;
  402. } else if (HwDeviceId == DISPLAY_ADAPTER_HW_ID) {
  403. switch (VideoPowerManagement->PowerState) {
  404. case VideoPowerOn:
  405. case VideoPowerHibernate:
  406. case VideoPowerStandBy:
  407. case VideoPowerShutdown:
  408. return NO_ERROR;
  409. case VideoPowerSuspend:
  410. case VideoPowerOff:
  411. return ERROR_INVALID_PARAMETER;
  412. default:
  413. //
  414. // We indicated in S3GetPowerState that we couldn't
  415. // do VideoPowerOff. So we should not get a call to
  416. // do it here.
  417. //
  418. ASSERT(FALSE);
  419. return ERROR_INVALID_PARAMETER;
  420. }
  421. } else {
  422. VideoDebugPrint((1, "Unknown HwDeviceId"));
  423. ASSERT(FALSE);
  424. return ERROR_INVALID_PARAMETER;
  425. }
  426. }
  427. VP_STATUS
  428. S3FindAdapter(
  429. PVOID HwDeviceExtension,
  430. PVOID HwContext,
  431. PWSTR ArgumentString,
  432. PVIDEO_PORT_CONFIG_INFO ConfigInfo,
  433. PUCHAR Again
  434. )
  435. /*++
  436. Routine Description:
  437. This routine is called to determine if the adapter for this driver
  438. is present in the system.
  439. If it is present, the function fills out some information describing
  440. the adapter.
  441. Arguments:
  442. HwDeviceExtension - Supplies the miniport driver's adapter storage. This
  443. storage is initialized to zero before this call.
  444. HwContext - Supplies the context value which was passed to
  445. VideoPortInitialize(). Must be NULL for PnP drivers.
  446. ArgumentString - Suuplies a NULL terminated ASCII string. This string
  447. originates from the user.
  448. ConfigInfo - Returns the configuration information structure which is
  449. filled by the miniport driver. This structure is initialized with
  450. any knwon configuration information (such as SystemIoBusNumber) by
  451. the port driver. Where possible, drivers should have one set of
  452. defaults which do not require any supplied configuration information.
  453. Again - Indicates if the miniport driver wants the port driver to call
  454. its VIDEO_HW_FIND_ADAPTER function again with a new device extension
  455. and the same config info. This is used by the miniport drivers which
  456. can search for several adapters on a bus.
  457. Return Value:
  458. This routine must return:
  459. NO_ERROR - Indicates a host adapter was found and the
  460. configuration information was successfully determined.
  461. ERROR_INVALID_PARAMETER - Indicates an adapter was found but there was an
  462. error obtaining the configuration information. If possible an error
  463. should be logged.
  464. ERROR_DEV_NOT_EXIST - Indicates no host adapter was found for the
  465. supplied configuration information.
  466. --*/
  467. {
  468. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  469. ULONG i, key=0;
  470. VP_STATUS status;
  471. POINTER_CAPABILITY PointerCapability=0;
  472. VIDEO_ACCESS_RANGE accessRange[NUM_S3_ACCESS_RANGES+NUM_S3_PCI_ACCESS_RANGES];
  473. ULONG NumAccessRanges = NUM_S3_ACCESS_RANGES;
  474. //
  475. // Make sure the size of the structure is at least as large as what we
  476. // are expecting (check version of the config info structure).
  477. //
  478. if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) {
  479. return (ERROR_INVALID_PARAMETER);
  480. }
  481. //
  482. // Make a copy of the access ranges so we can modify them before they
  483. // are mapped.
  484. //
  485. VideoPortMoveMemory(accessRange,
  486. S3AccessRanges,
  487. sizeof(VIDEO_ACCESS_RANGE) * (NUM_S3_ACCESS_RANGES
  488. + NUM_S3_PCI_ACCESS_RANGES));
  489. //
  490. // Detect the PCI card.
  491. //
  492. if (ConfigInfo->AdapterInterfaceType == PCIBus)
  493. {
  494. ULONG Slot = 0;
  495. VideoDebugPrint((1, "S3!VgaFindAdapter: "
  496. "ConfigInfo->AdapterInterfaceType == PCIBus\n"));
  497. status = VideoPortGetAccessRanges(HwDeviceExtension,
  498. 0,
  499. NULL,
  500. NUM_S3_PCI_ACCESS_RANGES,
  501. &accessRange[LINEAR_FRAME_BUF],
  502. NULL,
  503. NULL,
  504. &Slot);
  505. //
  506. // Now we need to determine the Device ID.
  507. //
  508. if (status == NO_ERROR) {
  509. USHORT Id = 0;
  510. if (VideoPortGetBusData(HwDeviceExtension,
  511. PCIConfiguration,
  512. 0,
  513. (PVOID) &Id,
  514. FIELD_OFFSET(
  515. PCI_COMMON_CONFIG,
  516. DeviceID),
  517. sizeof(USHORT)) == 0) {
  518. //
  519. // Error getting bus data.
  520. //
  521. return ERROR_DEV_NOT_EXIST;
  522. }
  523. hwDeviceExtension->PCIDeviceID = Id;
  524. VideoDebugPrint((1, "==> DeviceID = 0x%x\n", Id));
  525. //
  526. // I am making the assumption that this driver will only
  527. // be loaded for legacy class devices. The INF for
  528. // newer PCI device should point to the newer driver.
  529. //
  530. //
  531. // If we have an 868 or a 968 then the card requested
  532. // will request 32 Meg instead of 64 Meg of access ranges.
  533. // Confirm that the PCI bus enumerator corrected for this.
  534. //
  535. if (((Id == 0x8880) || (Id == 0x88F0)) &&
  536. (accessRange[LINEAR_FRAME_BUF].RangeLength != 0x4000000))
  537. {
  538. VideoDebugPrint((1, "This device decodes 64Meg but "
  539. "was only assigned 32Meg.\n"));
  540. ASSERT(FALSE);
  541. }
  542. //
  543. // We have an additional access range for our linear frame
  544. // buffer.
  545. //
  546. NumAccessRanges++;
  547. } else {
  548. //
  549. // Error getting access ranges.
  550. //
  551. return ERROR_DEV_NOT_EXIST;
  552. }
  553. }
  554. //
  555. // Check to see if there is a hardware resource conflict.
  556. //
  557. status = VideoPortVerifyAccessRanges(hwDeviceExtension,
  558. NumAccessRanges,
  559. accessRange);
  560. if (status != NO_ERROR) {
  561. VideoDebugPrint((1, "S3: Access Range conflict\n"));
  562. return status;
  563. }
  564. //
  565. // Get the mapped addresses for the frame buffer, BIOS, and all the
  566. // registers. We will not map the linear frame buffer or linear BIOS
  567. // because the miniport does not need to access it.
  568. //
  569. for (i = 0; i < NUM_S3_ACCESS_RANGES_USED; i++) {
  570. if ( (hwDeviceExtension->MappedAddress[i] =
  571. VideoPortGetDeviceBase(hwDeviceExtension,
  572. accessRange[i].RangeStart,
  573. accessRange[i].RangeLength,
  574. accessRange[i].RangeInIoSpace)) == NULL) {
  575. VideoDebugPrint((1, "S3: DeviceBase mapping failed\n"));
  576. return ERROR_INVALID_PARAMETER;
  577. }
  578. }
  579. //
  580. // Is a BIOS available?
  581. //
  582. if (VideoPortReadRegisterUshort(hwDeviceExtension->MappedAddress[0])
  583. == 0xaa55)
  584. {
  585. hwDeviceExtension->BiosPresent = TRUE;
  586. }
  587. if (ConfigInfo->AdapterInterfaceType != PCIBus)
  588. {
  589. //
  590. // Look for a non-pci S3.
  591. //
  592. if (!S3IsaDetection(HwDeviceExtension, &key)) {
  593. //
  594. // We failed to find an S3 device, so restore the
  595. // lock registers.
  596. //
  597. if (key) {
  598. //
  599. // Only lock the extended registers if
  600. // we unlocked them.
  601. //
  602. LockExtendedRegs(HwDeviceExtension, key);
  603. }
  604. return ERROR_DEV_NOT_EXIST;
  605. }
  606. }
  607. else
  608. {
  609. //
  610. // Make sure the chip type we detected is stored in the
  611. // DeviceExtension. (We found card on PCI bus.)
  612. //
  613. S3RecordChipType(HwDeviceExtension, &key);
  614. }
  615. //
  616. // Get the capabilities, and Chip Name for the detected S3 device.
  617. //
  618. S3GetInfo(HwDeviceExtension, &PointerCapability, accessRange);
  619. //
  620. // Decide whether the alpha can use sparse or dense space.
  621. //
  622. AlphaDetermineMemoryUsage(HwDeviceExtension, accessRange);
  623. //
  624. // Get the DAC type.
  625. //
  626. S3DetermineDACType(HwDeviceExtension,
  627. &PointerCapability);
  628. //
  629. // Determine the amount of video memory we have.
  630. //
  631. S3DetermineMemorySize(HwDeviceExtension);
  632. //
  633. // Determine which Frequency Table to use.
  634. //
  635. S3DetermineFrequencyTable(HwDeviceExtension,
  636. accessRange,
  637. ConfigInfo->AdapterInterfaceType);
  638. //
  639. // Determine which modes are valid on this device.
  640. //
  641. S3ValidateModes(HwDeviceExtension, &PointerCapability);
  642. /////////////////////////////////////////////////////////////////////////
  643. //
  644. // We have this so that the int10 will also work on the VGA also if we
  645. // use it in this driver.
  646. //
  647. ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = 0x000A0000;
  648. ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0x00000000;
  649. ConfigInfo->VdmPhysicalVideoMemoryLength = 0x00020000;
  650. //
  651. // Clear out the Emulator entries and the state size since this driver
  652. // does not support them.
  653. //
  654. ConfigInfo->NumEmulatorAccessEntries = 0;
  655. ConfigInfo->EmulatorAccessEntries = NULL;
  656. ConfigInfo->EmulatorAccessEntriesContext = 0;
  657. //
  658. // This driver does not do SAVE/RESTORE of hardware state.
  659. //
  660. ConfigInfo->HardwareStateSize = 0;
  661. //
  662. // Frame buffer and memory-mapped I/O information.
  663. //
  664. hwDeviceExtension->PhysicalFrameAddress = accessRange[1].RangeStart;
  665. hwDeviceExtension->FrameLength = accessRange[1].RangeLength;
  666. hwDeviceExtension->PhysicalMmIoAddress = accessRange[1].RangeStart;
  667. hwDeviceExtension->MmIoLength = accessRange[1].RangeLength;
  668. hwDeviceExtension->MmIoSpace = accessRange[1].RangeInIoSpace;
  669. if (hwDeviceExtension->Capabilities & CAPS_NEW_MMIO) {
  670. //
  671. // Since we using NEW MMIO, use the values for our linear
  672. // access ranges.
  673. //
  674. hwDeviceExtension->PhysicalFrameAddress = accessRange[LINEAR_FRAME_BUF].RangeStart;
  675. hwDeviceExtension->FrameLength = accessRange[LINEAR_FRAME_BUF].RangeLength;
  676. hwDeviceExtension->PhysicalMmIoAddress = accessRange[LINEAR_FRAME_BUF].RangeStart;
  677. hwDeviceExtension->MmIoLength = accessRange[LINEAR_FRAME_BUF].RangeLength;
  678. hwDeviceExtension->MmIoSpace = accessRange[LINEAR_FRAME_BUF].RangeInIoSpace;
  679. //
  680. // Adjust the memory map offset so that we can still use our
  681. // old-style memory-mapped I/O routines, if need be. Also,
  682. // fix FrameLength and MmIoLength, since they're both set to
  683. // 64 MB right now.
  684. //
  685. hwDeviceExtension->PhysicalMmIoAddress.LowPart += NEW_MMIO_IO_OFFSET;
  686. hwDeviceExtension->MmIoLength = NEW_MMIO_IO_LENGTH;
  687. hwDeviceExtension->FrameLength = hwDeviceExtension->AdapterMemorySize;
  688. }
  689. //
  690. // IO Port information
  691. // Get the base address, starting at zero and map all registers
  692. //
  693. hwDeviceExtension->PhysicalRegisterAddress = accessRange[2].RangeStart;
  694. hwDeviceExtension->PhysicalRegisterAddress.LowPart &= 0xFFFF0000;
  695. hwDeviceExtension->RegisterLength = 0x10000;
  696. hwDeviceExtension->RegisterSpace = accessRange[2].RangeInIoSpace;
  697. //
  698. // Free up the ROM since we don't need it anymore.
  699. //
  700. VideoPortFreeDeviceBase(hwDeviceExtension,
  701. hwDeviceExtension->MappedAddress[0]);
  702. //
  703. // Indicate we do not wish to be called over
  704. //
  705. *Again = 0;
  706. //
  707. // We're done mucking about with the S3 chip, so lock all the registers.
  708. //
  709. LockExtendedRegs(HwDeviceExtension, key);
  710. //
  711. // Indicate a successful completion status.
  712. //
  713. return status;
  714. } // end S3FindAdapter()
  715. ULONG
  716. UnlockExtendedRegs(
  717. PHW_DEVICE_EXTENSION HwDeviceExtension
  718. )
  719. /*++
  720. Routine Description:
  721. This routine unlocks the extended S3 registers.
  722. Arguments:
  723. hwDeviceExtension - Pointer to the miniport's device extension.
  724. Return Value:
  725. ULONG used to restore the register values.
  726. --*/
  727. {
  728. ULONG key;
  729. //
  730. // Save the initial value of the S3 lock registers.
  731. // It's possible a non-s3 bios may expect them in a state
  732. // defined in POST.
  733. //
  734. key = (ULONG) VideoPortReadPortUchar(CRT_ADDRESS_REG);
  735. key <<= 8;
  736. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x38);
  737. key = (ULONG) VideoPortReadPortUchar(CRT_DATA_REG);
  738. key <<= 8;
  739. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x39);
  740. key |= (ULONG) VideoPortReadPortUchar(CRT_DATA_REG);
  741. //
  742. // Now unlock all the S3 registers, for use in this routine.
  743. //
  744. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x4838);
  745. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xA039);
  746. return key;
  747. }
  748. VOID
  749. LockExtendedRegs(
  750. PHW_DEVICE_EXTENSION HwDeviceExtension,
  751. ULONG key
  752. )
  753. /*++
  754. Routine Description:
  755. This routine restores the contents of the s3 lock registers.
  756. Arguments:
  757. hwDeviceExtension - Pointer to the miniport's device extension.
  758. Return Value:
  759. None.
  760. --*/
  761. {
  762. UCHAR val;
  763. val = (UCHAR) key;
  764. key >>= 8;
  765. VideoPortWritePortUshort(
  766. CRT_ADDRESS_REG, (USHORT)(((USHORT) val << 8) | 0x39));
  767. val = (UCHAR) key;
  768. key >>= 8;
  769. VideoPortWritePortUshort(
  770. CRT_ADDRESS_REG, (USHORT)(((USHORT) val << 8) | 0x38));
  771. val = (UCHAR) key;
  772. VideoPortWritePortUchar(CRT_ADDRESS_REG, val);
  773. }
  774. VOID
  775. AlphaDetermineMemoryUsage(
  776. PHW_DEVICE_EXTENSION HwDeviceExtension,
  777. VIDEO_ACCESS_RANGE accessRange[]
  778. )
  779. /*++
  780. Routine Description:
  781. This routine determines whether or not the ALPHA can map it's frame
  782. buffer using dense space.
  783. Arguments:
  784. hwDeviceExtension - Pointer to the miniport's device extension.
  785. Return Value:
  786. None.
  787. --*/
  788. {
  789. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  790. UCHAR jBus;
  791. hwDeviceExtension->PhysicalFrameIoSpace = 0;
  792. #if defined(_ALPHA_)
  793. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x36);
  794. jBus = VideoPortReadPortUchar(CRT_DATA_REG) & 0x3;
  795. if ((jBus == 0x2) &&
  796. ((hwDeviceExtension->ChipID >= S3_866) ||
  797. (hwDeviceExtension->SubTypeID == SUBTYPE_765))) {
  798. //
  799. // We want to use a dense space mapping of the frame buffer
  800. // whenever we can on the Alpha, because that will allow us to
  801. // support DCI and direct GDI access.
  802. //
  803. // Unfortunately, dense space mapping isn't really an option
  804. // with ISA cards because some of the older Alphas don't support
  805. // it, and it would be terribly slow on the newer Alphas anyway
  806. // (because any byte- or word-write requires a read/modify/write
  807. // operation, and the Alpha can only ever do 64-bit reads when
  808. // in dense mode -- meaning these operations would always require
  809. // 4 reads and 2 writes on the ISA bus).
  810. //
  811. // Any Alpha that supports PCI, though, can support dense space
  812. // mapping, and because the bus is wider and faster, the
  813. // read/modify/write case isn't nearly as painful. But the
  814. // problem I've found now is that 64- and 32-bit reads eventually
  815. // lock-up any S3 chip older than the 866/868/968.
  816. //
  817. hwDeviceExtension->PhysicalFrameIoSpace = 4;
  818. //
  819. // The new DeskStation Alpha machines don't always support
  820. // dense space. Therefore, we should try to map the memory
  821. // at this point as a test. If the mapping succeeds then
  822. // we can use dense space, otherwise we'll use sparse space.
  823. //
  824. {
  825. PULONG MappedSpace=0;
  826. PHYSICAL_ADDRESS FrameBuffer;
  827. ULONG FrameLength;
  828. ULONG inIoSpace;
  829. VideoDebugPrint((1, "Checking to see if we can use dense space...\n"));
  830. //
  831. // We want to try to map the dense memory where it will ultimately
  832. // be mapped anyway. If LINEAR_FRAME_BUF is valid, then use this
  833. // info, else use A000_FRAME_BUF.
  834. //
  835. if (accessRange[LINEAR_FRAME_BUF].RangeLength != 0)
  836. {
  837. FrameBuffer = accessRange[LINEAR_FRAME_BUF].RangeStart;
  838. FrameLength = accessRange[LINEAR_FRAME_BUF].RangeLength;
  839. }
  840. else
  841. {
  842. FrameBuffer = accessRange[A000_FRAME_BUF].RangeStart;
  843. FrameLength = accessRange[A000_FRAME_BUF].RangeLength;
  844. }
  845. inIoSpace = hwDeviceExtension->PhysicalFrameIoSpace;
  846. MappedSpace = (PULONG)VideoPortGetDeviceBase(hwDeviceExtension,
  847. FrameBuffer,
  848. FrameLength,
  849. (UCHAR)inIoSpace);
  850. if (MappedSpace == NULL)
  851. {
  852. //
  853. // Well, looks like we can't use dense space to map the
  854. // range. Lets use sparse space, and let the display
  855. // driver know.
  856. //
  857. VideoDebugPrint((1, "Can't use dense space!\n"));
  858. hwDeviceExtension->PhysicalFrameIoSpace = 0;
  859. hwDeviceExtension->Capabilities |= (CAPS_NO_DIRECT_ACCESS |
  860. CAPS_SPARSE_SPACE);
  861. }
  862. else
  863. {
  864. //
  865. // The mapping worked. However, we were only mapping to
  866. // see if dense space was supported. Free the memory.
  867. //
  868. VideoDebugPrint((1, "We can use dense space.\n"));
  869. VideoPortFreeDeviceBase(hwDeviceExtension,
  870. MappedSpace);
  871. }
  872. }
  873. } else {
  874. //
  875. // Gotta use a sparse space mapping, so let the display driver
  876. // know:
  877. //
  878. VideoDebugPrint((1, "We must use sparse space.\n"));
  879. hwDeviceExtension->Capabilities |= (CAPS_NO_DIRECT_ACCESS |
  880. CAPS_SPARSE_SPACE);
  881. }
  882. //
  883. // The 868/968 report to PCI that they decode
  884. // 32 Meg, while infact, they decode 64 Meg.
  885. // PCI attempts to work around this by moving
  886. // resources. However, this causes us to move
  887. // into a dense space region. So, when we try
  888. // to map our accelerator registers in sparce
  889. // space they actually end up in dense space.
  890. //
  891. // The 868/968 also have a bug such that if you
  892. // do a read from certain registers such as
  893. // BEE8, the chip will hang. In dense space,
  894. // USHORT writes are implemented as
  895. // read-modify-write sequences. This causes us
  896. // to hang.
  897. //
  898. // To work around this, we will disable NEW_MMIO
  899. // on the 868/968 and fall back to using
  900. // standard IO routines.
  901. //
  902. if ((hwDeviceExtension->SubTypeID == SUBTYPE_868) ||
  903. (hwDeviceExtension->SubTypeID == SUBTYPE_968)) {
  904. hwDeviceExtension->PhysicalFrameIoSpace = 0;
  905. hwDeviceExtension->Capabilities &= ~CAPS_NEW_MMIO;
  906. hwDeviceExtension->Capabilities |= (CAPS_NO_DIRECT_ACCESS |
  907. CAPS_SPARSE_SPACE);
  908. }
  909. #endif
  910. }
  911. VOID
  912. S3RecordChipType(
  913. PHW_DEVICE_EXTENSION HwDeviceExtension,
  914. PULONG key
  915. )
  916. /*++
  917. Routine Description:
  918. This routine should only be called if we found a PCI S3 card.
  919. The routine will fill in the ChipType and SubType fields of the
  920. HwDeviceExtension.
  921. Arguments:
  922. hwDeviceExtension - Pointer to the miniport's device extension.
  923. Return Value:
  924. None.
  925. --*/
  926. {
  927. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  928. UCHAR jRevision, jChipID, jSecondaryID;
  929. *key = UnlockExtendedRegs(HwDeviceExtension);
  930. switch (hwDeviceExtension->PCIDeviceID) {
  931. case 0x8811:
  932. //
  933. // We need to examine IO ports to determine between
  934. // three chips with the same PCI ID.
  935. //
  936. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x2F);
  937. jRevision = VideoPortReadPortUchar(CRT_DATA_REG);
  938. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x2E);
  939. jSecondaryID = VideoPortReadPortUchar(CRT_DATA_REG);
  940. hwDeviceExtension->ChipID = S3_864; // Treated as an 864
  941. if (jSecondaryID == 0x10) {
  942. //
  943. // This is an S3 732
  944. //
  945. VideoDebugPrint((2, "S3: 732 Chip Set\n"));
  946. hwDeviceExtension->SubTypeID = SUBTYPE_732;
  947. } else {
  948. if (jRevision & 0x40) {
  949. VideoDebugPrint((2, "S3: 765 Chip Set\n"));
  950. hwDeviceExtension->SubTypeID = SUBTYPE_765;
  951. } else {
  952. VideoDebugPrint((2, "S3: 764 Chip Set\n"));
  953. hwDeviceExtension->SubTypeID = SUBTYPE_764;
  954. }
  955. }
  956. break;
  957. case 0x8880:
  958. hwDeviceExtension->ChipID = S3_866;
  959. VideoDebugPrint((2, "S3: Vision868 Chip Set\n"));
  960. hwDeviceExtension->SubTypeID = SUBTYPE_868;
  961. break;
  962. case 0x8890:
  963. hwDeviceExtension->ChipID = S3_866;
  964. VideoDebugPrint((2, "S3: Vision866 Chip Set\n"));
  965. hwDeviceExtension->SubTypeID = SUBTYPE_866;
  966. break;
  967. case 0x88B0:
  968. case 0x88F0:
  969. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x30);
  970. jChipID = VideoPortReadPortUchar(CRT_DATA_REG);
  971. if (jChipID == 0xB0) {
  972. //
  973. // We found a PCI 928
  974. //
  975. VideoDebugPrint((2, "S3: 928 Chip Set\n"));
  976. hwDeviceExtension->ChipID = S3_928;
  977. hwDeviceExtension->SubTypeID = SUBTYPE_928;
  978. } else {
  979. VideoDebugPrint((2, "S3: Vision968 Chip Set\n"));
  980. hwDeviceExtension->ChipID = S3_866;
  981. hwDeviceExtension->SubTypeID = SUBTYPE_968;
  982. }
  983. break;
  984. case 0x88C0:
  985. case 0x88C1:
  986. hwDeviceExtension->ChipID = S3_864;
  987. VideoDebugPrint((2, "S3: 864 Chip Set\n"));
  988. hwDeviceExtension->SubTypeID = SUBTYPE_864;
  989. break;
  990. case 0x88D0:
  991. case 0x88D1:
  992. hwDeviceExtension->ChipID = S3_864;
  993. VideoDebugPrint((2, "S3: 964 Chip Set\n"));
  994. hwDeviceExtension->SubTypeID = SUBTYPE_964;
  995. break;
  996. default:
  997. //
  998. // It's an S3 we don't recognize. Don't assume it's
  999. // backwards-compatible:
  1000. //
  1001. VideoDebugPrint((2, "S3: Unknown Chip Set\n"));
  1002. break;
  1003. }
  1004. //
  1005. // The IBM Mach machine ships with an 868 but we must treat
  1006. // it as an 864 to avoid hanging problems.
  1007. //
  1008. WorkAroundForMach(hwDeviceExtension);
  1009. }
  1010. BOOLEAN
  1011. S3IsaDetection(
  1012. PHW_DEVICE_EXTENSION HwDeviceExtension,
  1013. PULONG key
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. This routine will test for the existance of an S3 card by
  1018. directly poking at IO ports.
  1019. NOTE: It is expected that this routine is called from
  1020. S3FindAdapter, and that the IO ports are mapped.
  1021. Arguments:
  1022. hwDeviceExtension - Pointer to the miniport's device extension.
  1023. Return Value:
  1024. TRUE - If an S3 card was detected,
  1025. FALSE - Otherwise.
  1026. --*/
  1027. {
  1028. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  1029. UCHAR jChipID, jRevision;
  1030. ULONG ulSecondaryID;
  1031. UCHAR reg30, reg47, reg49;
  1032. BOOLEAN DetectS3;
  1033. UCHAR jExtendedVideoDacControl;
  1034. //
  1035. // Determine if a BIOS is present.
  1036. //
  1037. // NOTE: At this point we have detected if an S3 was located on the PCI
  1038. // bus. For other bus types (EISA and ISA) we have not determined
  1039. // yet. So we do assume that reading from the ROM location will not
  1040. // cause the machine to fault (which could actually happen on the
  1041. // internal bus of RISC machines with no roms).
  1042. //
  1043. if (hwDeviceExtension->BiosPresent == TRUE) {
  1044. //
  1045. // Look for a ROM signature of Trident because our chip detection
  1046. // puts the Trident chip into a sleep state.
  1047. //
  1048. // Search the first 256 bytes of BIOS for signature "TRIDENT"
  1049. //
  1050. if (VideoPortScanRom(HwDeviceExtension,
  1051. HwDeviceExtension->MappedAddress[0],
  1052. 256,
  1053. "TRIDENT")) {
  1054. VideoDebugPrint((1, "Trident BIOS found - can not be an S3 !\n"));
  1055. return FALSE;
  1056. }
  1057. }
  1058. *key = UnlockExtendedRegs(HwDeviceExtension);
  1059. //
  1060. // Assume some defaults:
  1061. //
  1062. DetectS3 = TRUE;
  1063. //
  1064. // Make sure we're working with an S3
  1065. // And while were at it, pickup the chip ID
  1066. //
  1067. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x30);
  1068. jChipID = VideoPortReadPortUchar(CRT_DATA_REG);
  1069. switch(jChipID & 0xf0) {
  1070. case 0x80: // 911 or 924
  1071. //
  1072. // Note: A lot of 911/924 cards have timing problems in fast
  1073. // machines when doing monochrome expansions. We simply
  1074. // slow down every such transfer by setting the
  1075. // CAPS_SLOW_MONO_EXPANDS flag.
  1076. //
  1077. // We also ran into problems with the 911 hardware pointer
  1078. // when using the HGC_DY register to hide the pointer;
  1079. // since 911 cards are several generations out of date, we
  1080. // will simply disable the hardware pointer.
  1081. //
  1082. VideoDebugPrint((2, "S3: 911 Chip Set\n"));
  1083. hwDeviceExtension->ChipID = S3_911;
  1084. hwDeviceExtension->SubTypeID = SUBTYPE_911;
  1085. break;
  1086. case 0x90: // 928
  1087. case 0xB0: // 928PCI
  1088. VideoDebugPrint((2, "S3: 928 Chip Set\n"));
  1089. hwDeviceExtension->ChipID = S3_928;
  1090. hwDeviceExtension->SubTypeID = SUBTYPE_928;
  1091. //
  1092. // Note: We don't enable CAPS_MM_IO on the 928 because all the
  1093. // display driver's memory-mapped I/O routines assume they
  1094. // can do 32-bit writes to colour and mask registers,
  1095. // which the 928 can't do.
  1096. //
  1097. break;
  1098. case 0xA0: // 801/805
  1099. if (jChipID >= 0xA8) {
  1100. //
  1101. // It's an 805i, which appears to us to be pretty much a '928'.
  1102. //
  1103. VideoDebugPrint((2, "S3: 805i Chip Set\n"));
  1104. hwDeviceExtension->ChipID = S3_928;
  1105. hwDeviceExtension->SubTypeID = SUBTYPE_805i;
  1106. } else {
  1107. //
  1108. // The 80x rev 'A' and 'B' chips had bugs that prevented them
  1109. // from being able to do memory-mapped I/O. I'm not enabling
  1110. // memory-mapped I/O on later versions of the 80x because doing
  1111. // so at this point would be a testing problem.
  1112. //
  1113. VideoDebugPrint((2, "S3: 801/805 Chip Set\n"));
  1114. hwDeviceExtension->ChipID = S3_801;
  1115. hwDeviceExtension->SubTypeID = SUBTYPE_80x;
  1116. }
  1117. break;
  1118. case 0xC0: // 864
  1119. case 0xD0: // 964
  1120. hwDeviceExtension->ChipID = S3_864;
  1121. //
  1122. // Note: The first 896/964 revs have a bug dealing with the pattern
  1123. // hardware, where we have to draw a 1x8 rectangle before
  1124. // using a pattern already realized in off-screen memory,
  1125. // so we set the RE_REALIZE_PATTERN flag.
  1126. //
  1127. if ((jChipID & 0xF0) == 0xC0) {
  1128. VideoDebugPrint((2, "S3: 864 Chip Set\n"));
  1129. hwDeviceExtension->SubTypeID = SUBTYPE_864;
  1130. } else {
  1131. VideoDebugPrint((2, "S3: 964 Chip Set\n"));
  1132. hwDeviceExtension->SubTypeID = SUBTYPE_964;
  1133. }
  1134. break;
  1135. case 0xE0: // Newer than 864/964
  1136. //
  1137. // We can treat the newer chips, for the most part, as compatible
  1138. // with the 864, so use that ChipID. Also assume some basic
  1139. // capabilities.
  1140. //
  1141. hwDeviceExtension->ChipID = S3_866;
  1142. //
  1143. // Look at the secondary chip ID register to determine the chip
  1144. // type.
  1145. //
  1146. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x2D);
  1147. ulSecondaryID = ((ULONG) VideoPortReadPortUchar(CRT_DATA_REG)) << 8;
  1148. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x2E);
  1149. ulSecondaryID |= VideoPortReadPortUchar(CRT_DATA_REG);
  1150. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x2F);
  1151. jRevision = VideoPortReadPortUchar(CRT_DATA_REG);
  1152. switch (ulSecondaryID) {
  1153. case 0x8811:
  1154. hwDeviceExtension->ChipID = S3_864; // Treated as an 864
  1155. if (jRevision & 0x40) {
  1156. VideoDebugPrint((2, "S3: 765 Chip Set\n"));
  1157. hwDeviceExtension->SubTypeID = SUBTYPE_765;
  1158. } else {
  1159. VideoDebugPrint((2, "S3: 764 Chip Set\n"));
  1160. hwDeviceExtension->SubTypeID = SUBTYPE_764;
  1161. //
  1162. // Our #9 and Diamond 764 boards occasionally fail the HCT
  1163. // tests when we do dword or word reads from the frame buffer.
  1164. // To get on the HCL lists, cards must pass the HCTs, so we'll
  1165. // revert to byte reads for these chips:
  1166. //
  1167. }
  1168. break;
  1169. case 0x8810:
  1170. VideoDebugPrint((2, "S3: 732 Chip Set\n"));
  1171. hwDeviceExtension->ChipID = S3_864; // Treated as an 864
  1172. hwDeviceExtension->SubTypeID = SUBTYPE_732;
  1173. break;
  1174. case 0x8880:
  1175. VideoDebugPrint((2, "S3: Vision866 Chip Set\n"));
  1176. hwDeviceExtension->SubTypeID = SUBTYPE_866;
  1177. break;
  1178. case 0x8890:
  1179. VideoDebugPrint((2, "S3: Vision868 Chip Set\n"));
  1180. hwDeviceExtension->SubTypeID = SUBTYPE_868;
  1181. break;
  1182. case 0x88B0:
  1183. case 0x88F0:
  1184. VideoDebugPrint((2, "S3: Vision968 Chip Set\n"));
  1185. hwDeviceExtension->SubTypeID = SUBTYPE_968;
  1186. break;
  1187. default:
  1188. //
  1189. // It's an S3 we don't recognize. Don't assume it's
  1190. // backwards-compatible:
  1191. //
  1192. VideoDebugPrint((2, "S3: Unknown Chip Set\n"));
  1193. //
  1194. // Since we do not know what type of S3 this is, we
  1195. // can't risk letting the driver load!
  1196. //
  1197. DetectS3 = FALSE;
  1198. break;
  1199. }
  1200. break;
  1201. default:
  1202. DetectS3 = FALSE;
  1203. break;
  1204. }
  1205. //
  1206. // The IBM Mach machine ships with an 868 but we must treat
  1207. // it as an 864 to avoid hanging problems.
  1208. //
  1209. WorkAroundForMach(hwDeviceExtension);
  1210. //
  1211. // Windows NT now autodetects the user's video card in Setup by
  1212. // loading and running every video miniport until it finds one that
  1213. // returns success. Consequently, our detection code has to be
  1214. // rigorous enough that we don't accidentally recognize a wrong
  1215. // board.
  1216. //
  1217. // Simply checking the chip ID is not sufficient for guaranteeing
  1218. // that we are running on an S3 (it makes us think some Weitek
  1219. // boards are S3 compatible).
  1220. //
  1221. // We make doubly sure we're running on an S3 by checking that
  1222. // the S3 cursor position registers exist, and that the chip ID
  1223. // register can't be changed.
  1224. //
  1225. if (DetectS3) {
  1226. DetectS3 = FALSE;
  1227. //
  1228. // First, make sure 'chip ID' register 0x30 is not modifiable:
  1229. //
  1230. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x30);
  1231. if (VideoPortReadPortUchar(CRT_ADDRESS_REG) == 0x30) {
  1232. reg30 = VideoPortReadPortUchar(CRT_DATA_REG);
  1233. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) (reg30 + 7));
  1234. if (VideoPortReadPortUchar(CRT_DATA_REG) == reg30) {
  1235. //
  1236. // Next, make sure 'cursor origin-x' register 0x47 is
  1237. // modifiable:
  1238. //
  1239. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x47);
  1240. if (VideoPortReadPortUchar(CRT_ADDRESS_REG) == 0x47) {
  1241. reg47 = VideoPortReadPortUchar(CRT_DATA_REG);
  1242. VideoPortWritePortUchar(CRT_DATA_REG, 0x55);
  1243. if (VideoPortReadPortUchar(CRT_DATA_REG) == 0x55) {
  1244. //
  1245. // Finally, make sure 'cursor origin-y' register 0x49
  1246. // is modifiable:
  1247. //
  1248. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x49);
  1249. if (VideoPortReadPortUchar(CRT_ADDRESS_REG) == 0x49) {
  1250. reg49 = VideoPortReadPortUchar(CRT_DATA_REG);
  1251. VideoPortWritePortUchar(CRT_DATA_REG, 0xAA);
  1252. if (VideoPortReadPortUchar(CRT_DATA_REG) == 0xAA) {
  1253. DetectS3 = TRUE;
  1254. }
  1255. VideoPortWritePortUchar(CRT_DATA_REG, reg49);
  1256. }
  1257. }
  1258. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x47);
  1259. VideoPortWritePortUchar(CRT_DATA_REG, reg47);
  1260. }
  1261. }
  1262. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x30);
  1263. VideoPortWritePortUchar(CRT_DATA_REG, reg30);
  1264. }
  1265. }
  1266. return DetectS3;
  1267. }
  1268. VOID
  1269. S3GetInfo(
  1270. PHW_DEVICE_EXTENSION HwDeviceExtension,
  1271. POINTER_CAPABILITY *PointerCapability,
  1272. VIDEO_ACCESS_RANGE accessRange[]
  1273. )
  1274. /*++
  1275. Routine Description:
  1276. For fill in the capabilities bits for the s3 card, and return an
  1277. wide character string representing the chip.
  1278. Arguments:
  1279. HwDeviceExtension - Pointer to the miniport's device extension.
  1280. Return Value:
  1281. None.
  1282. --*/
  1283. {
  1284. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  1285. UCHAR jBus, jChipID;
  1286. PWSTR pwszChip;
  1287. ULONG cbChip;
  1288. //
  1289. // The second register used for setting the refresh rate depends
  1290. // on whether the chip is an 864/964, or newer. The integrated
  1291. // Trio chips use 41; the other high-end chips use 5B.
  1292. //
  1293. hwDeviceExtension->FrequencySecondaryIndex = 0x5B;
  1294. switch (hwDeviceExtension->SubTypeID) {
  1295. case SUBTYPE_911:
  1296. //
  1297. // Note: A lot of 911/924 cards have timing problems in fast
  1298. // machines when doing monochrome expansions. We simply
  1299. // slow down every such transfer by setting the
  1300. // CAPS_SLOW_MONO_EXPANDS flag.
  1301. //
  1302. // We also ran into problems with the 911 hardware pointer
  1303. // when using the HGC_DY register to hide the pointer;
  1304. // since 911 cards are several generations out of date, we
  1305. // will simply disable the hardware pointer.
  1306. //
  1307. VideoDebugPrint((2, "S3: 911 Chip Set\n"));
  1308. pwszChip = L"S3 911/924";
  1309. cbChip = sizeof(L"S3 911/924");
  1310. hwDeviceExtension->Capabilities = (CAPS_SLOW_MONO_EXPANDS |
  1311. CAPS_SW_POINTER);
  1312. break;
  1313. case SUBTYPE_928:
  1314. VideoDebugPrint((2, "S3: 928 Chip Set\n"));
  1315. pwszChip = L"S3 928";
  1316. cbChip = sizeof(L"S3 928");
  1317. //
  1318. // Note: We don't enable CAPS_MM_IO on the 928 because all the
  1319. // display driver's memory-mapped I/O routines assume they
  1320. // can do 32-bit writes to colour and mask registers,
  1321. // which the 928 can't do.
  1322. //
  1323. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1324. CAPS_MM_TRANSFER |
  1325. CAPS_MM_GLYPH_EXPAND |
  1326. CAPS_16_ENTRY_FIFO |
  1327. CAPS_NEW_BANK_CONTROL);
  1328. *PointerCapability = (POINTER_BUILT_IN | POINTER_WORKS_ONLY_AT_8BPP);
  1329. break;
  1330. case SUBTYPE_805i:
  1331. //
  1332. // It's an 805i, which appears to us to be pretty much a '928'.
  1333. //
  1334. VideoDebugPrint((2, "S3: 805i Chip Set\n"));
  1335. pwszChip = L"S3 805i";
  1336. cbChip = sizeof(L"S3 805i");
  1337. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1338. CAPS_MM_TRANSFER |
  1339. CAPS_MM_GLYPH_EXPAND |
  1340. CAPS_16_ENTRY_FIFO |
  1341. CAPS_NEW_BANK_CONTROL);
  1342. *PointerCapability = (POINTER_BUILT_IN | POINTER_WORKS_ONLY_AT_8BPP);
  1343. break;
  1344. case SUBTYPE_80x:
  1345. //
  1346. // The 80x rev 'A' and 'B' chips had bugs that prevented them
  1347. // from being able to do memory-mapped I/O. I'm not enabling
  1348. // memory-mapped I/O on later versions of the 80x because doing
  1349. // so at this point would be a testing problem.
  1350. //
  1351. VideoDebugPrint((2, "S3: 801/805 Chip Set\n"));
  1352. pwszChip = L"S3 801/805";
  1353. cbChip = sizeof(L"S3 801/805");
  1354. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1355. CAPS_MM_TRANSFER |
  1356. CAPS_NEW_BANK_CONTROL);
  1357. *PointerCapability = (POINTER_BUILT_IN | POINTER_WORKS_ONLY_AT_8BPP);
  1358. break;
  1359. case SUBTYPE_864:
  1360. //
  1361. // Note: The first 896/964 revs have a bug dealing with the pattern
  1362. // hardware, where we have to draw a 1x8 rectangle before
  1363. // using a pattern already realized in off-screen memory,
  1364. // so we set the RE_REALIZE_PATTERN flag.
  1365. //
  1366. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1367. CAPS_MM_TRANSFER |
  1368. CAPS_MM_32BIT_TRANSFER |
  1369. CAPS_MM_IO |
  1370. CAPS_MM_GLYPH_EXPAND |
  1371. CAPS_16_ENTRY_FIFO |
  1372. CAPS_NEWER_BANK_CONTROL |
  1373. CAPS_RE_REALIZE_PATTERN);
  1374. VideoDebugPrint((2, "S3: 864 Chip Set\n"));
  1375. pwszChip = L"S3 Vision864";
  1376. cbChip = sizeof(L"S3 Vision864");
  1377. *PointerCapability = (POINTER_BUILT_IN | POINTER_NEEDS_SCALING);
  1378. break;
  1379. case SUBTYPE_964:
  1380. //
  1381. // Note: The first 896/964 revs have a bug dealing with the pattern
  1382. // hardware, where we have to draw a 1x8 rectangle before
  1383. // using a pattern already realized in off-screen memory,
  1384. // so we set the RE_REALIZE_PATTERN flag.
  1385. //
  1386. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1387. CAPS_MM_TRANSFER |
  1388. CAPS_MM_32BIT_TRANSFER |
  1389. CAPS_MM_IO |
  1390. CAPS_MM_GLYPH_EXPAND |
  1391. CAPS_16_ENTRY_FIFO |
  1392. CAPS_NEWER_BANK_CONTROL |
  1393. CAPS_RE_REALIZE_PATTERN);
  1394. VideoDebugPrint((2, "S3: 964 Chip Set\n"));
  1395. pwszChip = L"S3 Vision964";
  1396. cbChip = sizeof(L"S3 Vision964");
  1397. break;
  1398. case SUBTYPE_765:
  1399. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1400. CAPS_MM_TRANSFER |
  1401. CAPS_MM_32BIT_TRANSFER |
  1402. CAPS_MM_IO |
  1403. CAPS_MM_GLYPH_EXPAND |
  1404. CAPS_16_ENTRY_FIFO |
  1405. CAPS_NEWER_BANK_CONTROL);
  1406. hwDeviceExtension->FrequencySecondaryIndex = 0x41;
  1407. *PointerCapability = POINTER_BUILT_IN;
  1408. VideoDebugPrint((2, "S3: Trio64V+ Chip Set\n"));
  1409. pwszChip = L"S3 Trio64V+";
  1410. cbChip = sizeof(L"S3 Trio64V+");
  1411. hwDeviceExtension->Capabilities |= (CAPS_NEW_MMIO |
  1412. CAPS_STREAMS_CAPABLE |
  1413. CAPS_PACKED_EXPANDS);
  1414. break;
  1415. case SUBTYPE_764:
  1416. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1417. CAPS_MM_TRANSFER |
  1418. CAPS_MM_32BIT_TRANSFER |
  1419. CAPS_MM_IO |
  1420. CAPS_MM_GLYPH_EXPAND |
  1421. CAPS_16_ENTRY_FIFO |
  1422. CAPS_NEWER_BANK_CONTROL);
  1423. hwDeviceExtension->FrequencySecondaryIndex = 0x41;
  1424. *PointerCapability = POINTER_BUILT_IN;
  1425. VideoDebugPrint((2, "S3: 764 Chip Set\n"));
  1426. pwszChip = L"S3 764";
  1427. cbChip = sizeof(L"S3 764");
  1428. //
  1429. // Our #9 and Diamond 764 boards occasionally fail the HCT
  1430. // tests when we do dword or word reads from the frame buffer.
  1431. // To get on the HCL lists, cards must pass the HCTs, so we'll
  1432. // revert to byte reads for these chips:
  1433. //
  1434. hwDeviceExtension->Capabilities |= CAPS_BAD_DWORD_READS;
  1435. break;
  1436. case SUBTYPE_732:
  1437. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1438. CAPS_MM_TRANSFER |
  1439. CAPS_MM_32BIT_TRANSFER |
  1440. CAPS_MM_IO |
  1441. CAPS_MM_GLYPH_EXPAND |
  1442. CAPS_16_ENTRY_FIFO |
  1443. CAPS_NEWER_BANK_CONTROL);
  1444. VideoDebugPrint((2, "S3: 732 Chip Set\n"));
  1445. pwszChip = L"S3 732";
  1446. cbChip = sizeof(L"S3 732");
  1447. *PointerCapability = POINTER_BUILT_IN;
  1448. hwDeviceExtension->FrequencySecondaryIndex = 0x41;
  1449. break;
  1450. case SUBTYPE_866:
  1451. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1452. CAPS_MM_TRANSFER |
  1453. CAPS_MM_32BIT_TRANSFER |
  1454. CAPS_MM_IO |
  1455. CAPS_MM_GLYPH_EXPAND |
  1456. CAPS_16_ENTRY_FIFO |
  1457. CAPS_NEWER_BANK_CONTROL);
  1458. VideoDebugPrint((2, "S3: Vision866 Chip Set\n"));
  1459. pwszChip = L"S3 Vision866";
  1460. cbChip = sizeof(L"S3 Vision866");
  1461. *PointerCapability = (POINTER_BUILT_IN |
  1462. POINTER_NEEDS_SCALING); // Note scaling
  1463. hwDeviceExtension->Capabilities |= (CAPS_NEW_MMIO |
  1464. CAPS_POLYGON |
  1465. CAPS_24BPP |
  1466. CAPS_BAD_24BPP |
  1467. CAPS_PACKED_EXPANDS);
  1468. break;
  1469. case SUBTYPE_868:
  1470. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1471. CAPS_MM_TRANSFER |
  1472. CAPS_MM_32BIT_TRANSFER |
  1473. CAPS_MM_IO |
  1474. CAPS_MM_GLYPH_EXPAND |
  1475. CAPS_16_ENTRY_FIFO |
  1476. CAPS_NEWER_BANK_CONTROL);
  1477. VideoDebugPrint((2, "S3: Vision868 Chip Set\n"));
  1478. pwszChip = L"S3 Vision868";
  1479. cbChip = sizeof(L"S3 Vision868");
  1480. *PointerCapability = (POINTER_BUILT_IN |
  1481. POINTER_NEEDS_SCALING); // Note scaling
  1482. hwDeviceExtension->Capabilities |= (CAPS_NEW_MMIO |
  1483. CAPS_POLYGON |
  1484. CAPS_24BPP |
  1485. CAPS_BAD_24BPP |
  1486. CAPS_PACKED_EXPANDS |
  1487. CAPS_PIXEL_FORMATTER);
  1488. break;
  1489. case SUBTYPE_968:
  1490. hwDeviceExtension->Capabilities = (CAPS_HW_PATTERNS |
  1491. CAPS_MM_TRANSFER |
  1492. CAPS_MM_32BIT_TRANSFER |
  1493. CAPS_MM_IO |
  1494. CAPS_MM_GLYPH_EXPAND |
  1495. CAPS_16_ENTRY_FIFO |
  1496. CAPS_NEWER_BANK_CONTROL);
  1497. VideoDebugPrint((2, "S3: Vision968 Chip Set\n"));
  1498. pwszChip = L"S3 Vision968";
  1499. cbChip = sizeof(L"S3 Vision968");
  1500. hwDeviceExtension->Capabilities |= (CAPS_NEW_MMIO |
  1501. CAPS_POLYGON |
  1502. CAPS_24BPP |
  1503. CAPS_BAD_24BPP |
  1504. CAPS_PACKED_EXPANDS |
  1505. CAPS_PIXEL_FORMATTER);
  1506. break;
  1507. default:
  1508. ASSERT(FALSE);
  1509. VideoDebugPrint((1, "What type of S3 is this???\n"));
  1510. pwszChip = L"S3 Unknown Chip Set";
  1511. cbChip = sizeof(L"S3 Unknown Chip Set");
  1512. break;
  1513. }
  1514. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x36);
  1515. jBus = VideoPortReadPortUchar(CRT_DATA_REG) & 0x3;
  1516. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x30);
  1517. jChipID = VideoPortReadPortUchar(CRT_DATA_REG);
  1518. if (jBus == 0x3) {
  1519. //
  1520. // Using the buffer expansion method of drawing text is always
  1521. // faster on ISA buses than the glyph expansion method.
  1522. //
  1523. hwDeviceExtension->Capabilities &= ~CAPS_MM_GLYPH_EXPAND;
  1524. //
  1525. // We have to disable memory-mapped I/O in some situations
  1526. // on ISA buses.
  1527. //
  1528. // We can't do any memory-mapped I/O on ISA systems with
  1529. // rev A through D 928's, or rev A or B 801/805's.
  1530. //
  1531. if (((hwDeviceExtension->ChipID == S3_928) && (jChipID < 0x94)) ||
  1532. ((hwDeviceExtension->ChipID == S3_801) && (jChipID < 0xA2))) {
  1533. hwDeviceExtension->Capabilities &= ~(CAPS_MM_TRANSFER | CAPS_MM_IO);
  1534. }
  1535. }
  1536. //
  1537. // We have some weird initialization bug on newer Diamond Stealth
  1538. // 805 and 928 local bus cards where if we enable memory-mapped I/O,
  1539. // even if we don't use it, we'll get all kinds of weird access
  1540. // violations in the system. The card is sending garbage over the
  1541. // bus? As a work-around I am simply disabling memory-mappped I/O
  1542. // on newer Diamond 928/928PCI and 805 cards. It is not a problem
  1543. // with their 964 or newer cards.
  1544. //
  1545. if (hwDeviceExtension->BoardID == S3_DIAMOND) {
  1546. if ((((jChipID & 0xF0) == 0x90) && (jChipID >= 0x94)) ||
  1547. (((jChipID & 0xF0) == 0xB0) && (jChipID >= 0xB0)) ||
  1548. (((jChipID & 0xF0) == 0xA0) && (jChipID >= 0xA2))) {
  1549. hwDeviceExtension->Capabilities
  1550. &= ~(CAPS_MM_TRANSFER | CAPS_MM_IO | CAPS_MM_GLYPH_EXPAND);
  1551. VideoDebugPrint((1, "S3: Disabling Diamond memory-mapped I/O\n"));
  1552. }
  1553. }
  1554. if (hwDeviceExtension->Capabilities & CAPS_NEW_MMIO) {
  1555. //
  1556. // Are we actually using new MMIO? If the length
  1557. // of the range for linear frame buffer entry
  1558. // in the accessRanges array is zero, then we aren't
  1559. // really using NEW_MMIO
  1560. //
  1561. if (accessRange[LINEAR_FRAME_BUF].RangeLength == 0)
  1562. {
  1563. hwDeviceExtension->Capabilities &= ~CAPS_NEW_MMIO;
  1564. }
  1565. }
  1566. VideoPortSetRegistryParameters(hwDeviceExtension,
  1567. L"HardwareInformation.ChipType",
  1568. pwszChip,
  1569. cbChip);
  1570. }
  1571. VOID
  1572. S3DetermineFrequencyTable(
  1573. PVOID HwDeviceExtension,
  1574. VIDEO_ACCESS_RANGE accessRange[],
  1575. INTERFACE_TYPE AdapterInterfaceType
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. Try to determine which frequency table to use based on the
  1580. vendor string in the bios.
  1581. Arguments:
  1582. HwDeviceExtension - Pointer to the miniport's device extension.
  1583. Return Value:
  1584. The accessRange array may have been modified.
  1585. --*/
  1586. {
  1587. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  1588. PVOID romAddress;
  1589. PWSTR pwszAdapterString = L"S3 Compatible";
  1590. ULONG cbAdapterString = sizeof(L"S3 Compatible");
  1591. //
  1592. // We will try to recognize the boards for which we have special
  1593. // frequency/modeset support.
  1594. //
  1595. //
  1596. // Set the defaults for the board type.
  1597. //
  1598. hwDeviceExtension->BoardID = S3_GENERIC;
  1599. hwDeviceExtension->FixedFrequencyTable = GenericFixedFrequencyTable;
  1600. if (hwDeviceExtension->ChipID <= S3_928) {
  1601. hwDeviceExtension->Int10FrequencyTable = GenericFrequencyTable;
  1602. } else {
  1603. hwDeviceExtension->Int10FrequencyTable = Generic64NewFrequencyTable;
  1604. }
  1605. romAddress = hwDeviceExtension->MappedAddress[0];
  1606. //
  1607. // Look for brand name signatures in the ROM.
  1608. //
  1609. if (VideoPortScanRom(hwDeviceExtension,
  1610. romAddress,
  1611. MAX_ROM_SCAN,
  1612. "Number Nine ")) {
  1613. hwDeviceExtension->BoardID = S3_NUMBER_NINE;
  1614. pwszAdapterString = L"Number Nine";
  1615. cbAdapterString = sizeof(L"Number Nine");
  1616. //
  1617. // We can set the refresh on 864/964 Number Nine boards.
  1618. //
  1619. if (hwDeviceExtension->ChipID >= S3_864) {
  1620. hwDeviceExtension->Int10FrequencyTable = NumberNine64FrequencyTable;
  1621. //
  1622. // We also have frequency tables for 928-based GXE boards.
  1623. //
  1624. } else if (hwDeviceExtension->ChipID == S3_928) {
  1625. UCHAR *pjRefString;
  1626. UCHAR *pjBiosVersion;
  1627. UCHAR offset;
  1628. LONG iCmpRet;
  1629. hwDeviceExtension->Int10FrequencyTable = NumberNine928OldFrequencyTable;
  1630. hwDeviceExtension->FixedFrequencyTable = NumberNine928NewFixedFrequencyTable;
  1631. //
  1632. // We know (at least we think) this is Number Nine board.
  1633. // There was a bios change at #9 to change the refresh rate
  1634. // mapping. This change was made at Microsofts request. The
  1635. // problem is that the change has not make into production at
  1636. // the time this driver was written. For this reason, we must
  1637. // check the bios version number, before we special case the
  1638. // card as the number nine card.
  1639. //
  1640. // There is a byte in the bios at offset 0x190, that is the
  1641. // offset from the beginning of the bios for the bios version
  1642. // number. The bios version number is a string. All the
  1643. // bios versions before 1.10.04 need this special translation.
  1644. // all the other bios's use a translation closer to the s3
  1645. // standard.
  1646. //
  1647. offset = VideoPortReadRegisterUchar(
  1648. ((PUCHAR) romAddress) + 0x190);
  1649. pjBiosVersion = (PUCHAR) romAddress + offset;
  1650. pjRefString = "1.10.04";
  1651. iCmpRet = CompareRom(pjBiosVersion,
  1652. pjRefString);
  1653. if (iCmpRet >= 0) {
  1654. hwDeviceExtension->Int10FrequencyTable = NumberNine928NewFrequencyTable;
  1655. }
  1656. }
  1657. } else if (VideoPortScanRom(hwDeviceExtension,
  1658. romAddress,
  1659. MAX_ROM_SCAN,
  1660. "Orchid Technology Fahrenheit 1280")) {
  1661. hwDeviceExtension->BoardID = S3_ORCHID;
  1662. pwszAdapterString = L"Orchid Technology Fahrenheit 1280";
  1663. cbAdapterString = sizeof(L"Orchid Technology Fahrenheit 1280");
  1664. //
  1665. // Only the 911 Orchid board needs specific init parameters.
  1666. // Otherwise, fall through the generic function.
  1667. //
  1668. if (hwDeviceExtension->ChipID == S3_911) {
  1669. hwDeviceExtension->FixedFrequencyTable = OrchidFixedFrequencyTable;
  1670. }
  1671. } else if (VideoPortScanRom(hwDeviceExtension,
  1672. romAddress,
  1673. MAX_ROM_SCAN,
  1674. "Diamond")) {
  1675. hwDeviceExtension->BoardID = S3_DIAMOND;
  1676. pwszAdapterString = L"Diamond Stealth";
  1677. cbAdapterString = sizeof(L"Diamond Stealth");
  1678. //
  1679. // We can set the frequency on 864 and 964 Diamonds.
  1680. //
  1681. if (hwDeviceExtension->ChipID >= S3_864) {
  1682. hwDeviceExtension->Int10FrequencyTable = Diamond64FrequencyTable;
  1683. //
  1684. // Not only did Diamond decide to have a different
  1685. // frequency convention from S3's standard, they also
  1686. // chose to use a different register than S3 did with
  1687. // the 764:
  1688. //
  1689. if (hwDeviceExtension->FrequencySecondaryIndex == 0x41) {
  1690. hwDeviceExtension->FrequencySecondaryIndex = 0x6B;
  1691. }
  1692. }
  1693. } else if (VideoPortScanRom(hwDeviceExtension,
  1694. romAddress,
  1695. MAX_ROM_SCAN,
  1696. "HP Ultra")) {
  1697. hwDeviceExtension->BoardID = S3_HP;
  1698. pwszAdapterString = L"HP Ultra";
  1699. cbAdapterString = sizeof(L"HP Ultra");
  1700. } else if (VideoPortScanRom(hwDeviceExtension,
  1701. romAddress,
  1702. MAX_ROM_SCAN,
  1703. "DELL")) {
  1704. hwDeviceExtension->BoardID = S3_DELL;
  1705. pwszAdapterString = L"DELL";
  1706. cbAdapterString = sizeof(L"DELL");
  1707. //
  1708. // We only have frequency tables for 805 based DELLs.
  1709. //
  1710. // DELLs with onboard 765s can use the Hercules Frequency Table.
  1711. //
  1712. if (hwDeviceExtension->ChipID == S3_801) {
  1713. hwDeviceExtension->Int10FrequencyTable = Dell805FrequencyTable;
  1714. } else if ((hwDeviceExtension->ChipID >= S3_864) &&
  1715. (hwDeviceExtension->SubTypeID == SUBTYPE_765)) {
  1716. hwDeviceExtension->Int10FrequencyTable = HerculesFrequencyTable;
  1717. }
  1718. } else if (VideoPortScanRom(hwDeviceExtension,
  1719. romAddress,
  1720. MAX_ROM_SCAN,
  1721. "Metheus")) {
  1722. pwszAdapterString = L"Metheus";
  1723. cbAdapterString = sizeof(L"Metheus");
  1724. hwDeviceExtension->BoardID = S3_METHEUS;
  1725. if (hwDeviceExtension->ChipID == S3_928) {
  1726. hwDeviceExtension->Int10FrequencyTable = Metheus928FrequencyTable;
  1727. }
  1728. } else if (VideoPortScanRom(hwDeviceExtension,
  1729. romAddress,
  1730. MAX_ROM_SCAN,
  1731. "Hercules")) {
  1732. if ((hwDeviceExtension->SubTypeID == SUBTYPE_732) ||
  1733. (hwDeviceExtension->SubTypeID == SUBTYPE_764) ||
  1734. (hwDeviceExtension->SubTypeID == SUBTYPE_765)) {
  1735. hwDeviceExtension->Int10FrequencyTable = HerculesFrequencyTable;
  1736. } else if ((hwDeviceExtension->SubTypeID == SUBTYPE_964) ||
  1737. (hwDeviceExtension->SubTypeID == SUBTYPE_864)) {
  1738. hwDeviceExtension->Int10FrequencyTable = Hercules64FrequencyTable;
  1739. } else if ((hwDeviceExtension->SubTypeID == SUBTYPE_968) ||
  1740. (hwDeviceExtension->SubTypeID == SUBTYPE_868)) {
  1741. hwDeviceExtension->Int10FrequencyTable = Hercules68FrequencyTable;
  1742. }
  1743. } else if (VideoPortScanRom(hwDeviceExtension,
  1744. romAddress,
  1745. MAX_ROM_SCAN,
  1746. "Phoenix S3")) {
  1747. pwszAdapterString = L"Phoenix";
  1748. cbAdapterString = sizeof(L"Phoenix");
  1749. if (hwDeviceExtension->ChipID >= S3_864) {
  1750. //
  1751. // The Phoenix 864/964 BIOS is based on S3's sample BIOS.
  1752. // Most of the 1.00 versions subscribe to the old 864/964
  1753. // refresh convention; most newer versions subscribe
  1754. // to the newer refresh convention. Unfortunately, there
  1755. // are exceptions: the ValuePoint machines have '1.00'
  1756. // versions, but subscribe to the new convention.
  1757. //
  1758. // There are probably other exceptions we don't know about,
  1759. // so we leave 'Use Hardware Default' as a refresh option
  1760. // for the user.
  1761. //
  1762. if (VideoPortScanRom(hwDeviceExtension,
  1763. romAddress,
  1764. MAX_ROM_SCAN,
  1765. "Phoenix S3 Vision") &&
  1766. VideoPortScanRom(hwDeviceExtension,
  1767. romAddress,
  1768. MAX_ROM_SCAN,
  1769. "VGA BIOS. Version 1.00") &&
  1770. !VideoPortScanRom(hwDeviceExtension,
  1771. romAddress,
  1772. MAX_ROM_SCAN,
  1773. "COPYRIGHT IBM")) {
  1774. hwDeviceExtension->Int10FrequencyTable = Generic64OldFrequencyTable;
  1775. } else {
  1776. hwDeviceExtension->Int10FrequencyTable = Generic64NewFrequencyTable;
  1777. }
  1778. }
  1779. }
  1780. #if defined(_X86_)
  1781. if ((hwDeviceExtension->BiosPresent == FALSE) &&
  1782. (AdapterInterfaceType == MicroChannel))
  1783. {
  1784. VP_STATUS status;
  1785. //
  1786. // This must be an IBM PS/2 with onboard S3 (no bios)
  1787. //
  1788. // We should release our claim on the video bios.
  1789. //
  1790. accessRange[0].RangeStart.LowPart = 0;
  1791. accessRange[0].RangeStart.HighPart = 0;
  1792. accessRange[0].RangeLength = 0;
  1793. pwszAdapterString = L"IBM MicroChannel";
  1794. cbAdapterString = sizeof(L"IBM MicroChannel");
  1795. hwDeviceExtension->BoardID = S3_IBM_PS2;
  1796. //
  1797. // We have to re-reserve every port.
  1798. //
  1799. status = VideoPortVerifyAccessRanges(hwDeviceExtension,
  1800. NUM_S3_ACCESS_RANGES,
  1801. accessRange);
  1802. if (status != NO_ERROR) {
  1803. VideoDebugPrint((1, "S3: Access Range conflict after ROM change\n"));
  1804. ASSERT(FALSE);
  1805. }
  1806. //
  1807. // If the machine does not have an S3 BIOS, then we need to
  1808. // restore bits 4, 5, and 6 of CRTC reg 0x5C when returning
  1809. // to a VGA mode.
  1810. //
  1811. // Here we'll store bits 4-6 of CRTC reg 0x5c, and set bit
  1812. // 7. When restoring the mode we'll reset the high order
  1813. // nibble of 0x5c to this value.
  1814. //
  1815. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5c);
  1816. hwDeviceExtension->CR5C = (VideoPortReadPortUchar(CRT_DATA_REG)
  1817. & 0x70) | 0x80;
  1818. }
  1819. #endif
  1820. VideoPortSetRegistryParameters(hwDeviceExtension,
  1821. L"HardwareInformation.AdapterString",
  1822. pwszAdapterString,
  1823. cbAdapterString);
  1824. //
  1825. // Is this a multi-card?
  1826. //
  1827. if (VideoPortScanRom(hwDeviceExtension,
  1828. (PVOID)((PUCHAR)romAddress + 0x7ff0),
  1829. 8,
  1830. "612167")) {
  1831. VideoDebugPrint((1, "Found a MEGA Lightning, dual S3 968\n"));
  1832. hwDeviceExtension->ChildCount = 1;
  1833. } else if (VideoPortScanRom(hwDeviceExtension,
  1834. (PVOID)((PUCHAR)romAddress + 0x7ff0),
  1835. 8,
  1836. "612168")) {
  1837. VideoDebugPrint((1, "Found a Pro Lightning+, dual S3 Trio64V+\n"));
  1838. hwDeviceExtension->ChildCount = 1;
  1839. } else if (VideoPortScanRom(hwDeviceExtension,
  1840. (PVOID)((PUCHAR)romAddress + 0x7ff0),
  1841. 8,
  1842. "612167")) {
  1843. VideoDebugPrint((1, "Found Quad Pro Lightning V+, quad S3 Trio64V+\n"));
  1844. hwDeviceExtension->ChildCount = 3;
  1845. }
  1846. }
  1847. VOID
  1848. S3DetermineDACType(
  1849. PVOID HwDeviceExtension,
  1850. POINTER_CAPABILITY *PointerCapability
  1851. )
  1852. /*++
  1853. Routine Description:
  1854. Determine the DAC type for HwPointer Capabilities.
  1855. Arguments:
  1856. HwDeviceExtension - Pointer to the miniport's device extension.
  1857. Return Value:
  1858. None.
  1859. --*/
  1860. {
  1861. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  1862. UCHAR jBt485Status;
  1863. UCHAR jExtendedVideoDacControl;
  1864. UCHAR jTiIndex;
  1865. UCHAR jGeneralOutput;
  1866. UCHAR jTiDacId;
  1867. PWSTR pwszDAC, pwszAdapterString = L"S3 Compatible";
  1868. ULONG cbDAC, cbAdapterString = sizeof(L"S3 Compatible");
  1869. hwDeviceExtension->DacID = UNKNOWN_DAC;
  1870. pwszDAC = L"Unknown";
  1871. cbDAC = sizeof(L"Unknown");
  1872. //
  1873. // We'll use a software pointer in all modes if the user sets
  1874. // the correct entry in the registry (because I predict that
  1875. // people will have hardware pointer problems on some boards,
  1876. // or won't like our jumpy S3 pointer).
  1877. //
  1878. if (NO_ERROR == VideoPortGetRegistryParameters(hwDeviceExtension,
  1879. L"UseSoftwareCursor",
  1880. FALSE,
  1881. S3RegistryCallback,
  1882. NULL)) {
  1883. hwDeviceExtension->Capabilities |= CAPS_SW_POINTER;
  1884. } else if (!(*PointerCapability & POINTER_BUILT_IN) ||
  1885. (hwDeviceExtension->ChipID == S3_928)) {
  1886. //
  1887. // Check for a TI TVP3020 or 3025 DAC.
  1888. //
  1889. // The TI3025 is sort of Brooktree 485 compatible. Unfortunately,
  1890. // there is a hardware bug between the TI and the 964 that
  1891. // causes the screen to occasionally jump when the pointer shape
  1892. // is changed. Consequently, we have to specifically use the
  1893. // TI pointer on the TI DAC.
  1894. //
  1895. // We also encountered some flakey Level 14 Number Nine boards
  1896. // that would show garbage on the screen when we used the S3
  1897. // internal pointer; consequently, we use the TI pointer instead.
  1898. //
  1899. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  1900. jGeneralOutput = VideoPortReadPortUchar(CRT_DATA_REG);
  1901. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) (jGeneralOutput & ~0x20));
  1902. // Select TI mode in the DAC
  1903. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1904. // Set CRTC index to EX_DAC_CT
  1905. jExtendedVideoDacControl = VideoPortReadPortUchar(CRT_DATA_REG);
  1906. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) ((jExtendedVideoDacControl & 0xfc) | 0x01));
  1907. jTiIndex = VideoPortReadPortUchar(TI025_INDEX_REG);
  1908. VideoPortWritePortUchar(TI025_INDEX_REG, 0x3f);
  1909. // Select ID register
  1910. if (VideoPortReadPortUchar(TI025_INDEX_REG) == 0x3f) {
  1911. jTiDacId = VideoPortReadPortUchar(TI025_DATA_REG);
  1912. if ((jTiDacId == 0x25) || (jTiDacId == 0x20)) {
  1913. hwDeviceExtension->Capabilities |= CAPS_TI025_POINTER;
  1914. hwDeviceExtension->DacID = TI_3020; // 3020 compatible
  1915. pwszDAC = L"TI TVP3020/3025";
  1916. cbDAC = sizeof(L"TI TVP3020/3025");
  1917. }
  1918. }
  1919. //
  1920. // Restore all the registers.
  1921. //
  1922. VideoPortWritePortUchar(TI025_INDEX_REG, jTiIndex);
  1923. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1924. VideoPortWritePortUchar(CRT_DATA_REG, jExtendedVideoDacControl);
  1925. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  1926. VideoPortWritePortUchar(CRT_DATA_REG, jGeneralOutput);
  1927. if (!(hwDeviceExtension->Capabilities & CAPS_DAC_POINTER)) {
  1928. //
  1929. // Check for a TI TVP3026 DAC.
  1930. //
  1931. // The procedure here is courtesy of Diamond Multimedia.
  1932. //
  1933. //
  1934. // This local declaration is extremely ugly, but the problem
  1935. // is that DAC_ADDRESS_WRITE_PORT is a macro that needs to
  1936. // dereference 'HwDeviceExtension' when all we have is a
  1937. // 'hwDeviceExtension'. I hate macros that take implicit
  1938. // arguments.
  1939. //
  1940. PHW_DEVICE_EXTENSION HwDeviceExtension = hwDeviceExtension;
  1941. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1942. // Set CRTC index to EX_DAC_CT
  1943. jExtendedVideoDacControl = VideoPortReadPortUchar(CRT_DATA_REG);
  1944. VideoPortWritePortUchar(CRT_DATA_REG,
  1945. (UCHAR) (jExtendedVideoDacControl & 0xfc));
  1946. VideoPortWritePortUchar(DAC_ADDRESS_WRITE_PORT, 0x3f);
  1947. VideoPortWritePortUchar(CRT_DATA_REG,
  1948. (UCHAR) ((jExtendedVideoDacControl & 0xfc) | 0x2));
  1949. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x37);
  1950. jTiDacId = VideoPortReadPortUchar(CRT_DATA_REG);
  1951. if (VideoPortReadPortUchar(DAC_PIXEL_MASK_REG) == 0x26) {
  1952. //
  1953. // The 3026 is Brooktree 485 compatible, except for a
  1954. // hardware bug that causes the hardware pointer to
  1955. // 'sparkle' when setting the palette colours, unless we
  1956. // wait for vertical retrace first:
  1957. //
  1958. hwDeviceExtension->Capabilities
  1959. |= (CAPS_BT485_POINTER | CAPS_WAIT_ON_PALETTE);
  1960. hwDeviceExtension->DacID = BT_485; // 485 compatible
  1961. pwszDAC = L"TI TVP3026";
  1962. cbDAC = sizeof(L"TI TVP3026");
  1963. }
  1964. //
  1965. // Restore all the registers.
  1966. //
  1967. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1968. VideoPortWritePortUchar(CRT_DATA_REG, jExtendedVideoDacControl);
  1969. }
  1970. if (!(hwDeviceExtension->Capabilities & CAPS_DAC_POINTER)) {
  1971. //
  1972. // Check for a BrookTree 485 DAC.
  1973. //
  1974. VideoPortWritePortUchar(BT485_ADDR_CMD_REG0, 0xff);
  1975. // Output 0xff to BT485 command register 0
  1976. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1977. // Set CRTC index to EX_DAC_CT
  1978. jExtendedVideoDacControl = VideoPortReadPortUchar(CRT_DATA_REG);
  1979. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) ((jExtendedVideoDacControl & 0xfc) | 0x02));
  1980. jBt485Status = VideoPortReadPortUchar(BT485_ADDR_CMD_REG0);
  1981. // Read Bt485 status register 0
  1982. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1983. // Set CRTC index to 0x55
  1984. jExtendedVideoDacControl = VideoPortReadPortUchar(CRT_DATA_REG);
  1985. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) (jExtendedVideoDacControl & 0xfc));
  1986. if (jBt485Status != 0xff) {
  1987. hwDeviceExtension->Capabilities |= CAPS_BT485_POINTER;
  1988. pwszDAC = L"Brooktree Bt485";
  1989. cbDAC = sizeof(L"Brooktree Bt485");
  1990. hwDeviceExtension->DacID = BT_485;
  1991. }
  1992. }
  1993. }
  1994. //
  1995. // This section looks for an S3 SDAC if another was not detected,
  1996. // for the PPC.
  1997. //
  1998. if (hwDeviceExtension->DacID == UNKNOWN_DAC) {
  1999. //
  2000. // Only try this on an 864 or newer, because Orchid Farhenheit
  2001. // 1280 911 boards would get black screens when in VGA mode and
  2002. // this code was run (such as during initial Setup):
  2003. //
  2004. if ((hwDeviceExtension->ChipID >= S3_864) &&
  2005. FindSDAC(hwDeviceExtension)) {
  2006. //
  2007. // SDAC does not provide a cursor, but we can use the cursor
  2008. // built into the S3 (if there is one).
  2009. //
  2010. pwszDAC = L"S3 SDAC";
  2011. cbDAC = sizeof(L"S3 SDAC");
  2012. hwDeviceExtension->DacID = S3_SDAC;
  2013. }
  2014. }
  2015. VideoPortSetRegistryParameters(hwDeviceExtension,
  2016. L"HardwareInformation.DacType",
  2017. pwszDAC,
  2018. cbDAC);
  2019. }
  2020. VOID
  2021. S3DetermineMemorySize(
  2022. PVOID HwDeviceExtension
  2023. )
  2024. {
  2025. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  2026. UCHAR s3MemSizeCode;
  2027. //
  2028. // Get the size of the video memory.
  2029. //
  2030. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x36);
  2031. s3MemSizeCode = (VideoPortReadPortUchar(CRT_DATA_REG) >> 5) & 0x7;
  2032. if (hwDeviceExtension->ChipID == S3_911) {
  2033. if (s3MemSizeCode & 1) {
  2034. hwDeviceExtension->AdapterMemorySize = 0x00080000;
  2035. } else {
  2036. hwDeviceExtension->AdapterMemorySize = 0x00100000;
  2037. }
  2038. } else {
  2039. hwDeviceExtension->AdapterMemorySize = gacjMemorySize[s3MemSizeCode];
  2040. }
  2041. VideoPortSetRegistryParameters(hwDeviceExtension,
  2042. L"HardwareInformation.MemorySize",
  2043. &hwDeviceExtension->AdapterMemorySize,
  2044. sizeof(ULONG));
  2045. }
  2046. VOID
  2047. S3ValidateModes(
  2048. PVOID HwDeviceExtension,
  2049. POINTER_CAPABILITY *PointerCapability
  2050. )
  2051. /*++
  2052. Routine Description:
  2053. For fill in the capabilities bits for the s3 card, and return an
  2054. wide character string representing the chip.
  2055. Arguments:
  2056. HwDeviceExtension - Pointer to the miniport's device extension.
  2057. Return Value:
  2058. None.
  2059. --*/
  2060. {
  2061. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  2062. PS3_VIDEO_FREQUENCIES FrequencyEntry;
  2063. PS3_VIDEO_MODES ModeEntry;
  2064. PS3_VIDEO_FREQUENCIES FrequencyTable;
  2065. ULONG i;
  2066. ULONG ModeIndex;
  2067. UCHAR reg67;
  2068. UCHAR jChipID, jRevision;
  2069. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x30);
  2070. jChipID = VideoPortReadPortUchar(CRT_DATA_REG);
  2071. /////////////////////////////////////////////////////////////////////////
  2072. // Here we prune valid modes, based on rules according to the chip
  2073. // capabilities and memory requirements. It would be better if we
  2074. // could make the VESA call to determine the modes that the BIOS
  2075. // supports; however, that requires a buffer and I don't have the
  2076. // time to get it working with our Int 10 support.
  2077. //
  2078. // We prune modes so that we will not annoy the user by presenting
  2079. // modes in the 'Video Applet' which we know the user can't use.
  2080. //
  2081. hwDeviceExtension->NumAvailableModes = 0;
  2082. hwDeviceExtension->NumTotalModes = 0;
  2083. //
  2084. // Since there are a number of frequencies possible for each
  2085. // distinct resolution/colour depth, we cycle through the
  2086. // frequency table and find the appropriate mode entry for that
  2087. // frequency entry.
  2088. //
  2089. if (hwDeviceExtension->BiosPresent) {
  2090. FrequencyTable = hwDeviceExtension->Int10FrequencyTable;
  2091. } else {
  2092. //
  2093. // If there is no BIOS, construct the mode list from whatever
  2094. // fixed frequency tables we have for this chip.
  2095. //
  2096. FrequencyTable = hwDeviceExtension->FixedFrequencyTable;
  2097. }
  2098. ModeIndex = 0;
  2099. for (FrequencyEntry = FrequencyTable;
  2100. FrequencyEntry->BitsPerPel != 0;
  2101. FrequencyEntry++, ModeIndex++) {
  2102. //
  2103. // Find the mode for this entry. First, assume we won't find one.
  2104. //
  2105. FrequencyEntry->ModeValid = FALSE;
  2106. FrequencyEntry->ModeIndex = ModeIndex;
  2107. for (ModeEntry = S3Modes, i = 0; i < NumS3VideoModes; ModeEntry++, i++) {
  2108. if ((FrequencyEntry->BitsPerPel ==
  2109. ModeEntry->ModeInformation.BitsPerPlane) &&
  2110. (FrequencyEntry->ScreenWidth ==
  2111. ModeEntry->ModeInformation.VisScreenWidth)) {
  2112. //
  2113. // We've found a mode table entry that matches this frequency
  2114. // table entry. Now we'll figure out if we can actually do
  2115. // this mode/frequency combination. For now, assume we'll
  2116. // succeed.
  2117. //
  2118. FrequencyEntry->ModeEntry = ModeEntry;
  2119. FrequencyEntry->ModeValid = TRUE;
  2120. //
  2121. // Flags for private communication with the S3 display driver.
  2122. //
  2123. ModeEntry->ModeInformation.DriverSpecificAttributeFlags =
  2124. hwDeviceExtension->Capabilities;
  2125. if (*PointerCapability & POINTER_WORKS_ONLY_AT_8BPP) {
  2126. //
  2127. // Rule: On 911, 80x, and 928 chips we always use the
  2128. // built-in S3 pointer whenever we can; modes of
  2129. // colour depths greater than 8bpp, or resolutions
  2130. // of width more than 1024, require a DAC pointer.
  2131. //
  2132. if ((ModeEntry->ModeInformation.BitsPerPlane == 8) &&
  2133. (ModeEntry->ModeInformation.VisScreenWidth <= 1024)) {
  2134. //
  2135. // Always use the S3 pointer in lieu of the Brooktree
  2136. // or TI pointer whenever we can.
  2137. //
  2138. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2139. &= ~CAPS_DAC_POINTER;
  2140. if ((hwDeviceExtension->DacID == TI_3020) &&
  2141. (hwDeviceExtension->ChipID == S3_928)) {
  2142. //
  2143. // There are goofy 4-MB Level 14 #9 boards where
  2144. // stuff is shown on the screen if we try to use
  2145. // the built-in S3 pointer, and the hot-spot
  2146. // is wrong if we try to use the TI pointer.
  2147. // There are other 928 boards with TI 3020 DACs
  2148. // where the internal S3 pointer doesn't work. So
  2149. // punt to a software pointer for these modes:
  2150. //
  2151. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2152. |= CAPS_SW_POINTER;
  2153. }
  2154. } else {
  2155. //
  2156. // We can't use the built-in S3 pointer; if we don't
  2157. // have a DAC pointer, use a software pointer.
  2158. //
  2159. if (!(ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2160. & CAPS_DAC_POINTER)) {
  2161. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2162. |= CAPS_SW_POINTER;
  2163. }
  2164. }
  2165. } else {
  2166. //
  2167. // On 864/964 or newer chips, the built-in S3 pointer
  2168. // either handles all colour depths or none.
  2169. //
  2170. if (*PointerCapability & POINTER_BUILT_IN) {
  2171. if (*PointerCapability & POINTER_NEEDS_SCALING) {
  2172. //
  2173. // Check out the type of DAC:
  2174. //
  2175. // Note: This I/O should likely be moved out of the
  2176. // prune loop.
  2177. //
  2178. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x67);
  2179. reg67 = (UCHAR) VideoPortReadPortUchar(CRT_DATA_REG);
  2180. //
  2181. // Newer 864 BIOSes revert to 8-bit DAC mode when
  2182. // running at 640x480x16bpp even if the DAC is
  2183. // 16-bits, due to a conflict with the Reel Magic
  2184. // MPEG board at that resolution. Unfortunately,
  2185. // there's not a consistent BIOS version number
  2186. // that we can look for; we could check the
  2187. // DAC type after doing the int 10, but
  2188. // unfortunately, we need this information now
  2189. // to decide whether we should scale the x-
  2190. // coordinate or not.
  2191. //
  2192. // So simply always use a software pointer when
  2193. // running at 640x480x16bpp, and there is no
  2194. // DAC pointer:
  2195. //
  2196. if (!(ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2197. & CAPS_DAC_POINTER) &&
  2198. (ModeEntry->ModeInformation.BitsPerPlane == 16) &&
  2199. (ModeEntry->ModeInformation.VisScreenWidth == 640)) {
  2200. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2201. |= CAPS_SW_POINTER;
  2202. } else if (reg67 == 8) {
  2203. //
  2204. // It's an 8bit DAC. At 16bpp, we have to
  2205. // scale the x-coordinate by 2. At 32bpp,
  2206. // we have to use a software pointer.
  2207. //
  2208. if (ModeEntry->ModeInformation.BitsPerPlane == 16) {
  2209. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2210. |= CAPS_SCALE_POINTER;
  2211. } else {
  2212. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2213. |= CAPS_SW_POINTER;
  2214. }
  2215. } else {
  2216. //
  2217. // It's a 16bit DAC. For 32bpp modes, we have
  2218. // to scale the pointer position by 2:
  2219. //
  2220. if (ModeEntry->ModeInformation.BitsPerPlane == 32) {
  2221. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2222. |= CAPS_SCALE_POINTER;
  2223. }
  2224. }
  2225. }
  2226. } else {
  2227. //
  2228. // There's no built-in S3 pointer. If we haven't
  2229. // detected a DAC pointer, we have to use a software
  2230. // pointer.
  2231. //
  2232. if (!(ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2233. & CAPS_DAC_POINTER)) {
  2234. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2235. |= CAPS_SW_POINTER;
  2236. }
  2237. }
  2238. }
  2239. //
  2240. // Rule: We allow refresh rates higher than 76 Hz only for
  2241. // cards that don't have a built-in S3 pointer. We
  2242. // do this because we assume that such cards are VRAM
  2243. // based and have a good external DAC that can properly
  2244. // handle rates higher than 76 Hz -- because we have
  2245. // found many Diamond DRAM cards that produce improper
  2246. // displays at the higher rates, especially on non-x86
  2247. // machines.
  2248. //
  2249. if ((FrequencyEntry->ScreenFrequency > 76) &&
  2250. (*PointerCapability & POINTER_BUILT_IN)) {
  2251. FrequencyEntry->ModeValid = FALSE;
  2252. }
  2253. //
  2254. // Rule: We handle only 8bpp on 911/924 cards. These chips can also
  2255. // support only non-contiguous modes.
  2256. //
  2257. if (hwDeviceExtension->ChipID == S3_911) {
  2258. if (ModeEntry->ModeInformation.BitsPerPlane != 8) {
  2259. FrequencyEntry->ModeValid = FALSE;
  2260. } else {
  2261. ModeEntry->Int10ModeNumberContiguous =
  2262. ModeEntry->Int10ModeNumberNoncontiguous;
  2263. ModeEntry->ScreenStrideContiguous =
  2264. ModeEntry->ModeInformation.ScreenStride;
  2265. }
  2266. }
  2267. //
  2268. // Rule: The 868/968 cannot do 'new packed 32-bit transfers'
  2269. // at 8bpp because of a chip bug.
  2270. //
  2271. if ((ModeEntry->ModeInformation.BitsPerPlane == 8) &&
  2272. ((hwDeviceExtension->SubTypeID == SUBTYPE_868) ||
  2273. (hwDeviceExtension->SubTypeID == SUBTYPE_968))) {
  2274. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2275. &= ~CAPS_PACKED_EXPANDS;
  2276. }
  2277. //
  2278. // Rule: The 801/805 cannot do any accelerated modes above
  2279. // 16bpp.
  2280. //
  2281. if ((hwDeviceExtension->ChipID == S3_801) &&
  2282. (ModeEntry->ModeInformation.BitsPerPlane > 16)) {
  2283. FrequencyEntry->ModeValid = FALSE;
  2284. }
  2285. //
  2286. // Rule: We use the 2xx non-contiguous modes whenever we can
  2287. // on 80x/928 boards because some BIOSes have bugs for
  2288. // the contiguous 8bpp modes.
  2289. //
  2290. // We don't use the non-contiguous modes on 864 cards
  2291. // because most 864 BIOSes have a bug where they don't
  2292. // set the M and N parameters correctly on 1 MB cards,
  2293. // causing screen noise.
  2294. //
  2295. if ((ModeEntry->ModeInformation.BitsPerPlane == 8) &&
  2296. (hwDeviceExtension->ChipID <= S3_928)) {
  2297. //
  2298. // If we have only 512k, we can't use a non-contiguous
  2299. // 800x600x256 mode.
  2300. //
  2301. if ((ModeEntry->ModeInformation.VisScreenWidth == 640) ||
  2302. ((ModeEntry->ModeInformation.VisScreenWidth == 800) &&
  2303. (hwDeviceExtension->AdapterMemorySize > 0x080000))) {
  2304. ModeEntry->Int10ModeNumberContiguous =
  2305. ModeEntry->Int10ModeNumberNoncontiguous;
  2306. ModeEntry->ScreenStrideContiguous =
  2307. ModeEntry->ModeInformation.ScreenStride;
  2308. }
  2309. }
  2310. //
  2311. // Rule: Only 964 or 968 or newer boards can handle resolutions
  2312. // larger than 1280x1024:
  2313. //
  2314. if (ModeEntry->ModeInformation.VisScreenWidth > 1280) {
  2315. if ((hwDeviceExtension->SubTypeID != SUBTYPE_964) &&
  2316. (hwDeviceExtension->SubTypeID < SUBTYPE_968)) {
  2317. FrequencyEntry->ModeValid = FALSE;
  2318. }
  2319. }
  2320. //
  2321. // Rule: 911s and early revs of 805s and 928s cannot do
  2322. // 1152x864:
  2323. //
  2324. if (ModeEntry->ModeInformation.VisScreenWidth == 1152) {
  2325. if ((hwDeviceExtension->ChipID == S3_911) ||
  2326. (jChipID == 0xA0) ||
  2327. (jChipID == 0x90)) {
  2328. FrequencyEntry->ModeValid = FALSE;
  2329. }
  2330. //
  2331. // Number 9 has different int 10 numbers from
  2332. // Diamond for 1152x864x16bpp and 1152x864x32bpp.
  2333. // Later perhaps we should incorporate mode numbers
  2334. // along with the frequency tables.
  2335. //
  2336. if (hwDeviceExtension->BoardID == S3_NUMBER_NINE) {
  2337. if (ModeEntry->ModeInformation.BitsPerPlane == 16) {
  2338. ModeEntry->Int10ModeNumberContiguous =
  2339. ModeEntry->Int10ModeNumberNoncontiguous =
  2340. 0x126;
  2341. } else if (ModeEntry->ModeInformation.BitsPerPlane == 32) {
  2342. ModeEntry->Int10ModeNumberContiguous =
  2343. ModeEntry->Int10ModeNumberNoncontiguous =
  2344. 0x127;
  2345. }
  2346. }
  2347. }
  2348. //
  2349. // 24bpp support. Need s3 968 and linear space for banks.
  2350. //
  2351. if (ModeEntry->ModeInformation.BitsPerPlane == 24) {
  2352. //
  2353. // 24bpp on diamond s3 968 seems to have problems doing ULONG reads.
  2354. //
  2355. if (hwDeviceExtension->BoardID == S3_DIAMOND)
  2356. ModeEntry->ModeInformation.DriverSpecificAttributeFlags |=
  2357. CAPS_BAD_DWORD_READS;
  2358. //
  2359. // Set FALSE for other than 968 and clear CAPS_BAD_DWORD_READS.
  2360. //
  2361. if ((hwDeviceExtension->SubTypeID != SUBTYPE_968) ||
  2362. ((hwDeviceExtension->BoardID != S3_DIAMOND) &&
  2363. (hwDeviceExtension->BoardID != S3_NUMBER_NINE)) || //#9 968 24bpp
  2364. (!(hwDeviceExtension->Capabilities & CAPS_NEW_MMIO))) {
  2365. FrequencyEntry->ModeValid = FALSE;
  2366. ModeEntry->ModeInformation.DriverSpecificAttributeFlags &=
  2367. ~CAPS_BAD_DWORD_READS;
  2368. }
  2369. }
  2370. if ((ModeEntry->ModeInformation.VisScreenWidth == 800) &&
  2371. (ModeEntry->ModeInformation.BitsPerPlane == 32)) {
  2372. //
  2373. // Rule: 928 revs A through D can only do 800x600x32 in
  2374. // a non-contiguous mode.
  2375. //
  2376. if (jChipID == 0x90) {
  2377. ModeEntry->ScreenStrideContiguous =
  2378. ModeEntry->ModeInformation.ScreenStride;
  2379. }
  2380. }
  2381. if (hwDeviceExtension->SubTypeID == SUBTYPE_732) {
  2382. //
  2383. // Rule: The 732 Trio32 chip simply can't do 800x600x32bpp.
  2384. //
  2385. if ((ModeEntry->ModeInformation.VisScreenWidth == 800) &&
  2386. (ModeEntry->ModeInformation.BitsPerPlane == 32)) {
  2387. FrequencyEntry->ModeValid = FALSE;
  2388. //
  2389. // Rule: The 732 Trio32 chip simply can't do 1152x864x16bpp.
  2390. //
  2391. } else if ((ModeEntry->ModeInformation.VisScreenWidth == 1152) &&
  2392. (ModeEntry->ModeInformation.BitsPerPlane == 16)) {
  2393. FrequencyEntry->ModeValid = FALSE;
  2394. //
  2395. // Rule: The 732 Trio32 chip simply can't do 1280x1024 modes
  2396. //
  2397. } else if ((ModeEntry->ModeInformation.VisScreenWidth) == 1280) {
  2398. FrequencyEntry->ModeValid = FALSE;
  2399. }
  2400. }
  2401. //
  2402. // Rule: We have to have enough memory to handle the mode.
  2403. //
  2404. // Note that we use the contiguous width for this
  2405. // computation; unfortunately, we don't know at this time
  2406. // whether we can handle a contiguous mode or not, so we
  2407. // may err on the side of listing too many possible modes.
  2408. //
  2409. // We may also list too many possible modes if the card
  2410. // combines VRAM with a DRAM cache, because it will report
  2411. // the VRAM + DRAM amount of memory, but only the VRAM can
  2412. // be used as screen memory.
  2413. //
  2414. if (ModeEntry->ModeInformation.VisScreenHeight *
  2415. ModeEntry->ScreenStrideContiguous >
  2416. hwDeviceExtension->AdapterMemorySize) {
  2417. FrequencyEntry->ModeValid = FALSE;
  2418. }
  2419. //
  2420. // Rule: If we can't use Int 10, restrict 1280x1024 to Number9
  2421. // cards, because I haven't been able to fix the mode
  2422. // tables for other cards yet.
  2423. //
  2424. if (FrequencyTable == hwDeviceExtension->FixedFrequencyTable) {
  2425. if ((ModeEntry->ModeInformation.VisScreenHeight == 1280) &&
  2426. (hwDeviceExtension->BoardID != S3_NUMBER_NINE)) {
  2427. FrequencyEntry->ModeValid = FALSE;
  2428. }
  2429. //
  2430. // Rule: If there isn't a table entry for programming the CRTC,
  2431. // we can't do this frequency at this mode.
  2432. //
  2433. if (FrequencyEntry->Fixed.CRTCTable[hwDeviceExtension->ChipID]
  2434. == NULL) {
  2435. FrequencyEntry->ModeValid = FALSE;
  2436. break;
  2437. }
  2438. }
  2439. //
  2440. // Don't forget to count it if it's still a valid mode after
  2441. // applying all those rules.
  2442. //
  2443. if (FrequencyEntry->ModeValid) {
  2444. hwDeviceExtension->NumAvailableModes++;
  2445. }
  2446. //
  2447. // We've found a mode for this frequency entry, so we
  2448. // can break out of the mode loop:
  2449. //
  2450. break;
  2451. }
  2452. }
  2453. }
  2454. hwDeviceExtension->NumTotalModes = ModeIndex;
  2455. VideoDebugPrint((2, "S3: Number of modes = %d\n", ModeIndex));
  2456. }
  2457. VP_STATUS
  2458. S3RegistryCallback(
  2459. PVOID HwDeviceExtension,
  2460. PVOID Context,
  2461. PWSTR ValueName,
  2462. PVOID ValueData,
  2463. ULONG ValueLength
  2464. )
  2465. /*++
  2466. Routine Description:
  2467. This routine determines if the alternate register set was requested via
  2468. the registry.
  2469. Arguments:
  2470. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  2471. Context - Context value passed to the get registry paramters routine.
  2472. ValueName - Name of the value requested.
  2473. ValueData - Pointer to the requested data.
  2474. ValueLength - Length of the requested data.
  2475. Return Value:
  2476. returns NO_ERROR if the paramter was TRUE.
  2477. returns ERROR_INVALID_PARAMETER otherwise.
  2478. --*/
  2479. {
  2480. if (ValueLength && *((PULONG)ValueData)) {
  2481. return NO_ERROR;
  2482. } else {
  2483. return ERROR_INVALID_PARAMETER;
  2484. }
  2485. } // end S3RegistryCallback()
  2486. BOOLEAN
  2487. S3Initialize(
  2488. PVOID HwDeviceExtension
  2489. )
  2490. /*++
  2491. Routine Description:
  2492. This routine does one time initialization of the device.
  2493. Arguments:
  2494. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  2495. Return Value:
  2496. Always returns TRUE since this routine can never fail.
  2497. --*/
  2498. {
  2499. UNREFERENCED_PARAMETER(HwDeviceExtension);
  2500. return TRUE;
  2501. } // end S3Initialize()
  2502. BOOLEAN
  2503. S3ResetHw(
  2504. PVOID HwDeviceExtension,
  2505. ULONG Columns,
  2506. ULONG Rows
  2507. )
  2508. /*++
  2509. Routine Description:
  2510. This routine preps the S3 card for return to a VGA mode.
  2511. This routine is called during system shutdown. By returning
  2512. a FALSE we inform the HAL to do an int 10 to go into text
  2513. mode before shutting down. Shutdown would fail with some S3
  2514. cards without this.
  2515. We do some clean up before returning so that the int 10
  2516. will work.
  2517. Arguments:
  2518. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  2519. Return Value:
  2520. The return value of FALSE informs the hal to go into text mode.
  2521. --*/
  2522. {
  2523. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  2524. UNREFERENCED_PARAMETER(Columns);
  2525. UNREFERENCED_PARAMETER(Rows);
  2526. //
  2527. // We don't want to execute this reset code if we are not
  2528. // currently in an S3 mode!
  2529. //
  2530. if (!hwDeviceExtension->bNeedReset)
  2531. {
  2532. return FALSE;
  2533. }
  2534. hwDeviceExtension->bNeedReset = FALSE;
  2535. //
  2536. // Wait for the GP to become idle.
  2537. //
  2538. while (VideoPortReadPortUshort(GP_STAT) & 0x0200);
  2539. //
  2540. // Zero the DAC and the Screen buffer memory.
  2541. //
  2542. ZeroMemAndDac(HwDeviceExtension);
  2543. //
  2544. // Reset the board to a default mode
  2545. //
  2546. // After NT 3.51 ships use the same modetable for all
  2547. // architectures, but just to be sure we don't break
  2548. // something we'll use two for now. The 'no_bios'
  2549. // version of the modetable is for the IBM PS/2 model
  2550. // 76i.
  2551. //
  2552. if (hwDeviceExtension->BiosPresent == FALSE)
  2553. {
  2554. SetHWMode(HwDeviceExtension, s3_set_vga_mode_no_bios);
  2555. }
  2556. else
  2557. {
  2558. SetHWMode(HwDeviceExtension, s3_set_vga_mode);
  2559. }
  2560. return FALSE;
  2561. }
  2562. BOOLEAN
  2563. S3StartIO(
  2564. PVOID pvHwDeviceExtension,
  2565. PVIDEO_REQUEST_PACKET RequestPacket
  2566. )
  2567. /*++
  2568. Routine Description:
  2569. This routine is the main execution routine for the miniport driver. It
  2570. acceptss a Video Request Packet, performs the request, and then returns
  2571. with the appropriate status.
  2572. Arguments:
  2573. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  2574. RequestPacket - Pointer to the video request packet. This structure
  2575. contains all the parameters passed to the VideoIoControl function.
  2576. Return Value:
  2577. --*/
  2578. {
  2579. PHW_DEVICE_EXTENSION hwDeviceExtension = pvHwDeviceExtension;
  2580. PHW_DEVICE_EXTENSION HwDeviceExtension = pvHwDeviceExtension;
  2581. VP_STATUS status;
  2582. PVIDEO_MODE_INFORMATION modeInformation;
  2583. PVIDEO_CLUT clutBuffer;
  2584. UCHAR byte;
  2585. ULONG modeNumber;
  2586. PS3_VIDEO_MODES ModeEntry;
  2587. PS3_VIDEO_FREQUENCIES FrequencyEntry;
  2588. PS3_VIDEO_FREQUENCIES FrequencyTable;
  2589. UCHAR ModeControlByte;
  2590. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  2591. PVIDEO_SHARE_MEMORY pShareMemory;
  2592. PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
  2593. PHYSICAL_ADDRESS shareAddress;
  2594. PVOID virtualAddress;
  2595. ULONG sharedViewSize;
  2596. ULONG inIoSpace;
  2597. UCHAR OriginalRegPrimary;
  2598. UCHAR OriginalRegSecondary;
  2599. //
  2600. // Switch on the IoContolCode in the RequestPacket. It indicates which
  2601. // function must be performed by the driver.
  2602. //
  2603. switch (RequestPacket->IoControlCode) {
  2604. case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
  2605. VideoDebugPrint((2, "S3tartIO - MapVideoMemory\n"));
  2606. {
  2607. PVIDEO_MEMORY_INFORMATION memoryInformation;
  2608. ULONG physicalFrameLength;
  2609. ULONG inIoSpace;
  2610. if ( (RequestPacket->OutputBufferLength <
  2611. (RequestPacket->StatusBlock->Information =
  2612. sizeof(VIDEO_MEMORY_INFORMATION))) ||
  2613. (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
  2614. status = ERROR_INSUFFICIENT_BUFFER;
  2615. break;
  2616. }
  2617. memoryInformation = RequestPacket->OutputBuffer;
  2618. memoryInformation->VideoRamBase = ((PVIDEO_MEMORY)
  2619. (RequestPacket->InputBuffer))->RequestedVirtualAddress;
  2620. physicalFrameLength = hwDeviceExtension->FrameLength;
  2621. inIoSpace = hwDeviceExtension->PhysicalFrameIoSpace;
  2622. //
  2623. // IMPORTANT - As a rule we only map the actual amount of memory
  2624. // on the board, not the whole physical address space reported
  2625. // by PCI. The reason for this is that mapping the memory takes
  2626. // up a lot of resources in the machine, which as quite scarce by
  2627. // default. Mapping 64MEG of address space would actually always
  2628. // fail in machines that have 32MEG or even 64MEG of RAM.
  2629. //
  2630. //
  2631. // Performance:
  2632. //
  2633. // Enable USWC on the P6 processor.
  2634. // We only do it for the frame buffer - memory mapped registers can
  2635. // not be mapped USWC because write combining the registers would
  2636. // cause very bad things to happen !
  2637. //
  2638. inIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  2639. //
  2640. // P6 workaround:
  2641. //
  2642. // Because of a current limitation in many P6 machines, USWC only
  2643. // works on sections of 4MEG of memory. So lets round up the size
  2644. // of memory on the cards that have less than 4MEG up to 4MEG so
  2645. // they can also benefit from this feature.
  2646. //
  2647. // We will only do this for NEW_MMIO cards, which have a large
  2648. // block of address space that is reserved via PCI. This way
  2649. // we are sure we will not conflict with another device that might
  2650. // have addresses right after us.
  2651. //
  2652. // We do this only for mapping purposes. We still want to return
  2653. // the real size of memory since the driver can not use memory that
  2654. // is not actually there !
  2655. //
  2656. if ((hwDeviceExtension->Capabilities & CAPS_NEW_MMIO) &&
  2657. (physicalFrameLength < 0x00400000)) {
  2658. physicalFrameLength = 0x00400000;
  2659. }
  2660. status = VideoPortMapMemory(hwDeviceExtension,
  2661. hwDeviceExtension->PhysicalFrameAddress,
  2662. &physicalFrameLength,
  2663. &inIoSpace,
  2664. &(memoryInformation->VideoRamBase));
  2665. //
  2666. // The frame buffer and virtual memory are equivalent in this
  2667. // case.
  2668. //
  2669. memoryInformation->FrameBufferBase =
  2670. memoryInformation->VideoRamBase;
  2671. memoryInformation->FrameBufferLength =
  2672. hwDeviceExtension->FrameLength;
  2673. memoryInformation->VideoRamLength =
  2674. hwDeviceExtension->FrameLength;
  2675. }
  2676. break;
  2677. case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
  2678. VideoDebugPrint((2, "S3StartIO - UnMapVideoMemory\n"));
  2679. if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) {
  2680. status = ERROR_INSUFFICIENT_BUFFER;
  2681. break;
  2682. }
  2683. status = VideoPortUnmapMemory(hwDeviceExtension,
  2684. ((PVIDEO_MEMORY)
  2685. (RequestPacket->InputBuffer))->
  2686. RequestedVirtualAddress,
  2687. 0);
  2688. break;
  2689. case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
  2690. VideoDebugPrint((2, "S3StartIO - QueryPublicAccessRanges\n"));
  2691. {
  2692. PVIDEO_PUBLIC_ACCESS_RANGES portAccess;
  2693. ULONG physicalPortLength;
  2694. if ( RequestPacket->OutputBufferLength <
  2695. (RequestPacket->StatusBlock->Information =
  2696. 2 * sizeof(VIDEO_PUBLIC_ACCESS_RANGES)) ) {
  2697. status = ERROR_INSUFFICIENT_BUFFER;
  2698. break;
  2699. }
  2700. portAccess = RequestPacket->OutputBuffer;
  2701. portAccess->VirtualAddress = (PVOID) NULL; // Requested VA
  2702. portAccess->InIoSpace = hwDeviceExtension->RegisterSpace;
  2703. portAccess->MappedInIoSpace = portAccess->InIoSpace;
  2704. physicalPortLength = hwDeviceExtension->RegisterLength;
  2705. status = VideoPortMapMemory(hwDeviceExtension,
  2706. hwDeviceExtension->PhysicalRegisterAddress,
  2707. &physicalPortLength,
  2708. &(portAccess->MappedInIoSpace),
  2709. &(portAccess->VirtualAddress));
  2710. if (status == NO_ERROR) {
  2711. portAccess++;
  2712. portAccess->VirtualAddress = (PVOID) NULL; // Requested VA
  2713. portAccess->InIoSpace = hwDeviceExtension->MmIoSpace;
  2714. portAccess->MappedInIoSpace = portAccess->InIoSpace;
  2715. physicalPortLength = hwDeviceExtension->MmIoLength;
  2716. status = VideoPortMapMemory(hwDeviceExtension,
  2717. hwDeviceExtension->PhysicalMmIoAddress,
  2718. &physicalPortLength,
  2719. &(portAccess->MappedInIoSpace),
  2720. &(portAccess->VirtualAddress));
  2721. }
  2722. }
  2723. break;
  2724. case IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES:
  2725. VideoDebugPrint((2, "S3StartIO - FreePublicAccessRanges\n"));
  2726. {
  2727. PVIDEO_MEMORY mappedMemory;
  2728. if (RequestPacket->InputBufferLength < 2 * sizeof(VIDEO_MEMORY)) {
  2729. status = ERROR_INSUFFICIENT_BUFFER;
  2730. break;
  2731. }
  2732. status = NO_ERROR;
  2733. mappedMemory = RequestPacket->InputBuffer;
  2734. if (mappedMemory->RequestedVirtualAddress != NULL) {
  2735. status = VideoPortUnmapMemory(hwDeviceExtension,
  2736. mappedMemory->
  2737. RequestedVirtualAddress,
  2738. 0);
  2739. }
  2740. if (status == NO_ERROR) {
  2741. mappedMemory++;
  2742. status = VideoPortUnmapMemory(hwDeviceExtension,
  2743. mappedMemory->
  2744. RequestedVirtualAddress,
  2745. 0);
  2746. }
  2747. }
  2748. break;
  2749. case IOCTL_VIDEO_QUERY_AVAIL_MODES:
  2750. VideoDebugPrint((2, "S3StartIO - QueryAvailableModes\n"));
  2751. if (RequestPacket->OutputBufferLength <
  2752. (RequestPacket->StatusBlock->Information =
  2753. hwDeviceExtension->NumAvailableModes
  2754. * sizeof(VIDEO_MODE_INFORMATION)) ) {
  2755. VideoDebugPrint((1, "\n*** NOT ENOUGH MEMORY FOR OUTPUT ***\n\n"));
  2756. status = ERROR_INSUFFICIENT_BUFFER;
  2757. } else {
  2758. modeInformation = RequestPacket->OutputBuffer;
  2759. if (hwDeviceExtension->BiosPresent) {
  2760. FrequencyTable = hwDeviceExtension->Int10FrequencyTable;
  2761. } else {
  2762. FrequencyTable = hwDeviceExtension->FixedFrequencyTable;
  2763. }
  2764. for (FrequencyEntry = FrequencyTable;
  2765. FrequencyEntry->BitsPerPel != 0;
  2766. FrequencyEntry++) {
  2767. if (FrequencyEntry->ModeValid) {
  2768. *modeInformation =
  2769. FrequencyEntry->ModeEntry->ModeInformation;
  2770. modeInformation->Frequency =
  2771. FrequencyEntry->ScreenFrequency;
  2772. modeInformation->ModeIndex =
  2773. FrequencyEntry->ModeIndex;
  2774. modeInformation++;
  2775. }
  2776. }
  2777. status = NO_ERROR;
  2778. }
  2779. break;
  2780. case IOCTL_VIDEO_QUERY_CURRENT_MODE:
  2781. VideoDebugPrint((2, "S3StartIO - QueryCurrentModes\n"));
  2782. if (RequestPacket->OutputBufferLength <
  2783. (RequestPacket->StatusBlock->Information =
  2784. sizeof(VIDEO_MODE_INFORMATION)) ) {
  2785. status = ERROR_INSUFFICIENT_BUFFER;
  2786. } else {
  2787. *((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer) =
  2788. hwDeviceExtension->ActiveModeEntry->ModeInformation;
  2789. ((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer)->Frequency =
  2790. hwDeviceExtension->ActiveFrequencyEntry->ScreenFrequency;
  2791. status = NO_ERROR;
  2792. }
  2793. break;
  2794. case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
  2795. VideoDebugPrint((2, "S3StartIO - QueryNumAvailableModes\n"));
  2796. //
  2797. // Find out the size of the data to be put in the the buffer and
  2798. // return that in the status information (whether or not the
  2799. // information is there). If the buffer passed in is not large
  2800. // enough return an appropriate error code.
  2801. //
  2802. if (RequestPacket->OutputBufferLength <
  2803. (RequestPacket->StatusBlock->Information =
  2804. sizeof(VIDEO_NUM_MODES)) ) {
  2805. status = ERROR_INSUFFICIENT_BUFFER;
  2806. } else {
  2807. ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->NumModes =
  2808. hwDeviceExtension->NumAvailableModes;
  2809. ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->ModeInformationLength =
  2810. sizeof(VIDEO_MODE_INFORMATION);
  2811. status = NO_ERROR;
  2812. }
  2813. break;
  2814. case IOCTL_VIDEO_SET_CURRENT_MODE:
  2815. VideoDebugPrint((2, "S3StartIO - SetCurrentMode\n"));
  2816. //
  2817. // Check if the size of the data in the input buffer is large enough.
  2818. //
  2819. if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE)) {
  2820. status = ERROR_INSUFFICIENT_BUFFER;
  2821. break;
  2822. }
  2823. //
  2824. // Assume failure for now.
  2825. //
  2826. status = ERROR_INVALID_PARAMETER;
  2827. //
  2828. // Find the correct entries in the S3_VIDEO_MODES and S3_VIDEO_FREQUENCIES
  2829. // tables that correspond to this mode number. (Remember that each
  2830. // mode in the S3_VIDEO_MODES table can have a number of possible
  2831. // frequencies associated with it.)
  2832. //
  2833. modeNumber = ((PVIDEO_MODE) RequestPacket->InputBuffer)->RequestedMode;
  2834. if (modeNumber >= hwDeviceExtension->NumTotalModes) {
  2835. break;
  2836. }
  2837. if (hwDeviceExtension->BiosPresent) {
  2838. FrequencyEntry = &hwDeviceExtension->Int10FrequencyTable[modeNumber];
  2839. if (!(FrequencyEntry->ModeValid)) {
  2840. break;
  2841. }
  2842. ModeEntry = FrequencyEntry->ModeEntry;
  2843. //
  2844. // At this point, 'ModeEntry' and 'FrequencyEntry' point to the
  2845. // necessary table entries required for setting the requested mode.
  2846. //
  2847. VideoPortZeroMemory(&biosArguments, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
  2848. //
  2849. // Unlock the S3 registers.
  2850. //
  2851. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x4838);
  2852. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xA039);
  2853. //
  2854. // Use register 52 before every Int 10 modeset to set the refresh
  2855. // rate. If the card doesn't support it, or we don't know what
  2856. // values to use, the requested frequency will be '1', which means
  2857. // 'use the hardware default refresh.'
  2858. //
  2859. if (FrequencyEntry->ScreenFrequency != 1) {
  2860. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x52);
  2861. OriginalRegPrimary = VideoPortReadPortUchar(CRT_DATA_REG);
  2862. ModeControlByte = OriginalRegPrimary;
  2863. ModeControlByte &= ~FrequencyEntry->Int10.FrequencyPrimaryMask;
  2864. ModeControlByte |= FrequencyEntry->Int10.FrequencyPrimarySet;
  2865. VideoPortWritePortUchar(CRT_DATA_REG, ModeControlByte);
  2866. if (FrequencyEntry->Int10.FrequencySecondaryMask != 0) {
  2867. VideoPortWritePortUchar(CRT_ADDRESS_REG,
  2868. hwDeviceExtension->FrequencySecondaryIndex);
  2869. OriginalRegSecondary = VideoPortReadPortUchar(CRT_DATA_REG);
  2870. ModeControlByte = OriginalRegSecondary;
  2871. ModeControlByte &= ~FrequencyEntry->Int10.FrequencySecondaryMask;
  2872. ModeControlByte |= FrequencyEntry->Int10.FrequencySecondarySet;
  2873. VideoPortWritePortUchar(CRT_DATA_REG, ModeControlByte);
  2874. }
  2875. }
  2876. //
  2877. // To do 24bpp on the #9 968 set bit 7 in register 41 before every
  2878. // Int 10 modeset. If not doing 24bpp, clear that bit.
  2879. //
  2880. if ((hwDeviceExtension->BoardID == S3_NUMBER_NINE) &&
  2881. (hwDeviceExtension->SubTypeID == SUBTYPE_968)) {
  2882. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x41);
  2883. OriginalRegPrimary = VideoPortReadPortUchar(CRT_DATA_REG);
  2884. ModeControlByte = OriginalRegPrimary;
  2885. if (ModeEntry->ModeInformation.BitsPerPlane == 24) {
  2886. ModeControlByte |= 0x80;
  2887. } else {
  2888. ModeControlByte &= ~0x80;
  2889. }
  2890. VideoPortWritePortUchar(CRT_DATA_REG, ModeControlByte);
  2891. }
  2892. //
  2893. // Turn off the screen to work around a bug in some
  2894. // s3 bios's. (The symptom of the bug is we loop
  2895. // forever in the bios after trying to set a mode.)
  2896. //
  2897. VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x1);
  2898. VideoPortWritePortUchar(SEQ_DATA_REG,
  2899. (UCHAR)(VideoPortReadPortUchar(SEQ_DATA_REG) | 0x20));
  2900. //
  2901. // First try the modeset with the 'Contiguous' mode:
  2902. //
  2903. biosArguments.Ebx = ModeEntry->Int10ModeNumberContiguous;
  2904. biosArguments.Eax = 0x4f02;
  2905. status = VideoPortInt10(HwDeviceExtension, &biosArguments);
  2906. if (status != NO_ERROR) {
  2907. VideoDebugPrint((1, "S3: first int10 call FAILED\n"));
  2908. }
  2909. if ((status == NO_ERROR) && (biosArguments.Eax & 0xff00) == 0) {
  2910. //
  2911. // The contiguous mode set succeeded.
  2912. //
  2913. ModeEntry->ModeInformation.ScreenStride =
  2914. ModeEntry->ScreenStrideContiguous;
  2915. } else {
  2916. //
  2917. // Try again with the 'Noncontiguous' mode:
  2918. //
  2919. biosArguments.Ebx = ModeEntry->Int10ModeNumberNoncontiguous;
  2920. biosArguments.Eax = 0x4f02;
  2921. status = VideoPortInt10(HwDeviceExtension, &biosArguments);
  2922. if (status != NO_ERROR)
  2923. {
  2924. VideoDebugPrint((1, "S3: second int10 call FAILED\n"));
  2925. }
  2926. //
  2927. // If the video port called succeeded, check the register return
  2928. // code. Some HP BIOSes always return failure even when the
  2929. // int 10 works fine, so we ignore its return code.
  2930. //
  2931. if ((status == NO_ERROR) &&
  2932. ((hwDeviceExtension->BoardID != S3_HP) &&
  2933. ((biosArguments.Eax & 0xff00) != 0))) {
  2934. status = ERROR_INVALID_PARAMETER;
  2935. }
  2936. }
  2937. if (FrequencyEntry->ScreenFrequency != 1) {
  2938. //
  2939. // Unlock the S3 registers.
  2940. //
  2941. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x4838);
  2942. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xA039);
  2943. //
  2944. // If the user has been running the Display Applet and we're
  2945. // reverting back to 'hardware default setting,' we have to
  2946. // restore the refresh registers to their original settings.
  2947. //
  2948. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x52);
  2949. VideoPortWritePortUchar(CRT_DATA_REG, OriginalRegPrimary);
  2950. VideoPortWritePortUchar(CRT_ADDRESS_REG,
  2951. hwDeviceExtension->FrequencySecondaryIndex);
  2952. VideoPortWritePortUchar(CRT_DATA_REG, OriginalRegSecondary);
  2953. }
  2954. }
  2955. if (status != NO_ERROR) {
  2956. VideoDebugPrint((1, "S3: Trying fixed mode-set\n"));
  2957. //
  2958. // A problem occured during the int10. Let's see if we can recover.
  2959. //
  2960. #ifndef S3_USE_FIXED_TABLES
  2961. //
  2962. // If we are only supposed to use int10, then this is total
  2963. // failure. Just leave.
  2964. //
  2965. break;
  2966. #endif
  2967. //
  2968. // Let see if we are using a fixed mode table number
  2969. //
  2970. if (!hwDeviceExtension->BiosPresent) {
  2971. FrequencyEntry = &hwDeviceExtension->FixedFrequencyTable[modeNumber];
  2972. } else {
  2973. PS3_VIDEO_FREQUENCIES oldFrequencyEntry = FrequencyEntry;
  2974. PS3_VIDEO_FREQUENCIES newFrequencyEntry;
  2975. PS3_VIDEO_FREQUENCIES bestFrequencyEntry;
  2976. //
  2977. // Okay, we constructed our original mode list assuming
  2978. // we could use Int 10, but we have just discovered the
  2979. // Int 10 didn't work -- probably because there was a
  2980. // problem with the BIOS emulator. To recover, we will now
  2981. // try to find the best mode in the Fixed Frequency table to
  2982. // match the requested mode.
  2983. //
  2984. FrequencyEntry = NULL;
  2985. bestFrequencyEntry = NULL;
  2986. for (newFrequencyEntry = &hwDeviceExtension->FixedFrequencyTable[0];
  2987. newFrequencyEntry->BitsPerPel != 0;
  2988. newFrequencyEntry++) {
  2989. //
  2990. // Check for a matching mode.
  2991. //
  2992. if ( (newFrequencyEntry->BitsPerPel ==
  2993. oldFrequencyEntry->BitsPerPel) &&
  2994. (newFrequencyEntry->ScreenWidth ==
  2995. oldFrequencyEntry->ScreenWidth) ) {
  2996. if (FrequencyEntry == NULL) {
  2997. //
  2998. // Remember the first mode that matched, ignoring
  2999. // the frequency.
  3000. //
  3001. FrequencyEntry = newFrequencyEntry;
  3002. }
  3003. if (newFrequencyEntry->ScreenFrequency <=
  3004. oldFrequencyEntry->ScreenFrequency) {
  3005. //
  3006. // Ideally, we would like to choose the frequency
  3007. // that is closest to, but less than or equal to,
  3008. // the requested frequency.
  3009. //
  3010. if ( (bestFrequencyEntry == NULL) ||
  3011. (bestFrequencyEntry->ScreenFrequency <
  3012. newFrequencyEntry->ScreenFrequency) ) {
  3013. bestFrequencyEntry = newFrequencyEntry;
  3014. }
  3015. }
  3016. }
  3017. }
  3018. //
  3019. // Use the preferred frequency setting, if there is one.
  3020. //
  3021. if (bestFrequencyEntry != NULL) {
  3022. FrequencyEntry = bestFrequencyEntry;
  3023. }
  3024. //
  3025. // If we have no valid mode, we must return failure
  3026. //
  3027. if (FrequencyEntry == NULL) {
  3028. VideoDebugPrint((1, "S3: no valid Fixed Frequency mode\n"));
  3029. status = ERROR_INVALID_PARAMETER;
  3030. break;
  3031. }
  3032. //
  3033. // Our new ModeEntry is the same as the old.
  3034. //
  3035. FrequencyEntry->ModeEntry = oldFrequencyEntry->ModeEntry;
  3036. FrequencyEntry->ModeValid = TRUE;
  3037. VideoDebugPrint((1, "S3: Selected Fixed Frequency mode from int 10:\n"));
  3038. VideoDebugPrint((1, " Bits Per Pel: %d\n", FrequencyEntry->BitsPerPel));
  3039. VideoDebugPrint((1, " Screen Width: %d\n", FrequencyEntry->ScreenWidth));
  3040. VideoDebugPrint((1, " Frequency: %d\n", FrequencyEntry->ScreenFrequency));
  3041. }
  3042. ModeEntry = FrequencyEntry->ModeEntry;
  3043. //
  3044. // NOTE:
  3045. // We have to set the ActiveFrequencyEntry since the SetHWMode
  3046. // function depends on this variable to set the CRTC registers.
  3047. // So lets set it here, and it will get reset to the same
  3048. // value after we set the mode.
  3049. //
  3050. hwDeviceExtension->ActiveFrequencyEntry = FrequencyEntry;
  3051. //
  3052. // If it failed, we may not be able to perform int10 due
  3053. // to BIOS emulation problems.
  3054. //
  3055. // Then just do a table mode-set. First we need to find the
  3056. // right mode table in the fixed Frequency tables.
  3057. //
  3058. //
  3059. // Select the Enhanced mode init depending upon the type of
  3060. // chip found.
  3061. if ( (hwDeviceExtension->BoardID == S3_NUMBER_NINE) &&
  3062. (ModeEntry->ModeInformation.VisScreenWidth == 1280) ) {
  3063. SetHWMode(hwDeviceExtension, S3_928_1280_Enhanced_Mode);
  3064. } else {
  3065. //
  3066. // Use defaults for all other boards
  3067. //
  3068. switch(hwDeviceExtension->ChipID) {
  3069. case S3_911:
  3070. SetHWMode(hwDeviceExtension, S3_911_Enhanced_Mode);
  3071. break;
  3072. case S3_801:
  3073. SetHWMode(hwDeviceExtension, S3_801_Enhanced_Mode);
  3074. break;
  3075. case S3_928:
  3076. SetHWMode(hwDeviceExtension, S3_928_Enhanced_Mode);
  3077. break;
  3078. case S3_864:
  3079. SetHWMode(hwDeviceExtension, S3_864_Enhanced_Mode);
  3080. Set864MemoryTiming(hwDeviceExtension);
  3081. break;
  3082. default:
  3083. VideoDebugPrint((1, "S3: Bad chip type for these boards"));
  3084. break;
  3085. }
  3086. }
  3087. }
  3088. //
  3089. // Call Int 10, function 0x4f06 to obtain the correct screen pitch
  3090. // of all S3's except the 911/924.
  3091. //
  3092. if ((hwDeviceExtension->ChipID != S3_911) &&
  3093. (hwDeviceExtension->BiosPresent)) {
  3094. VideoPortZeroMemory(&biosArguments,sizeof(VIDEO_X86_BIOS_ARGUMENTS));
  3095. biosArguments.Ebx = 0x0001;
  3096. biosArguments.Eax = 0x4f06;
  3097. status = VideoPortInt10(HwDeviceExtension, &biosArguments);
  3098. //
  3099. // Check to see if the Bios supported this function, and if so
  3100. // update the screen stride for this mode.
  3101. //
  3102. if ((status == NO_ERROR) && (biosArguments.Eax & 0xffff) == 0x004f) {
  3103. ModeEntry->ModeInformation.ScreenStride =
  3104. biosArguments.Ebx;
  3105. } else {
  3106. //
  3107. // We will use the default value in the mode table.
  3108. //
  3109. }
  3110. }
  3111. //
  3112. // Save the mode since we know the rest will work.
  3113. //
  3114. hwDeviceExtension->ActiveModeEntry = ModeEntry;
  3115. hwDeviceExtension->ActiveFrequencyEntry = FrequencyEntry;
  3116. //
  3117. // Record the fact that we are in an S3 mode, and
  3118. // that we need to be reset.
  3119. //
  3120. hwDeviceExtension->bNeedReset = TRUE;
  3121. //////////////////////////////////////////////////////////////////
  3122. // Update VIDEO_MODE_INFORMATION fields
  3123. //
  3124. // Now that we've set the mode, we now know the screen stride, and
  3125. // so can update some fields in the VIDEO_MODE_INFORMATION
  3126. // structure for this mode. The S3 display driver is expected to
  3127. // call IOCTL_VIDEO_QUERY_CURRENT_MODE to query these corrected
  3128. // values.
  3129. //
  3130. //
  3131. // Calculate the bitmap width.
  3132. // We currently assume the bitmap width is equivalent to the stride.
  3133. //
  3134. {
  3135. LONG x;
  3136. x = ModeEntry->ModeInformation.BitsPerPlane;
  3137. //
  3138. // you waste 16 bps even when you only use 15 for info.
  3139. //
  3140. if( x == 15 )
  3141. {
  3142. x = 16;
  3143. }
  3144. ModeEntry->ModeInformation.VideoMemoryBitmapWidth =
  3145. (ModeEntry->ModeInformation.ScreenStride * 8) / x;
  3146. }
  3147. //
  3148. // If we're in a mode that the BIOS doesn't really support, it may
  3149. // have reported back a bogus screen width.
  3150. //
  3151. if (ModeEntry->ModeInformation.VideoMemoryBitmapWidth <
  3152. ModeEntry->ModeInformation.VisScreenWidth) {
  3153. VideoDebugPrint((1, "S3: BIOS returned invalid screen width\n"));
  3154. status = ERROR_INVALID_PARAMETER;
  3155. break;
  3156. }
  3157. //
  3158. // Calculate the bitmap height.
  3159. //
  3160. ModeEntry->ModeInformation.VideoMemoryBitmapHeight =
  3161. hwDeviceExtension->AdapterMemorySize /
  3162. ModeEntry->ModeInformation.ScreenStride;
  3163. //
  3164. // The current position registers in the current S3 chips are
  3165. // limited to 12 bits of precision, with the range [0, 4095].
  3166. // Consequently, we must clamp the bitmap height so that we don't
  3167. // attempt to do any drawing beyond that range.
  3168. //
  3169. ModeEntry->ModeInformation.VideoMemoryBitmapHeight =
  3170. MIN(4096, ModeEntry->ModeInformation.VideoMemoryBitmapHeight);
  3171. //////////////////////////////////////////////////////////////////
  3172. // Unlock the S3 registers, we need to unlock the registers a second
  3173. // time since the interperter has them locked when it returns to us.
  3174. //
  3175. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x4838);
  3176. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xA039);
  3177. //////////////////////////////////////////////////////////////////
  3178. // Warm up the hardware for the new mode, and work around any
  3179. // BIOS bugs.
  3180. //
  3181. if ((hwDeviceExtension->ChipID == S3_801) &&
  3182. (hwDeviceExtension->AdapterMemorySize == 0x080000)) {
  3183. //
  3184. // On 801/805 chipsets with 512k of memory we must AND
  3185. // register 0x54 with 0x7.
  3186. //
  3187. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x54);
  3188. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3189. byte &= 0x07;
  3190. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3191. }
  3192. if (ModeEntry->ModeInformation.BitsPerPlane > 8) {
  3193. //
  3194. // Make sure 16-bit memory reads/writes are enabled.
  3195. //
  3196. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x31);
  3197. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3198. byte |= 0x04;
  3199. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3200. }
  3201. //
  3202. // Set the colours for the built-in S3 pointer.
  3203. //
  3204. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xff0e);
  3205. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x000f);
  3206. if (hwDeviceExtension->ChipID >= S3_864) {
  3207. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x45);
  3208. VideoPortReadPortUchar(CRT_DATA_REG);
  3209. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x4A);
  3210. VideoPortWritePortUchar(CRT_DATA_REG, 0xFF);
  3211. VideoPortWritePortUchar(CRT_DATA_REG, 0xFF);
  3212. VideoPortWritePortUchar(CRT_DATA_REG, 0xFF);
  3213. VideoPortWritePortUchar(CRT_DATA_REG, 0xFF);
  3214. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x45);
  3215. VideoPortReadPortUchar(CRT_DATA_REG);
  3216. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x4B);
  3217. VideoPortWritePortUchar(CRT_DATA_REG, 0x00);
  3218. VideoPortWritePortUchar(CRT_DATA_REG, 0x00);
  3219. VideoPortWritePortUchar(CRT_DATA_REG, 0x00);
  3220. VideoPortWritePortUchar(CRT_DATA_REG, 0x00);
  3221. }
  3222. if (hwDeviceExtension->ChipID > S3_911) {
  3223. //
  3224. // Set the address for the frame buffer window and set the window
  3225. // size.
  3226. //
  3227. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x59);
  3228. VideoPortWritePortUchar(CRT_DATA_REG,
  3229. (UCHAR) (hwDeviceExtension->PhysicalFrameAddress.LowPart >> 24));
  3230. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5A);
  3231. VideoPortWritePortUchar(CRT_DATA_REG,
  3232. (UCHAR) (hwDeviceExtension->PhysicalFrameAddress.LowPart >> 16));
  3233. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x58);
  3234. byte = VideoPortReadPortUchar(CRT_DATA_REG) & ~0x3;
  3235. switch (hwDeviceExtension->FrameLength)
  3236. {
  3237. case 0x400000:
  3238. case 0x800000:
  3239. byte |= 0x3;
  3240. break;
  3241. case 0x200000:
  3242. byte |= 0x2;
  3243. break;
  3244. case 0x100000:
  3245. byte |= 0x1;
  3246. break;
  3247. case 0x010000:
  3248. break;
  3249. default:
  3250. byte |= 0x3;
  3251. break;
  3252. }
  3253. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3254. }
  3255. if (hwDeviceExtension->Capabilities & CAPS_NEW_MMIO) {
  3256. //
  3257. // Enable 'new memory-mapped I/O':
  3258. //
  3259. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x53);
  3260. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3261. byte |= 0x18;
  3262. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3263. }
  3264. if ((ModeEntry->ModeInformation.DriverSpecificAttributeFlags &
  3265. CAPS_BT485_POINTER) &&
  3266. (hwDeviceExtension->ChipID == S3_928)) {
  3267. //
  3268. // Some of the Number Nine boards do not set the chip up correctly
  3269. // for an external cursor. We must OR in the bits, because if we
  3270. // don't the Metheus board will not initialize.
  3271. //
  3272. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x45);
  3273. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3274. byte |= 0x20;
  3275. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3276. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  3277. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3278. byte |= 0x20;
  3279. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3280. }
  3281. //
  3282. // Some BIOSes don't disable linear addressing by default, so
  3283. // make sure we do it here.
  3284. //
  3285. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x58);
  3286. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3287. byte &= ~0x10;
  3288. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3289. //
  3290. // Enable the Graphics engine.
  3291. //
  3292. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x40);
  3293. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3294. byte |= 0x01;
  3295. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3296. status = NO_ERROR;
  3297. break;
  3298. case IOCTL_VIDEO_SET_COLOR_REGISTERS:
  3299. VideoDebugPrint((2, "S3StartIO - SetColorRegs\n"));
  3300. clutBuffer = RequestPacket->InputBuffer;
  3301. status = S3SetColorLookup(HwDeviceExtension,
  3302. (PVIDEO_CLUT) RequestPacket->InputBuffer,
  3303. RequestPacket->InputBufferLength);
  3304. break;
  3305. case IOCTL_VIDEO_RESET_DEVICE:
  3306. VideoDebugPrint((2, "S3StartIO - RESET_DEVICE\n"));
  3307. //
  3308. // Prep the S3 card to return to a VGA mode
  3309. //
  3310. S3ResetHw(HwDeviceExtension, 0, 0);
  3311. VideoDebugPrint((2, "S3 RESET_DEVICE - About to do int10\n"));
  3312. //
  3313. // Do an Int10 to mode 3 will put the board to a known state.
  3314. //
  3315. VideoPortZeroMemory(&biosArguments, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
  3316. biosArguments.Eax = 0x0003;
  3317. VideoPortInt10(HwDeviceExtension,
  3318. &biosArguments);
  3319. VideoDebugPrint((2, "S3 RESET_DEVICE - Did int10\n"));
  3320. status = NO_ERROR;
  3321. break;
  3322. case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
  3323. VideoDebugPrint((2, "S3StartIO - ShareVideoMemory\n"));
  3324. if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION)) ||
  3325. (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
  3326. VideoDebugPrint((1, "IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INSUFFICIENT_BUFFER\n"));
  3327. status = ERROR_INSUFFICIENT_BUFFER;
  3328. break;
  3329. }
  3330. pShareMemory = RequestPacket->InputBuffer;
  3331. if ( (pShareMemory->ViewOffset > hwDeviceExtension->AdapterMemorySize) ||
  3332. ((pShareMemory->ViewOffset + pShareMemory->ViewSize) >
  3333. hwDeviceExtension->AdapterMemorySize) ) {
  3334. VideoDebugPrint((1, "IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INVALID_PARAMETER\n"));
  3335. status = ERROR_INVALID_PARAMETER;
  3336. break;
  3337. }
  3338. RequestPacket->StatusBlock->Information =
  3339. sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
  3340. //
  3341. // Beware: the input buffer and the output buffer are the same
  3342. // buffer, and therefore data should not be copied from one to the
  3343. // other
  3344. //
  3345. virtualAddress = pShareMemory->ProcessHandle;
  3346. sharedViewSize = pShareMemory->ViewSize;
  3347. inIoSpace = hwDeviceExtension->PhysicalFrameIoSpace;
  3348. //
  3349. // NOTE: we are ignoring ViewOffset
  3350. //
  3351. shareAddress.QuadPart =
  3352. hwDeviceExtension->PhysicalFrameAddress.QuadPart;
  3353. if (hwDeviceExtension->Capabilities & CAPS_NEW_MMIO) {
  3354. //
  3355. // With 'new memory-mapped I/O', the frame buffer is always
  3356. // mapped in linearly.
  3357. //
  3358. //
  3359. // Performance:
  3360. //
  3361. // Enable USWC on the P6 processor.
  3362. // We only do it for the frame buffer - memory mapped registers can
  3363. // not be mapped USWC because write combining the registers would
  3364. // cause very bad things to happen !
  3365. //
  3366. inIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  3367. //
  3368. // Unlike the MAP_MEMORY IOCTL, in this case we can not map extra
  3369. // address space since the application could actually use the
  3370. // pointer we return to it to touch locations in the address space
  3371. // that do not have actual video memory in them.
  3372. //
  3373. // An app doing this would cause the machine to crash.
  3374. //
  3375. // However, because the caching policy for USWC in the P6 is on
  3376. // *physical* addresses, this memory mapping will "piggy back" on
  3377. // the normal frame buffer mapping, and therefore also benefit
  3378. // from USWC ! Cool side-effect !!!
  3379. //
  3380. status = VideoPortMapMemory(hwDeviceExtension,
  3381. shareAddress,
  3382. &sharedViewSize,
  3383. &inIoSpace,
  3384. &virtualAddress);
  3385. pShareMemoryInformation = RequestPacket->OutputBuffer;
  3386. pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
  3387. pShareMemoryInformation->VirtualAddress = virtualAddress;
  3388. pShareMemoryInformation->SharedViewSize = sharedViewSize;
  3389. } else {
  3390. status = ERROR_INVALID_PARAMETER;
  3391. }
  3392. break;
  3393. case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
  3394. VideoDebugPrint((2, "S3StartIO - UnshareVideoMemory\n"));
  3395. if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY)) {
  3396. status = ERROR_INSUFFICIENT_BUFFER;
  3397. break;
  3398. }
  3399. pShareMemory = RequestPacket->InputBuffer;
  3400. status = VideoPortUnmapMemory(hwDeviceExtension,
  3401. pShareMemory->RequestedVirtualAddress,
  3402. pShareMemory->ProcessHandle);
  3403. break;
  3404. case IOCTL_VIDEO_S3_QUERY_STREAMS_PARAMETERS:
  3405. VideoDebugPrint((2, "S3StartIO - QueryStreamsParameters\n"));
  3406. //
  3407. // This is a private, non-standard IOCTL so that the display driver
  3408. // can query the appropriate minimum stretch ratio and FIFO value
  3409. // for using the streams overlay processor in a particular mode.
  3410. //
  3411. if ((RequestPacket->InputBufferLength < sizeof(VIDEO_QUERY_STREAMS_MODE)) ||
  3412. (RequestPacket->OutputBufferLength < sizeof(VIDEO_QUERY_STREAMS_PARAMETERS))) {
  3413. status = ERROR_INSUFFICIENT_BUFFER;
  3414. break;
  3415. }
  3416. status = QueryStreamsParameters(hwDeviceExtension,
  3417. RequestPacket->InputBuffer,
  3418. RequestPacket->OutputBuffer);
  3419. if (status == NO_ERROR) {
  3420. RequestPacket->StatusBlock->Information =
  3421. sizeof(VIDEO_QUERY_STREAMS_PARAMETERS);
  3422. }
  3423. break;
  3424. case IOCTL_PRIVATE_GET_FUNCTIONAL_UNIT:
  3425. VideoDebugPrint((2, "S3StartIO - GetFunctionalUnit\n"));
  3426. if (RequestPacket->OutputBufferLength <
  3427. (RequestPacket->StatusBlock->Information =
  3428. sizeof(FUNCTIONAL_UNIT_INFO)) ) {
  3429. status = ERROR_INSUFFICIENT_BUFFER;
  3430. } else {
  3431. ((PFUNCTIONAL_UNIT_INFO)RequestPacket->OutputBuffer)->FunctionalUnitID =
  3432. hwDeviceExtension->FunctionalUnitID;
  3433. ((PFUNCTIONAL_UNIT_INFO)RequestPacket->OutputBuffer)->Reserved = 0;
  3434. status = NO_ERROR;
  3435. }
  3436. break;
  3437. //
  3438. // if we get here, an invalid IoControlCode was specified.
  3439. //
  3440. default:
  3441. VideoDebugPrint((1, "Fell through S3 startIO routine - invalid command\n"));
  3442. status = ERROR_INVALID_FUNCTION;
  3443. break;
  3444. }
  3445. VideoDebugPrint((2, "Leaving S3 startIO routine\n"));
  3446. RequestPacket->StatusBlock->Status = status;
  3447. return TRUE;
  3448. } // end S3StartIO()
  3449. VP_STATUS
  3450. S3SetColorLookup(
  3451. PHW_DEVICE_EXTENSION HwDeviceExtension,
  3452. PVIDEO_CLUT ClutBuffer,
  3453. ULONG ClutBufferSize
  3454. )
  3455. /*++
  3456. Routine Description:
  3457. This routine sets a specified portion of the color lookup table settings.
  3458. Arguments:
  3459. HwDeviceExtension - Pointer to the miniport driver's device extension.
  3460. ClutBufferSize - Length of the input buffer supplied by the user.
  3461. ClutBuffer - Pointer to the structure containing the color lookup table.
  3462. Return Value:
  3463. None.
  3464. --*/
  3465. {
  3466. USHORT i;
  3467. //
  3468. // Check if the size of the data in the input buffer is large enough.
  3469. //
  3470. if ( (ClutBufferSize < sizeof(VIDEO_CLUT) - sizeof(ULONG)) ||
  3471. (ClutBufferSize < sizeof(VIDEO_CLUT) +
  3472. (sizeof(ULONG) * (ClutBuffer->NumEntries - 1)) ) ) {
  3473. return ERROR_INSUFFICIENT_BUFFER;
  3474. }
  3475. //
  3476. // Check to see if the parameters are valid.
  3477. //
  3478. if ( (ClutBuffer->NumEntries == 0) ||
  3479. (ClutBuffer->FirstEntry > VIDEO_MAX_COLOR_REGISTER) ||
  3480. (ClutBuffer->FirstEntry + ClutBuffer->NumEntries >
  3481. VIDEO_MAX_COLOR_REGISTER + 1) ) {
  3482. return ERROR_INVALID_PARAMETER;
  3483. }
  3484. if (HwDeviceExtension->Capabilities & CAPS_WAIT_ON_PALETTE) {
  3485. //
  3486. // On some DACs, the hardware pointer 'sparkles' unless we first
  3487. // wait for vertical retrace.
  3488. //
  3489. while (VideoPortReadPortUchar(SYSTEM_CONTROL_REG) & 0x08)
  3490. ;
  3491. while (!(VideoPortReadPortUchar(SYSTEM_CONTROL_REG) & 0x08))
  3492. ;
  3493. //
  3494. // Then pause a little more. 0x400 is the lowest value that made
  3495. // any remaining sparkle disappear on my PCI P90.
  3496. //
  3497. // Unfortunately, I have discovered that this is not a complete
  3498. // solution -- there is still sparkle if the mouse is positioned
  3499. // near the top of the screen. A more complete solution would
  3500. // probably be to turn the mouse off entirely if it's in that
  3501. // range.
  3502. //
  3503. for (i = 0x400; i != 0; i--) {
  3504. VideoPortReadPortUchar(SYSTEM_CONTROL_REG);
  3505. }
  3506. }
  3507. //
  3508. // Set CLUT registers directly on the hardware
  3509. //
  3510. for (i = 0; i < ClutBuffer->NumEntries; i++) {
  3511. VideoPortWritePortUchar(DAC_ADDRESS_WRITE_PORT, (UCHAR) (ClutBuffer->FirstEntry + i));
  3512. VideoPortWritePortUchar(DAC_DATA_REG_PORT, (UCHAR) (ClutBuffer->LookupTable[i].RgbArray.Red));
  3513. VideoPortWritePortUchar(DAC_DATA_REG_PORT, (UCHAR) (ClutBuffer->LookupTable[i].RgbArray.Green));
  3514. VideoPortWritePortUchar(DAC_DATA_REG_PORT, (UCHAR) (ClutBuffer->LookupTable[i].RgbArray.Blue));
  3515. }
  3516. return NO_ERROR;
  3517. } // end S3SetColorLookup()
  3518. VOID
  3519. SetHWMode(
  3520. PHW_DEVICE_EXTENSION HwDeviceExtension,
  3521. PUSHORT pusCmdStream
  3522. )
  3523. /*++
  3524. Routine Description:
  3525. Interprets the appropriate command array to set up VGA registers for the
  3526. requested mode. Typically used to set the VGA into a particular mode by
  3527. programming all of the registers
  3528. Arguments:
  3529. HwDeviceExtension - Pointer to the miniport driver's device extension.
  3530. pusCmdStream - pointer to a command stream to execute.
  3531. Return Value:
  3532. The status of the operation (can only fail on a bad command); TRUE for
  3533. success, FALSE for failure.
  3534. --*/
  3535. {
  3536. ULONG ulCmd;
  3537. ULONG ulPort;
  3538. UCHAR jValue;
  3539. USHORT usValue;
  3540. ULONG culCount;
  3541. ULONG ulIndex,
  3542. Microseconds;
  3543. ULONG mappedAddressIndex = 2; // fool Prefix
  3544. ULONG mappedAddressOffset = 0x3c0; // fool Prefix
  3545. //
  3546. // If there is no command string, just return
  3547. //
  3548. if (!pusCmdStream) {
  3549. return;
  3550. }
  3551. while ((ulCmd = *pusCmdStream++) != EOD) {
  3552. //
  3553. // Determine major command type
  3554. //
  3555. switch (ulCmd & 0xF0) {
  3556. case RESET_CR5C:
  3557. if (HwDeviceExtension->BiosPresent == FALSE)
  3558. {
  3559. UCHAR value, oldvalue;
  3560. //
  3561. // Reset the upper four bits of the General Out Port Reg
  3562. // with the value it had after the POST.
  3563. //
  3564. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5c);
  3565. value = VideoPortReadPortUchar(CRT_DATA_REG);
  3566. oldvalue = value;
  3567. value &= 0x0f;
  3568. value |= HwDeviceExtension->CR5C;
  3569. VideoPortWritePortUchar(CRT_DATA_REG, value);
  3570. VideoDebugPrint((2, "S3: CRC5 was 0x%x and we "
  3571. "have set it to 0x%x\n",
  3572. oldvalue, value));
  3573. }
  3574. break;
  3575. case SELECTACCESSRANGE:
  3576. //
  3577. // Determine which address range to use for commands that follow
  3578. //
  3579. switch (ulCmd & 0x0F) {
  3580. case VARIOUSVGA:
  3581. //
  3582. // Used for registers in the range 0x3c0 - 0x3cf
  3583. //
  3584. mappedAddressIndex = 2;
  3585. mappedAddressOffset = 0x3c0;
  3586. break;
  3587. case SYSTEMCONTROL:
  3588. //
  3589. // Used for registers in the range 0x3d4 - 0x3df
  3590. //
  3591. mappedAddressIndex = 3;
  3592. mappedAddressOffset = 0x3d4;
  3593. break;
  3594. case ADVANCEDFUNCTIONCONTROL:
  3595. //
  3596. // Used for registers in the range 0x4ae8-0x4ae9
  3597. //
  3598. mappedAddressIndex = 5;
  3599. mappedAddressOffset = 0x4ae8;
  3600. break;
  3601. }
  3602. break;
  3603. case OWM:
  3604. ulPort = *pusCmdStream++;
  3605. culCount = *pusCmdStream++;
  3606. while (culCount--) {
  3607. usValue = *pusCmdStream++;
  3608. VideoPortWritePortUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort),
  3609. usValue);
  3610. }
  3611. break;
  3612. // Basic input/output command
  3613. case INOUT:
  3614. // Determine type of inout instruction
  3615. if (!(ulCmd & IO)) {
  3616. // Out instruction
  3617. // Single or multiple outs?
  3618. if (!(ulCmd & MULTI)) {
  3619. // Single out
  3620. // Byte or word out?
  3621. if (!(ulCmd & BW)) {
  3622. // Single byte out
  3623. ulPort = *pusCmdStream++;
  3624. jValue = (UCHAR) *pusCmdStream++;
  3625. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3626. jValue);
  3627. } else {
  3628. // Single word out
  3629. ulPort = *pusCmdStream++;
  3630. usValue = *pusCmdStream++;
  3631. VideoPortWritePortUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort),
  3632. usValue);
  3633. }
  3634. } else {
  3635. // Output a string of values
  3636. // Byte or word outs?
  3637. if (!(ulCmd & BW)) {
  3638. // String byte outs. Do in a loop; can't use
  3639. // VideoPortWritePortBufferUchar because the data
  3640. // is in USHORT form
  3641. ulPort = *pusCmdStream++;
  3642. culCount = *pusCmdStream++;
  3643. while (culCount--) {
  3644. jValue = (UCHAR) *pusCmdStream++;
  3645. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3646. jValue);
  3647. }
  3648. } else {
  3649. // String word outs
  3650. ulPort = *pusCmdStream++;
  3651. culCount = *pusCmdStream++;
  3652. VideoPortWritePortBufferUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort),
  3653. pusCmdStream,
  3654. culCount);
  3655. pusCmdStream += culCount;
  3656. }
  3657. }
  3658. } else {
  3659. // In instruction
  3660. // Currently, string in instructions aren't supported; all
  3661. // in instructions are handled as single-byte ins
  3662. // Byte or word in?
  3663. if (!(ulCmd & BW)) {
  3664. // Single byte in
  3665. ulPort = *pusCmdStream++;
  3666. jValue = VideoPortReadPortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort);
  3667. } else {
  3668. // Single word in
  3669. ulPort = *pusCmdStream++;
  3670. usValue = VideoPortReadPortUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort));
  3671. }
  3672. }
  3673. break;
  3674. // Higher-level input/output commands
  3675. case METAOUT:
  3676. // Determine type of metaout command, based on minor command field
  3677. switch (ulCmd & 0x0F) {
  3678. // Indexed outs
  3679. case INDXOUT:
  3680. ulPort = *pusCmdStream++;
  3681. culCount = *pusCmdStream++;
  3682. ulIndex = *pusCmdStream++;
  3683. while (culCount--) {
  3684. usValue = (USHORT) (ulIndex +
  3685. (((ULONG)(*pusCmdStream++)) << 8));
  3686. VideoPortWritePortUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort),
  3687. usValue);
  3688. ulIndex++;
  3689. }
  3690. break;
  3691. // Masked out (read, AND, XOR, write)
  3692. case MASKOUT:
  3693. ulPort = *pusCmdStream++;
  3694. jValue = VideoPortReadPortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort);
  3695. jValue &= *pusCmdStream++;
  3696. jValue ^= *pusCmdStream++;
  3697. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3698. jValue);
  3699. break;
  3700. // Attribute Controller out
  3701. case ATCOUT:
  3702. ulPort = *pusCmdStream++;
  3703. culCount = *pusCmdStream++;
  3704. ulIndex = *pusCmdStream++;
  3705. while (culCount--) {
  3706. // Write Attribute Controller index
  3707. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3708. (UCHAR)ulIndex);
  3709. // Write Attribute Controller data
  3710. jValue = (UCHAR) *pusCmdStream++;
  3711. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3712. jValue);
  3713. ulIndex++;
  3714. }
  3715. break;
  3716. case DELAY:
  3717. Microseconds = (ULONG) *pusCmdStream++;
  3718. VideoPortStallExecution(Microseconds);
  3719. break;
  3720. case VBLANK:
  3721. Wait_VSync(HwDeviceExtension);
  3722. break;
  3723. //
  3724. // This function in setmode is pageable !!!
  3725. // it is only used to set high res modes.
  3726. //
  3727. case SETCLK:
  3728. Set_Oem_Clock(HwDeviceExtension);
  3729. break;
  3730. case SETCRTC:
  3731. //
  3732. // NOTE:
  3733. // beware: recursive call ...
  3734. //
  3735. SetHWMode(HwDeviceExtension,
  3736. HwDeviceExtension->ActiveFrequencyEntry->
  3737. Fixed.CRTCTable[HwDeviceExtension->ChipID]);
  3738. break;
  3739. // None of the above; error
  3740. default:
  3741. return;
  3742. }
  3743. break;
  3744. // NOP
  3745. case NCMD:
  3746. break;
  3747. // Unknown command; error
  3748. default:
  3749. return;
  3750. }
  3751. }
  3752. return;
  3753. } // end SetHWMode()
  3754. LONG
  3755. CompareRom(
  3756. PUCHAR Rom,
  3757. PUCHAR String
  3758. )
  3759. /*++
  3760. Routine Description:
  3761. Compares a string to that in the ROM. Returns -1 if Rom < String, 0
  3762. if Rom == String, 1 if Rom > String.
  3763. Arguments:
  3764. Rom - Rom pointer.
  3765. String - String pointer.
  3766. Return Value:
  3767. None
  3768. --*/
  3769. {
  3770. UCHAR jString;
  3771. UCHAR jRom;
  3772. while (*String) {
  3773. jString = *String;
  3774. jRom = VideoPortReadRegisterUchar(Rom);
  3775. if (jRom != jString) {
  3776. return(jRom < jString ? -1 : 1);
  3777. }
  3778. String++;
  3779. Rom++;
  3780. }
  3781. return(0);
  3782. }
  3783. VOID
  3784. ZeroMemAndDac(
  3785. PHW_DEVICE_EXTENSION HwDeviceExtension
  3786. )
  3787. /*++
  3788. Routine Description:
  3789. Initialize the DAC to 0 (black).
  3790. Arguments:
  3791. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  3792. Return Value:
  3793. None
  3794. --*/
  3795. {
  3796. ULONG i;
  3797. //
  3798. // Turn off the screen at the DAC.
  3799. //
  3800. VideoPortWritePortUchar(DAC_PIXEL_MASK_REG, 0x0);
  3801. for (i = 0; i < 256; i++) {
  3802. VideoPortWritePortUchar(DAC_ADDRESS_WRITE_PORT, (UCHAR)i);
  3803. VideoPortWritePortUchar(DAC_DATA_REG_PORT, 0x0);
  3804. VideoPortWritePortUchar(DAC_DATA_REG_PORT, 0x0);
  3805. VideoPortWritePortUchar(DAC_DATA_REG_PORT, 0x0);
  3806. }
  3807. //
  3808. // Zero the memory.
  3809. //
  3810. //
  3811. // The zeroing of video memory should be implemented at a later time to
  3812. // ensure that no information remains in video memory at shutdown, or
  3813. // while swtiching to fullscren mode (for security reasons).
  3814. //
  3815. //
  3816. // Turn on the screen at the DAC
  3817. //
  3818. VideoPortWritePortUchar(DAC_PIXEL_MASK_REG, 0x0ff);
  3819. return;
  3820. }
  3821. VP_STATUS
  3822. Set_Oem_Clock(
  3823. PHW_DEVICE_EXTENSION HwDeviceExtension
  3824. )
  3825. /*++
  3826. Routine Description:
  3827. Set the clock chip on each of the supported cards.
  3828. Arguments:
  3829. HwDeviceExtension - Pointer to the miniport driver's device extension.
  3830. Return Value:
  3831. Always TRUE
  3832. --*/
  3833. {
  3834. ULONG ul;
  3835. ULONG screen_width;
  3836. UCHAR cr5C;
  3837. ULONG clock_numbers;
  3838. switch(HwDeviceExtension->BoardID) {
  3839. case S3_NUMBER_NINE:
  3840. VideoPortStallExecution(1000);
  3841. // Jerry said to make the M clock not multiple of the P clock
  3842. // on the 3 meg (level 12) board. This solves the shimmy
  3843. // problem.
  3844. if (HwDeviceExtension->AdapterMemorySize == 0x00300000) {
  3845. ul = 49000000;
  3846. clock_numbers = calc_clock(ul, 3);
  3847. set_clock(HwDeviceExtension, clock_numbers);
  3848. VideoPortStallExecution(3000);
  3849. }
  3850. ul = HwDeviceExtension->ActiveFrequencyEntry->Fixed.Clock;
  3851. clock_numbers = calc_clock(ul, 2);
  3852. set_clock(HwDeviceExtension, clock_numbers);
  3853. VideoPortStallExecution(3000);
  3854. break;
  3855. case S3_IBM_PS2:
  3856. // Read the current screen frequency and width
  3857. ul = HwDeviceExtension->ActiveFrequencyEntry->ScreenFrequency;
  3858. screen_width = HwDeviceExtension->ActiveFrequencyEntry->ScreenWidth;
  3859. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3860. cr5C = VideoPortReadPortUchar( CRT_DATA_REG );
  3861. cr5C &= 0xCF;
  3862. switch (screen_width) {
  3863. case 640:
  3864. if (ul == 60) {
  3865. cr5C |= 0x00;
  3866. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3867. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3868. } else { // 72Hz
  3869. cr5C |= 0x20;
  3870. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3871. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3872. } /* endif */
  3873. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3874. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x00);
  3875. VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)0xEF);
  3876. break;
  3877. case 800:
  3878. if (ul == 60) {
  3879. cr5C |= 0x00;
  3880. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3881. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3882. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3883. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x05);
  3884. } else { // 72Hz
  3885. cr5C |= 0x10;
  3886. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3887. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3888. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3889. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x02);
  3890. } /* endif */
  3891. VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)0x2F);
  3892. break;
  3893. case 1024:
  3894. if (ul == 60) {
  3895. cr5C |= 0x00;
  3896. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3897. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3898. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3899. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x05);
  3900. VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)0xEF);
  3901. } else { // 72Hz
  3902. cr5C |= 0x20;
  3903. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3904. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3905. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3906. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x05);
  3907. VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)0x2F);
  3908. } /* endif */
  3909. break;
  3910. default:
  3911. break;
  3912. } /* endswitch */
  3913. break;
  3914. //
  3915. // Generic S3 board.
  3916. //
  3917. case S3_GENERIC:
  3918. default:
  3919. //
  3920. // If the board has an SDAC then assume it also has an 864 (for now)
  3921. // this could be made better later by checking ChipID too, it appears
  3922. // that the display driver will need to be made 864 specific to get
  3923. // the best possible performance and this one may need to be specific
  3924. // before this is all done so I am not making it bulletproof yet
  3925. //
  3926. if( HwDeviceExtension->DacID == S3_SDAC ) {
  3927. InitializeSDAC( HwDeviceExtension );
  3928. } else {
  3929. ul = HwDeviceExtension->ActiveFrequencyEntry->Fixed.Clock;
  3930. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3931. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) ul);
  3932. }
  3933. break;
  3934. }
  3935. return TRUE;
  3936. }
  3937. VP_STATUS
  3938. Wait_VSync(
  3939. PHW_DEVICE_EXTENSION HwDeviceExtension
  3940. )
  3941. /*++
  3942. Routine Description:
  3943. Wait for the vertical blanking interval on the chip
  3944. Arguments:
  3945. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  3946. Return Value:
  3947. Always TRUE
  3948. --*/
  3949. {
  3950. ULONG i;
  3951. UCHAR byte;
  3952. // It's real possible that this routine will get called
  3953. // when the 911 is in a zombie state, meaning there is no
  3954. // vertical sync being generated. This is why we have some long
  3955. // time out loops here.
  3956. // First wait for getting into vertical blanking.
  3957. for (i = 0; i < 0x100000; i++) {
  3958. byte = VideoPortReadPortUchar(SYSTEM_CONTROL_REG);
  3959. if (byte & 0x08)
  3960. break;
  3961. }
  3962. //
  3963. // We are either in a vertical blaning interval or we have timmed out.
  3964. // Wait for the Vertical display interval.
  3965. // This is done to make sure we exit this routine at the beginning
  3966. // of a vertical blanking interval, and not in the middle or near
  3967. // the end of one.
  3968. //
  3969. for (i = 0; i < 0x100000; i++) {
  3970. byte = VideoPortReadPortUchar(SYSTEM_CONTROL_REG);
  3971. if (!(byte & 0x08))
  3972. break;
  3973. }
  3974. //
  3975. // Now wait to get into the vertical blank interval again.
  3976. //
  3977. for (i = 0; i < 0x100000; i++) {
  3978. byte = VideoPortReadPortUchar(SYSTEM_CONTROL_REG);
  3979. if (byte & 0x08)
  3980. break;
  3981. }
  3982. return (TRUE);
  3983. }
  3984. BOOLEAN
  3985. Set864MemoryTiming(
  3986. PHW_DEVICE_EXTENSION HwDeviceExtension
  3987. )
  3988. /*++
  3989. Routine Description:
  3990. Sets L, M and N timing parameters, also sets and enables the
  3991. Start Display FIFO register
  3992. Arguments:
  3993. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  3994. Return Value:
  3995. TRUE if success, FALSE if failure
  3996. --*/
  3997. {
  3998. ULONG MIndex, ColorDepth, ScreenWidth, failure = 0;
  3999. USHORT data16;
  4000. UCHAR data8, old38, old39;
  4001. //
  4002. // unlock registers
  4003. //
  4004. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x38);
  4005. old38 = VideoPortReadPortUchar( CRT_DATA_REG);
  4006. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x39);
  4007. old39 = VideoPortReadPortUchar( CRT_DATA_REG);
  4008. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x4838);
  4009. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xA039);
  4010. //
  4011. // make sure this is an 864
  4012. //
  4013. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x30);
  4014. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4015. if ((data8 & 0xf0) != 0xc0)
  4016. failure = 1;
  4017. //
  4018. // make sure there is an entry in the M parameter table for this mode
  4019. //
  4020. MIndex = (HwDeviceExtension->AdapterMemorySize < 0x200000) ? 0 : 12;
  4021. switch (HwDeviceExtension->ActiveFrequencyEntry->ScreenWidth) {
  4022. case 640:
  4023. MIndex += 0;
  4024. break;
  4025. case 800:
  4026. MIndex += 4;
  4027. break;
  4028. case 1024:
  4029. MIndex += 8;
  4030. break;
  4031. default:
  4032. failure = 1;
  4033. break;
  4034. }
  4035. switch (HwDeviceExtension->ActiveFrequencyEntry->BitsPerPel) {
  4036. case 8:
  4037. MIndex += 0;
  4038. break;
  4039. case 16:
  4040. MIndex += 2;
  4041. break;
  4042. default:
  4043. failure = 1;
  4044. break;
  4045. }
  4046. switch (HwDeviceExtension->ActiveFrequencyEntry->ScreenFrequency) {
  4047. case 60:
  4048. MIndex += 0;
  4049. break;
  4050. case 72:
  4051. MIndex += 1;
  4052. break;
  4053. default:
  4054. failure = 1;
  4055. break;
  4056. }
  4057. if (failure) {
  4058. // reset lock registers to previous state
  4059. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x38);
  4060. VideoPortWritePortUchar(CRT_DATA_REG, old38);
  4061. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x39);
  4062. VideoPortWritePortUchar(CRT_DATA_REG, old39);
  4063. return (FALSE);
  4064. }
  4065. //
  4066. // set and enable L parameter, 1 Mb frame buffer configurations are
  4067. // restricted to a 32 bit data path and therefore make twice as many
  4068. // transfers
  4069. //
  4070. ScreenWidth = HwDeviceExtension->ActiveFrequencyEntry->ScreenWidth;
  4071. ColorDepth = HwDeviceExtension->ActiveFrequencyEntry->BitsPerPel;
  4072. if (HwDeviceExtension->AdapterMemorySize < 0x200000)
  4073. data16 = (USHORT) ((ScreenWidth * (ColorDepth / 8)) / 4);
  4074. else
  4075. data16 = (USHORT) ((ScreenWidth * (ColorDepth / 8)) / 8);
  4076. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x62);
  4077. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) (data16 & 0xff));
  4078. data16 = (data16 >> 8) & 0x07;
  4079. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x61);
  4080. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) ((data16 & 0x07) | 0x80));
  4081. //
  4082. // set Start Display FIFO register
  4083. //
  4084. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5d);
  4085. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4086. data16 = data8 & 0x01;
  4087. data16 <<= 8;
  4088. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x00);
  4089. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4090. data16 |= data8;
  4091. data16 -= 5; // typical CR3B is CR0 - 5 (with extension bits)
  4092. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x3b);
  4093. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) (data16 & 0xff));
  4094. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5d);
  4095. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4096. data8 &= 0xbf;
  4097. data8 = data8 | (UCHAR) ((data16 & 0x100) >> 2);
  4098. VideoPortWritePortUchar(CRT_DATA_REG, data8);
  4099. //
  4100. // enable Start Display FIFO register
  4101. //
  4102. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x34);
  4103. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4104. data8 |= 0x10;
  4105. VideoPortWritePortUchar(CRT_DATA_REG, data8);
  4106. //
  4107. // set M parameter
  4108. //
  4109. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x54);
  4110. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) MParameterTable[MIndex]);
  4111. //
  4112. // set N parameter
  4113. //
  4114. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x60);
  4115. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) 0xff);
  4116. //
  4117. // restore lock registers to previous state
  4118. //
  4119. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x38);
  4120. VideoPortWritePortUchar(CRT_DATA_REG, old38);
  4121. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x39);
  4122. VideoPortWritePortUchar(CRT_DATA_REG, old39);
  4123. return (TRUE);
  4124. }
  4125. VP_STATUS
  4126. QueryStreamsParameters(
  4127. PHW_DEVICE_EXTENSION HwDeviceExtension,
  4128. VIDEO_QUERY_STREAMS_MODE *pStreamsMode,
  4129. VIDEO_QUERY_STREAMS_PARAMETERS *pStreamsParameters
  4130. )
  4131. /*++
  4132. Routine Description:
  4133. Queries various attributes of the card for later determine streams
  4134. parameters for minimum horizontal stretch and FIFO control
  4135. Arguments:
  4136. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  4137. RefreshRate - Supplies the exact refresh rate (a default rate of '1' will
  4138. not do).
  4139. pWidthRatio - Returns the corresponding minimum horizontal stretch factor,
  4140. expressed as a multiple of 1000.
  4141. pFifoValue - Returns the corresponding FIFO setting.
  4142. Return Value:
  4143. TRUE if success, FALSE if failure
  4144. --*/
  4145. {
  4146. ULONG BitsPerPel;
  4147. ULONG ScreenWidth;
  4148. ULONG RefreshRate;
  4149. UCHAR MemoryFlags;
  4150. ULONG n;
  4151. ULONG m;
  4152. ULONG r;
  4153. ULONG mclock;
  4154. ULONG MemorySpeed;
  4155. K2TABLE* pEntry;
  4156. ULONG MatchRefreshRate;
  4157. ULONG MatchMemorySpeed;
  4158. //
  4159. // Copy the input parameters and round 15 up to 16.
  4160. //
  4161. BitsPerPel = (pStreamsMode->BitsPerPel + 1) & ~7;
  4162. ScreenWidth = pStreamsMode->ScreenWidth;
  4163. RefreshRate = pStreamsMode->RefreshRate;
  4164. //
  4165. // Determine the memory type and memory size.
  4166. //
  4167. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x36);
  4168. MemoryFlags = (VideoPortReadPortUchar(CRT_DATA_REG) & 0x0c) >> 2;
  4169. if (HwDeviceExtension->AdapterMemorySize != 0x100000) {
  4170. MemoryFlags |= MEM_2MB;
  4171. }
  4172. //
  4173. // Unlock sequencer registers.
  4174. //
  4175. VideoPortWritePortUshort(SEQ_ADDRESS_REG, 0x0608);
  4176. //
  4177. // Get memory speed, using some inexplicable code from S3.
  4178. //
  4179. VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x10);
  4180. n = VideoPortReadPortUchar(SEQ_DATA_REG);
  4181. VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x11);
  4182. m = VideoPortReadPortUchar(SEQ_DATA_REG) & 0x7f;
  4183. MemorySpeed = n | (m << 8);
  4184. switch (MemorySpeed) {
  4185. case 0x1A40: // Known power-on default value
  4186. case 0x2841: // 50MHz
  4187. MemorySpeed = 50;
  4188. break;
  4189. case 0x4142: // 60MHz
  4190. MemorySpeed = 60;
  4191. break;
  4192. case 0x3643: // 40MHz
  4193. MemorySpeed = 40;
  4194. break;
  4195. default: // All others:
  4196. r = (n >> 5) & 0x03;
  4197. if (r == 0)
  4198. r = 1;
  4199. else
  4200. r = 2 << (r-1);
  4201. n = n & 0x1f;
  4202. mclock = ((m + 2) * 14318L) / (((n + 2) * r) * 100L);
  4203. MemorySpeed = mclock / 10;
  4204. if ((mclock % 10) >= 5)
  4205. MemorySpeed++;
  4206. if (MemorySpeed < 40)
  4207. MemorySpeed = 40;
  4208. break;
  4209. }
  4210. pEntry = &K2WidthRatio[0];
  4211. MatchRefreshRate = 0;
  4212. MatchMemorySpeed = 0;
  4213. while (pEntry->ScreenWidth != 0) {
  4214. //
  4215. // First find an exact match based on resolution, bits-per-pel,
  4216. // memory type and size.
  4217. //
  4218. if ((pEntry->ScreenWidth == ScreenWidth) &&
  4219. (pEntry->BitsPerPel == BitsPerPel) &&
  4220. (pEntry->MemoryFlags == MemoryFlags)) {
  4221. //
  4222. // Now find the entry with the refresh rate and memory speed the
  4223. // closest to, but not more than, our refresh rate and memory
  4224. // speed.
  4225. //
  4226. if ((pEntry->RefreshRate <= RefreshRate) &&
  4227. (pEntry->RefreshRate >= MatchRefreshRate) &&
  4228. (pEntry->MemorySpeed <= MemorySpeed) &&
  4229. (pEntry->MemorySpeed >= MatchMemorySpeed)) {
  4230. MatchRefreshRate = pEntry->RefreshRate;
  4231. MatchMemorySpeed = pEntry->MemorySpeed;
  4232. pStreamsParameters->MinOverlayStretch = pEntry->Value;
  4233. }
  4234. }
  4235. pEntry++;
  4236. }
  4237. if (MatchRefreshRate == 0) {
  4238. return ERROR_INVALID_PARAMETER;
  4239. }
  4240. pEntry = &K2FifoValue[0];
  4241. MatchRefreshRate = 0;
  4242. MatchMemorySpeed = 0;
  4243. while (pEntry->ScreenWidth != 0) {
  4244. //
  4245. // First find an exact match based on resolution, bits-per-pel,
  4246. // memory type and size.
  4247. //
  4248. if ((pEntry->ScreenWidth == ScreenWidth) &&
  4249. (pEntry->BitsPerPel == BitsPerPel) &&
  4250. (pEntry->MemoryFlags == MemoryFlags)) {
  4251. //
  4252. // Now find the entry with the refresh rate and memory speed the
  4253. // closest to, but not more than, our refresh rate and memory
  4254. // speed.
  4255. //
  4256. if ((pEntry->RefreshRate <= RefreshRate) &&
  4257. (pEntry->RefreshRate >= MatchRefreshRate) &&
  4258. (pEntry->MemorySpeed <= MemorySpeed) &&
  4259. (pEntry->MemorySpeed >= MatchMemorySpeed)) {
  4260. MatchRefreshRate = pEntry->RefreshRate;
  4261. MatchMemorySpeed = pEntry->MemorySpeed;
  4262. pStreamsParameters->FifoValue = pEntry->Value;
  4263. }
  4264. }
  4265. pEntry++;
  4266. }
  4267. if (MatchRefreshRate == 0) {
  4268. return ERROR_INVALID_PARAMETER;
  4269. }
  4270. return NO_ERROR;
  4271. }
  4272. /*****************************************************************************
  4273. *
  4274. * FUNCTION NAME: isMach()
  4275. *
  4276. * DESCRIPTIVE NAME:
  4277. *
  4278. * FUNCTION: Determine if system is an IBM Mach
  4279. *
  4280. *
  4281. * NOTES: Query the Vital Product Data (VPD) area
  4282. * F000:FFA0 in ROM.
  4283. * MACH Systems have "N", "P", "R", or "T" at location D
  4284. * i.e. at F000:FFAD location
  4285. *
  4286. * EXIT: return code FALSE if not an IBM MACH System
  4287. * return code TRUE if a IBM MACH System
  4288. *
  4289. * INTERNAL REFERENCES:
  4290. * ROUTINES:
  4291. *
  4292. * EXTERNAL REFERENCES:
  4293. * ROUTINES:
  4294. *
  4295. ****************************************************************************/
  4296. BOOLEAN isMach(PHW_DEVICE_EXTENSION HwDeviceExtension)
  4297. {
  4298. BOOLEAN ret = FALSE;
  4299. PVOID MappedVPDAddr = NULL;
  4300. PHYSICAL_ADDRESS VPDPhysAddr;
  4301. VPDPhysAddr.LowPart = 0x000fffad ;
  4302. VPDPhysAddr.HighPart = 0x00000000 ;
  4303. // Get the mapped address of the physical address F000:FFA0
  4304. MappedVPDAddr = VideoPortGetDeviceBase(HwDeviceExtension,
  4305. VPDPhysAddr,
  4306. 0x20,
  4307. 0);
  4308. if (MappedVPDAddr != NULL)
  4309. {
  4310. if ((VideoPortScanRom(HwDeviceExtension,
  4311. MappedVPDAddr,
  4312. 1,
  4313. "N"))||
  4314. (VideoPortScanRom(HwDeviceExtension,
  4315. MappedVPDAddr,
  4316. 1,
  4317. "P"))||
  4318. (VideoPortScanRom(HwDeviceExtension,
  4319. MappedVPDAddr,
  4320. 1,
  4321. "R"))||
  4322. (VideoPortScanRom(HwDeviceExtension,
  4323. MappedVPDAddr,
  4324. 1,
  4325. "T")))
  4326. {
  4327. VideoPortFreeDeviceBase(HwDeviceExtension,
  4328. MappedVPDAddr);
  4329. ret = TRUE;
  4330. }
  4331. }
  4332. return(ret);
  4333. }
  4334. VOID
  4335. WorkAroundForMach(
  4336. PHW_DEVICE_EXTENSION HwDeviceExtension
  4337. )
  4338. /*++
  4339. Routine Description:
  4340. This routine will attempt to determine if we are running on an
  4341. IBM Mach system. If so, and and 868 card was detected, we
  4342. will treat the card as an 864.
  4343. Arguments:
  4344. HwDeviceExtension - pointer to the miniports device extension.
  4345. Return:
  4346. none.
  4347. --*/
  4348. {
  4349. if ((HwDeviceExtension->SubTypeID == SUBTYPE_868) &&
  4350. isMach(HwDeviceExtension))
  4351. {
  4352. VideoDebugPrint((1, "S3 868 detected on IBM Mach. Treat as 864.\n"));
  4353. HwDeviceExtension->ChipID = S3_864;
  4354. HwDeviceExtension->SubTypeID = SUBTYPE_864;
  4355. }
  4356. }