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

6215 lines
185 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 pvHwDeviceExtension,
  1850. POINTER_CAPABILITY *PointerCapability
  1851. )
  1852. /*++
  1853. Routine Description:
  1854. Determine the DAC type for HwPointer Capabilities.
  1855. Arguments:
  1856. pHwDeviceExtension - Pointer to the miniport's device extension.
  1857. Return Value:
  1858. None.
  1859. --*/
  1860. {
  1861. PHW_DEVICE_EXTENSION HwDeviceExtension = pvHwDeviceExtension;
  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. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1934. // Set CRTC index to EX_DAC_CT
  1935. jExtendedVideoDacControl = VideoPortReadPortUchar(CRT_DATA_REG);
  1936. VideoPortWritePortUchar(CRT_DATA_REG,
  1937. (UCHAR) (jExtendedVideoDacControl & 0xfc));
  1938. VideoPortWritePortUchar(DAC_ADDRESS_WRITE_PORT, 0x3f);
  1939. VideoPortWritePortUchar(CRT_DATA_REG,
  1940. (UCHAR) ((jExtendedVideoDacControl & 0xfc) | 0x2));
  1941. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x37);
  1942. jTiDacId = VideoPortReadPortUchar(CRT_DATA_REG);
  1943. if (VideoPortReadPortUchar(DAC_PIXEL_MASK_REG) == 0x26) {
  1944. //
  1945. // The 3026 is Brooktree 485 compatible, except for a
  1946. // hardware bug that causes the hardware pointer to
  1947. // 'sparkle' when setting the palette colours, unless we
  1948. // wait for vertical retrace first:
  1949. //
  1950. HwDeviceExtension->Capabilities
  1951. |= (CAPS_BT485_POINTER | CAPS_WAIT_ON_PALETTE);
  1952. HwDeviceExtension->DacID = BT_485; // 485 compatible
  1953. pwszDAC = L"TI TVP3026";
  1954. cbDAC = sizeof(L"TI TVP3026");
  1955. }
  1956. //
  1957. // Restore all the registers.
  1958. //
  1959. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1960. VideoPortWritePortUchar(CRT_DATA_REG, jExtendedVideoDacControl);
  1961. }
  1962. if (!(HwDeviceExtension->Capabilities & CAPS_DAC_POINTER)) {
  1963. //
  1964. // Check for a BrookTree 485 DAC.
  1965. //
  1966. VideoPortWritePortUchar(BT485_ADDR_CMD_REG0, 0xff);
  1967. // Output 0xff to BT485 command register 0
  1968. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1969. // Set CRTC index to EX_DAC_CT
  1970. jExtendedVideoDacControl = VideoPortReadPortUchar(CRT_DATA_REG);
  1971. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) ((jExtendedVideoDacControl & 0xfc) | 0x02));
  1972. jBt485Status = VideoPortReadPortUchar(BT485_ADDR_CMD_REG0);
  1973. // Read Bt485 status register 0
  1974. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  1975. // Set CRTC index to 0x55
  1976. jExtendedVideoDacControl = VideoPortReadPortUchar(CRT_DATA_REG);
  1977. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) (jExtendedVideoDacControl & 0xfc));
  1978. if (jBt485Status != 0xff) {
  1979. HwDeviceExtension->Capabilities |= CAPS_BT485_POINTER;
  1980. pwszDAC = L"Brooktree Bt485";
  1981. cbDAC = sizeof(L"Brooktree Bt485");
  1982. HwDeviceExtension->DacID = BT_485;
  1983. }
  1984. }
  1985. }
  1986. //
  1987. // This section looks for an S3 SDAC if another was not detected,
  1988. // for the PPC.
  1989. //
  1990. if (HwDeviceExtension->DacID == UNKNOWN_DAC) {
  1991. //
  1992. // Only try this on an 864 or newer, because Orchid Farhenheit
  1993. // 1280 911 boards would get black screens when in VGA mode and
  1994. // this code was run (such as during initial Setup):
  1995. //
  1996. if ((HwDeviceExtension->ChipID >= S3_864) &&
  1997. FindSDAC(HwDeviceExtension)) {
  1998. //
  1999. // SDAC does not provide a cursor, but we can use the cursor
  2000. // built into the S3 (if there is one).
  2001. //
  2002. pwszDAC = L"S3 SDAC";
  2003. cbDAC = sizeof(L"S3 SDAC");
  2004. HwDeviceExtension->DacID = S3_SDAC;
  2005. }
  2006. }
  2007. VideoPortSetRegistryParameters(HwDeviceExtension,
  2008. L"HardwareInformation.DacType",
  2009. pwszDAC,
  2010. cbDAC);
  2011. }
  2012. VOID
  2013. S3DetermineMemorySize(
  2014. PVOID HwDeviceExtension
  2015. )
  2016. {
  2017. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  2018. UCHAR s3MemSizeCode;
  2019. //
  2020. // Get the size of the video memory.
  2021. //
  2022. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x36);
  2023. s3MemSizeCode = (VideoPortReadPortUchar(CRT_DATA_REG) >> 5) & 0x7;
  2024. if (hwDeviceExtension->ChipID == S3_911) {
  2025. if (s3MemSizeCode & 1) {
  2026. hwDeviceExtension->AdapterMemorySize = 0x00080000;
  2027. } else {
  2028. hwDeviceExtension->AdapterMemorySize = 0x00100000;
  2029. }
  2030. } else {
  2031. hwDeviceExtension->AdapterMemorySize = gacjMemorySize[s3MemSizeCode];
  2032. }
  2033. VideoPortSetRegistryParameters(hwDeviceExtension,
  2034. L"HardwareInformation.MemorySize",
  2035. &hwDeviceExtension->AdapterMemorySize,
  2036. sizeof(ULONG));
  2037. }
  2038. VOID
  2039. S3ValidateModes(
  2040. PVOID HwDeviceExtension,
  2041. POINTER_CAPABILITY *PointerCapability
  2042. )
  2043. /*++
  2044. Routine Description:
  2045. For fill in the capabilities bits for the s3 card, and return an
  2046. wide character string representing the chip.
  2047. Arguments:
  2048. HwDeviceExtension - Pointer to the miniport's device extension.
  2049. Return Value:
  2050. None.
  2051. --*/
  2052. {
  2053. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  2054. PS3_VIDEO_FREQUENCIES FrequencyEntry;
  2055. PS3_VIDEO_MODES ModeEntry;
  2056. PS3_VIDEO_FREQUENCIES FrequencyTable;
  2057. ULONG i;
  2058. ULONG ModeIndex;
  2059. UCHAR reg67;
  2060. UCHAR jChipID, jRevision;
  2061. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x30);
  2062. jChipID = VideoPortReadPortUchar(CRT_DATA_REG);
  2063. /////////////////////////////////////////////////////////////////////////
  2064. // Here we prune valid modes, based on rules according to the chip
  2065. // capabilities and memory requirements. It would be better if we
  2066. // could make the VESA call to determine the modes that the BIOS
  2067. // supports; however, that requires a buffer and I don't have the
  2068. // time to get it working with our Int 10 support.
  2069. //
  2070. // We prune modes so that we will not annoy the user by presenting
  2071. // modes in the 'Video Applet' which we know the user can't use.
  2072. //
  2073. hwDeviceExtension->NumAvailableModes = 0;
  2074. hwDeviceExtension->NumTotalModes = 0;
  2075. //
  2076. // Since there are a number of frequencies possible for each
  2077. // distinct resolution/colour depth, we cycle through the
  2078. // frequency table and find the appropriate mode entry for that
  2079. // frequency entry.
  2080. //
  2081. if (hwDeviceExtension->BiosPresent) {
  2082. FrequencyTable = hwDeviceExtension->Int10FrequencyTable;
  2083. } else {
  2084. //
  2085. // If there is no BIOS, construct the mode list from whatever
  2086. // fixed frequency tables we have for this chip.
  2087. //
  2088. FrequencyTable = hwDeviceExtension->FixedFrequencyTable;
  2089. }
  2090. ModeIndex = 0;
  2091. for (FrequencyEntry = FrequencyTable;
  2092. FrequencyEntry->BitsPerPel != 0;
  2093. FrequencyEntry++, ModeIndex++) {
  2094. //
  2095. // Find the mode for this entry. First, assume we won't find one.
  2096. //
  2097. FrequencyEntry->ModeValid = FALSE;
  2098. FrequencyEntry->ModeIndex = ModeIndex;
  2099. for (ModeEntry = S3Modes, i = 0; i < NumS3VideoModes; ModeEntry++, i++) {
  2100. if ((FrequencyEntry->BitsPerPel ==
  2101. ModeEntry->ModeInformation.BitsPerPlane) &&
  2102. (FrequencyEntry->ScreenWidth ==
  2103. ModeEntry->ModeInformation.VisScreenWidth)) {
  2104. //
  2105. // We've found a mode table entry that matches this frequency
  2106. // table entry. Now we'll figure out if we can actually do
  2107. // this mode/frequency combination. For now, assume we'll
  2108. // succeed.
  2109. //
  2110. FrequencyEntry->ModeEntry = ModeEntry;
  2111. FrequencyEntry->ModeValid = TRUE;
  2112. //
  2113. // Flags for private communication with the S3 display driver.
  2114. //
  2115. ModeEntry->ModeInformation.DriverSpecificAttributeFlags =
  2116. hwDeviceExtension->Capabilities;
  2117. if (*PointerCapability & POINTER_WORKS_ONLY_AT_8BPP) {
  2118. //
  2119. // Rule: On 911, 80x, and 928 chips we always use the
  2120. // built-in S3 pointer whenever we can; modes of
  2121. // colour depths greater than 8bpp, or resolutions
  2122. // of width more than 1024, require a DAC pointer.
  2123. //
  2124. if ((ModeEntry->ModeInformation.BitsPerPlane == 8) &&
  2125. (ModeEntry->ModeInformation.VisScreenWidth <= 1024)) {
  2126. //
  2127. // Always use the S3 pointer in lieu of the Brooktree
  2128. // or TI pointer whenever we can.
  2129. //
  2130. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2131. &= ~CAPS_DAC_POINTER;
  2132. if ((hwDeviceExtension->DacID == TI_3020) &&
  2133. (hwDeviceExtension->ChipID == S3_928)) {
  2134. //
  2135. // There are goofy 4-MB Level 14 #9 boards where
  2136. // stuff is shown on the screen if we try to use
  2137. // the built-in S3 pointer, and the hot-spot
  2138. // is wrong if we try to use the TI pointer.
  2139. // There are other 928 boards with TI 3020 DACs
  2140. // where the internal S3 pointer doesn't work. So
  2141. // punt to a software pointer for these modes:
  2142. //
  2143. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2144. |= CAPS_SW_POINTER;
  2145. }
  2146. } else {
  2147. //
  2148. // We can't use the built-in S3 pointer; if we don't
  2149. // have a DAC pointer, use a software pointer.
  2150. //
  2151. if (!(ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2152. & CAPS_DAC_POINTER)) {
  2153. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2154. |= CAPS_SW_POINTER;
  2155. }
  2156. }
  2157. } else {
  2158. //
  2159. // On 864/964 or newer chips, the built-in S3 pointer
  2160. // either handles all colour depths or none.
  2161. //
  2162. if (*PointerCapability & POINTER_BUILT_IN) {
  2163. if (*PointerCapability & POINTER_NEEDS_SCALING) {
  2164. //
  2165. // Check out the type of DAC:
  2166. //
  2167. // Note: This I/O should likely be moved out of the
  2168. // prune loop.
  2169. //
  2170. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x67);
  2171. reg67 = (UCHAR) VideoPortReadPortUchar(CRT_DATA_REG);
  2172. //
  2173. // Newer 864 BIOSes revert to 8-bit DAC mode when
  2174. // running at 640x480x16bpp even if the DAC is
  2175. // 16-bits, due to a conflict with the Reel Magic
  2176. // MPEG board at that resolution. Unfortunately,
  2177. // there's not a consistent BIOS version number
  2178. // that we can look for; we could check the
  2179. // DAC type after doing the int 10, but
  2180. // unfortunately, we need this information now
  2181. // to decide whether we should scale the x-
  2182. // coordinate or not.
  2183. //
  2184. // So simply always use a software pointer when
  2185. // running at 640x480x16bpp, and there is no
  2186. // DAC pointer:
  2187. //
  2188. if (!(ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2189. & CAPS_DAC_POINTER) &&
  2190. (ModeEntry->ModeInformation.BitsPerPlane == 16) &&
  2191. (ModeEntry->ModeInformation.VisScreenWidth == 640)) {
  2192. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2193. |= CAPS_SW_POINTER;
  2194. } else if (reg67 == 8) {
  2195. //
  2196. // It's an 8bit DAC. At 16bpp, we have to
  2197. // scale the x-coordinate by 2. At 32bpp,
  2198. // we have to use a software pointer.
  2199. //
  2200. if (ModeEntry->ModeInformation.BitsPerPlane == 16) {
  2201. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2202. |= CAPS_SCALE_POINTER;
  2203. } else {
  2204. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2205. |= CAPS_SW_POINTER;
  2206. }
  2207. } else {
  2208. //
  2209. // It's a 16bit DAC. For 32bpp modes, we have
  2210. // to scale the pointer position by 2:
  2211. //
  2212. if (ModeEntry->ModeInformation.BitsPerPlane == 32) {
  2213. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2214. |= CAPS_SCALE_POINTER;
  2215. }
  2216. }
  2217. }
  2218. } else {
  2219. //
  2220. // There's no built-in S3 pointer. If we haven't
  2221. // detected a DAC pointer, we have to use a software
  2222. // pointer.
  2223. //
  2224. if (!(ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2225. & CAPS_DAC_POINTER)) {
  2226. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2227. |= CAPS_SW_POINTER;
  2228. }
  2229. }
  2230. }
  2231. //
  2232. // Rule: We allow refresh rates higher than 76 Hz only for
  2233. // cards that don't have a built-in S3 pointer. We
  2234. // do this because we assume that such cards are VRAM
  2235. // based and have a good external DAC that can properly
  2236. // handle rates higher than 76 Hz -- because we have
  2237. // found many Diamond DRAM cards that produce improper
  2238. // displays at the higher rates, especially on non-x86
  2239. // machines.
  2240. //
  2241. if ((FrequencyEntry->ScreenFrequency > 76) &&
  2242. (*PointerCapability & POINTER_BUILT_IN)) {
  2243. FrequencyEntry->ModeValid = FALSE;
  2244. }
  2245. //
  2246. // Rule: We handle only 8bpp on 911/924 cards. These chips can also
  2247. // support only non-contiguous modes.
  2248. //
  2249. if (hwDeviceExtension->ChipID == S3_911) {
  2250. if (ModeEntry->ModeInformation.BitsPerPlane != 8) {
  2251. FrequencyEntry->ModeValid = FALSE;
  2252. } else {
  2253. ModeEntry->Int10ModeNumberContiguous =
  2254. ModeEntry->Int10ModeNumberNoncontiguous;
  2255. ModeEntry->ScreenStrideContiguous =
  2256. ModeEntry->ModeInformation.ScreenStride;
  2257. }
  2258. }
  2259. //
  2260. // Rule: The 868/968 cannot do 'new packed 32-bit transfers'
  2261. // at 8bpp because of a chip bug.
  2262. //
  2263. if ((ModeEntry->ModeInformation.BitsPerPlane == 8) &&
  2264. ((hwDeviceExtension->SubTypeID == SUBTYPE_868) ||
  2265. (hwDeviceExtension->SubTypeID == SUBTYPE_968))) {
  2266. ModeEntry->ModeInformation.DriverSpecificAttributeFlags
  2267. &= ~CAPS_PACKED_EXPANDS;
  2268. }
  2269. //
  2270. // Rule: The 801/805 cannot do any accelerated modes above
  2271. // 16bpp.
  2272. //
  2273. if ((hwDeviceExtension->ChipID == S3_801) &&
  2274. (ModeEntry->ModeInformation.BitsPerPlane > 16)) {
  2275. FrequencyEntry->ModeValid = FALSE;
  2276. }
  2277. //
  2278. // Rule: We use the 2xx non-contiguous modes whenever we can
  2279. // on 80x/928 boards because some BIOSes have bugs for
  2280. // the contiguous 8bpp modes.
  2281. //
  2282. // We don't use the non-contiguous modes on 864 cards
  2283. // because most 864 BIOSes have a bug where they don't
  2284. // set the M and N parameters correctly on 1 MB cards,
  2285. // causing screen noise.
  2286. //
  2287. if ((ModeEntry->ModeInformation.BitsPerPlane == 8) &&
  2288. (hwDeviceExtension->ChipID <= S3_928)) {
  2289. //
  2290. // If we have only 512k, we can't use a non-contiguous
  2291. // 800x600x256 mode.
  2292. //
  2293. if ((ModeEntry->ModeInformation.VisScreenWidth == 640) ||
  2294. ((ModeEntry->ModeInformation.VisScreenWidth == 800) &&
  2295. (hwDeviceExtension->AdapterMemorySize > 0x080000))) {
  2296. ModeEntry->Int10ModeNumberContiguous =
  2297. ModeEntry->Int10ModeNumberNoncontiguous;
  2298. ModeEntry->ScreenStrideContiguous =
  2299. ModeEntry->ModeInformation.ScreenStride;
  2300. }
  2301. }
  2302. //
  2303. // Rule: Only 964 or 968 or newer boards can handle resolutions
  2304. // larger than 1280x1024:
  2305. //
  2306. if (ModeEntry->ModeInformation.VisScreenWidth > 1280) {
  2307. if ((hwDeviceExtension->SubTypeID != SUBTYPE_964) &&
  2308. (hwDeviceExtension->SubTypeID < SUBTYPE_968)) {
  2309. FrequencyEntry->ModeValid = FALSE;
  2310. }
  2311. }
  2312. //
  2313. // Rule: 911s and early revs of 805s and 928s cannot do
  2314. // 1152x864:
  2315. //
  2316. if (ModeEntry->ModeInformation.VisScreenWidth == 1152) {
  2317. if ((hwDeviceExtension->ChipID == S3_911) ||
  2318. (jChipID == 0xA0) ||
  2319. (jChipID == 0x90)) {
  2320. FrequencyEntry->ModeValid = FALSE;
  2321. }
  2322. //
  2323. // Number 9 has different int 10 numbers from
  2324. // Diamond for 1152x864x16bpp and 1152x864x32bpp.
  2325. // Later perhaps we should incorporate mode numbers
  2326. // along with the frequency tables.
  2327. //
  2328. if (hwDeviceExtension->BoardID == S3_NUMBER_NINE) {
  2329. if (ModeEntry->ModeInformation.BitsPerPlane == 16) {
  2330. ModeEntry->Int10ModeNumberContiguous =
  2331. ModeEntry->Int10ModeNumberNoncontiguous =
  2332. 0x126;
  2333. } else if (ModeEntry->ModeInformation.BitsPerPlane == 32) {
  2334. ModeEntry->Int10ModeNumberContiguous =
  2335. ModeEntry->Int10ModeNumberNoncontiguous =
  2336. 0x127;
  2337. }
  2338. }
  2339. }
  2340. //
  2341. // 24bpp support. Need s3 968 and linear space for banks.
  2342. //
  2343. if (ModeEntry->ModeInformation.BitsPerPlane == 24) {
  2344. //
  2345. // 24bpp on diamond s3 968 seems to have problems doing ULONG reads.
  2346. //
  2347. if (hwDeviceExtension->BoardID == S3_DIAMOND)
  2348. ModeEntry->ModeInformation.DriverSpecificAttributeFlags |=
  2349. CAPS_BAD_DWORD_READS;
  2350. //
  2351. // Set FALSE for other than 968 and clear CAPS_BAD_DWORD_READS.
  2352. //
  2353. if ((hwDeviceExtension->SubTypeID != SUBTYPE_968) ||
  2354. ((hwDeviceExtension->BoardID != S3_DIAMOND) &&
  2355. (hwDeviceExtension->BoardID != S3_NUMBER_NINE)) || //#9 968 24bpp
  2356. (!(hwDeviceExtension->Capabilities & CAPS_NEW_MMIO))) {
  2357. FrequencyEntry->ModeValid = FALSE;
  2358. ModeEntry->ModeInformation.DriverSpecificAttributeFlags &=
  2359. ~CAPS_BAD_DWORD_READS;
  2360. }
  2361. }
  2362. if ((ModeEntry->ModeInformation.VisScreenWidth == 800) &&
  2363. (ModeEntry->ModeInformation.BitsPerPlane == 32)) {
  2364. //
  2365. // Rule: 928 revs A through D can only do 800x600x32 in
  2366. // a non-contiguous mode.
  2367. //
  2368. if (jChipID == 0x90) {
  2369. ModeEntry->ScreenStrideContiguous =
  2370. ModeEntry->ModeInformation.ScreenStride;
  2371. }
  2372. }
  2373. if (hwDeviceExtension->SubTypeID == SUBTYPE_732) {
  2374. //
  2375. // Rule: The 732 Trio32 chip simply can't do 800x600x32bpp.
  2376. //
  2377. if ((ModeEntry->ModeInformation.VisScreenWidth == 800) &&
  2378. (ModeEntry->ModeInformation.BitsPerPlane == 32)) {
  2379. FrequencyEntry->ModeValid = FALSE;
  2380. //
  2381. // Rule: The 732 Trio32 chip simply can't do 1152x864x16bpp.
  2382. //
  2383. } else if ((ModeEntry->ModeInformation.VisScreenWidth == 1152) &&
  2384. (ModeEntry->ModeInformation.BitsPerPlane == 16)) {
  2385. FrequencyEntry->ModeValid = FALSE;
  2386. //
  2387. // Rule: The 732 Trio32 chip simply can't do 1280x1024 modes
  2388. //
  2389. } else if ((ModeEntry->ModeInformation.VisScreenWidth) == 1280) {
  2390. FrequencyEntry->ModeValid = FALSE;
  2391. }
  2392. }
  2393. //
  2394. // Rule: We have to have enough memory to handle the mode.
  2395. //
  2396. // Note that we use the contiguous width for this
  2397. // computation; unfortunately, we don't know at this time
  2398. // whether we can handle a contiguous mode or not, so we
  2399. // may err on the side of listing too many possible modes.
  2400. //
  2401. // We may also list too many possible modes if the card
  2402. // combines VRAM with a DRAM cache, because it will report
  2403. // the VRAM + DRAM amount of memory, but only the VRAM can
  2404. // be used as screen memory.
  2405. //
  2406. if (ModeEntry->ModeInformation.VisScreenHeight *
  2407. ModeEntry->ScreenStrideContiguous >
  2408. hwDeviceExtension->AdapterMemorySize) {
  2409. FrequencyEntry->ModeValid = FALSE;
  2410. }
  2411. //
  2412. // Rule: If we can't use Int 10, restrict 1280x1024 to Number9
  2413. // cards, because I haven't been able to fix the mode
  2414. // tables for other cards yet.
  2415. //
  2416. if (FrequencyTable == hwDeviceExtension->FixedFrequencyTable) {
  2417. if ((ModeEntry->ModeInformation.VisScreenHeight == 1280) &&
  2418. (hwDeviceExtension->BoardID != S3_NUMBER_NINE)) {
  2419. FrequencyEntry->ModeValid = FALSE;
  2420. }
  2421. //
  2422. // Rule: If there isn't a table entry for programming the CRTC,
  2423. // we can't do this frequency at this mode.
  2424. //
  2425. if (FrequencyEntry->Fixed.CRTCTable[hwDeviceExtension->ChipID]
  2426. == NULL) {
  2427. FrequencyEntry->ModeValid = FALSE;
  2428. break;
  2429. }
  2430. }
  2431. //
  2432. // Don't forget to count it if it's still a valid mode after
  2433. // applying all those rules.
  2434. //
  2435. if (FrequencyEntry->ModeValid) {
  2436. hwDeviceExtension->NumAvailableModes++;
  2437. }
  2438. //
  2439. // We've found a mode for this frequency entry, so we
  2440. // can break out of the mode loop:
  2441. //
  2442. break;
  2443. }
  2444. }
  2445. }
  2446. hwDeviceExtension->NumTotalModes = ModeIndex;
  2447. VideoDebugPrint((2, "S3: Number of modes = %d\n", ModeIndex));
  2448. }
  2449. VP_STATUS
  2450. S3RegistryCallback(
  2451. PVOID HwDeviceExtension,
  2452. PVOID Context,
  2453. PWSTR ValueName,
  2454. PVOID ValueData,
  2455. ULONG ValueLength
  2456. )
  2457. /*++
  2458. Routine Description:
  2459. This routine determines if the alternate register set was requested via
  2460. the registry.
  2461. Arguments:
  2462. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  2463. Context - Context value passed to the get registry paramters routine.
  2464. ValueName - Name of the value requested.
  2465. ValueData - Pointer to the requested data.
  2466. ValueLength - Length of the requested data.
  2467. Return Value:
  2468. returns NO_ERROR if the paramter was TRUE.
  2469. returns ERROR_INVALID_PARAMETER otherwise.
  2470. --*/
  2471. {
  2472. if (ValueLength && *((PULONG)ValueData)) {
  2473. return NO_ERROR;
  2474. } else {
  2475. return ERROR_INVALID_PARAMETER;
  2476. }
  2477. } // end S3RegistryCallback()
  2478. BOOLEAN
  2479. S3Initialize(
  2480. PVOID HwDeviceExtension
  2481. )
  2482. /*++
  2483. Routine Description:
  2484. This routine does one time initialization of the device.
  2485. Arguments:
  2486. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  2487. Return Value:
  2488. Always returns TRUE since this routine can never fail.
  2489. --*/
  2490. {
  2491. UNREFERENCED_PARAMETER(HwDeviceExtension);
  2492. return TRUE;
  2493. } // end S3Initialize()
  2494. BOOLEAN
  2495. S3ResetHw(
  2496. PVOID HwDeviceExtension,
  2497. ULONG Columns,
  2498. ULONG Rows
  2499. )
  2500. /*++
  2501. Routine Description:
  2502. This routine preps the S3 card for return to a VGA mode.
  2503. This routine is called during system shutdown. By returning
  2504. a FALSE we inform the HAL to do an int 10 to go into text
  2505. mode before shutting down. Shutdown would fail with some S3
  2506. cards without this.
  2507. We do some clean up before returning so that the int 10
  2508. will work.
  2509. Arguments:
  2510. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  2511. Return Value:
  2512. The return value of FALSE informs the hal to go into text mode.
  2513. --*/
  2514. {
  2515. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  2516. UNREFERENCED_PARAMETER(Columns);
  2517. UNREFERENCED_PARAMETER(Rows);
  2518. //
  2519. // We don't want to execute this reset code if we are not
  2520. // currently in an S3 mode!
  2521. //
  2522. if (!hwDeviceExtension->bNeedReset)
  2523. {
  2524. return FALSE;
  2525. }
  2526. hwDeviceExtension->bNeedReset = FALSE;
  2527. //
  2528. // Wait for the GP to become idle.
  2529. //
  2530. while (VideoPortReadPortUshort(GP_STAT) & 0x0200);
  2531. //
  2532. // Zero the DAC and the Screen buffer memory.
  2533. //
  2534. ZeroMemAndDac(HwDeviceExtension);
  2535. //
  2536. // Reset the board to a default mode
  2537. //
  2538. // After NT 3.51 ships use the same modetable for all
  2539. // architectures, but just to be sure we don't break
  2540. // something we'll use two for now. The 'no_bios'
  2541. // version of the modetable is for the IBM PS/2 model
  2542. // 76i.
  2543. //
  2544. if (hwDeviceExtension->BiosPresent == FALSE)
  2545. {
  2546. SetHWMode(HwDeviceExtension, s3_set_vga_mode_no_bios);
  2547. }
  2548. else
  2549. {
  2550. SetHWMode(HwDeviceExtension, s3_set_vga_mode);
  2551. }
  2552. return FALSE;
  2553. }
  2554. BOOLEAN
  2555. S3StartIO(
  2556. PVOID pvHwDeviceExtension,
  2557. PVIDEO_REQUEST_PACKET RequestPacket
  2558. )
  2559. /*++
  2560. Routine Description:
  2561. This routine is the main execution routine for the miniport driver. It
  2562. acceptss a Video Request Packet, performs the request, and then returns
  2563. with the appropriate status.
  2564. Arguments:
  2565. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  2566. RequestPacket - Pointer to the video request packet. This structure
  2567. contains all the parameters passed to the VideoIoControl function.
  2568. Return Value:
  2569. --*/
  2570. {
  2571. PHW_DEVICE_EXTENSION hwDeviceExtension = pvHwDeviceExtension;
  2572. PHW_DEVICE_EXTENSION HwDeviceExtension = pvHwDeviceExtension;
  2573. VP_STATUS status;
  2574. PVIDEO_MODE_INFORMATION modeInformation;
  2575. PVIDEO_CLUT clutBuffer;
  2576. UCHAR byte;
  2577. ULONG modeNumber;
  2578. PS3_VIDEO_MODES ModeEntry;
  2579. PS3_VIDEO_FREQUENCIES FrequencyEntry;
  2580. PS3_VIDEO_FREQUENCIES FrequencyTable;
  2581. UCHAR ModeControlByte;
  2582. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  2583. PVIDEO_SHARE_MEMORY pShareMemory;
  2584. PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
  2585. PHYSICAL_ADDRESS shareAddress;
  2586. PVOID virtualAddress;
  2587. ULONG sharedViewSize;
  2588. ULONG inIoSpace;
  2589. UCHAR OriginalRegPrimary;
  2590. UCHAR OriginalRegSecondary;
  2591. //
  2592. // Switch on the IoContolCode in the RequestPacket. It indicates which
  2593. // function must be performed by the driver.
  2594. //
  2595. switch (RequestPacket->IoControlCode) {
  2596. case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
  2597. VideoDebugPrint((2, "S3tartIO - MapVideoMemory\n"));
  2598. {
  2599. PVIDEO_MEMORY_INFORMATION memoryInformation;
  2600. ULONG physicalFrameLength;
  2601. if ( (RequestPacket->OutputBufferLength <
  2602. (RequestPacket->StatusBlock->Information =
  2603. sizeof(VIDEO_MEMORY_INFORMATION))) ||
  2604. (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
  2605. status = ERROR_INSUFFICIENT_BUFFER;
  2606. break;
  2607. }
  2608. memoryInformation = RequestPacket->OutputBuffer;
  2609. memoryInformation->VideoRamBase = ((PVIDEO_MEMORY)
  2610. (RequestPacket->InputBuffer))->RequestedVirtualAddress;
  2611. physicalFrameLength = hwDeviceExtension->FrameLength;
  2612. inIoSpace = hwDeviceExtension->PhysicalFrameIoSpace;
  2613. //
  2614. // IMPORTANT - As a rule we only map the actual amount of memory
  2615. // on the board, not the whole physical address space reported
  2616. // by PCI. The reason for this is that mapping the memory takes
  2617. // up a lot of resources in the machine, which as quite scarce by
  2618. // default. Mapping 64MEG of address space would actually always
  2619. // fail in machines that have 32MEG or even 64MEG of RAM.
  2620. //
  2621. //
  2622. // Performance:
  2623. //
  2624. // Enable USWC on the P6 processor.
  2625. // We only do it for the frame buffer - memory mapped registers can
  2626. // not be mapped USWC because write combining the registers would
  2627. // cause very bad things to happen !
  2628. //
  2629. inIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  2630. //
  2631. // P6 workaround:
  2632. //
  2633. // Because of a current limitation in many P6 machines, USWC only
  2634. // works on sections of 4MEG of memory. So lets round up the size
  2635. // of memory on the cards that have less than 4MEG up to 4MEG so
  2636. // they can also benefit from this feature.
  2637. //
  2638. // We will only do this for NEW_MMIO cards, which have a large
  2639. // block of address space that is reserved via PCI. This way
  2640. // we are sure we will not conflict with another device that might
  2641. // have addresses right after us.
  2642. //
  2643. // We do this only for mapping purposes. We still want to return
  2644. // the real size of memory since the driver can not use memory that
  2645. // is not actually there !
  2646. //
  2647. if ((hwDeviceExtension->Capabilities & CAPS_NEW_MMIO) &&
  2648. (physicalFrameLength < 0x00400000)) {
  2649. physicalFrameLength = 0x00400000;
  2650. }
  2651. status = VideoPortMapMemory(hwDeviceExtension,
  2652. hwDeviceExtension->PhysicalFrameAddress,
  2653. &physicalFrameLength,
  2654. &inIoSpace,
  2655. &(memoryInformation->VideoRamBase));
  2656. //
  2657. // The frame buffer and virtual memory are equivalent in this
  2658. // case.
  2659. //
  2660. memoryInformation->FrameBufferBase =
  2661. memoryInformation->VideoRamBase;
  2662. memoryInformation->FrameBufferLength =
  2663. hwDeviceExtension->FrameLength;
  2664. memoryInformation->VideoRamLength =
  2665. hwDeviceExtension->FrameLength;
  2666. }
  2667. break;
  2668. case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
  2669. VideoDebugPrint((2, "S3StartIO - UnMapVideoMemory\n"));
  2670. if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) {
  2671. status = ERROR_INSUFFICIENT_BUFFER;
  2672. break;
  2673. }
  2674. status = VideoPortUnmapMemory(hwDeviceExtension,
  2675. ((PVIDEO_MEMORY)
  2676. (RequestPacket->InputBuffer))->
  2677. RequestedVirtualAddress,
  2678. 0);
  2679. break;
  2680. case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
  2681. VideoDebugPrint((2, "S3StartIO - QueryPublicAccessRanges\n"));
  2682. {
  2683. PVIDEO_PUBLIC_ACCESS_RANGES portAccess;
  2684. ULONG physicalPortLength;
  2685. if ( RequestPacket->OutputBufferLength <
  2686. (RequestPacket->StatusBlock->Information =
  2687. 2 * sizeof(VIDEO_PUBLIC_ACCESS_RANGES)) ) {
  2688. status = ERROR_INSUFFICIENT_BUFFER;
  2689. break;
  2690. }
  2691. portAccess = RequestPacket->OutputBuffer;
  2692. portAccess->VirtualAddress = (PVOID) NULL; // Requested VA
  2693. portAccess->InIoSpace = hwDeviceExtension->RegisterSpace;
  2694. portAccess->MappedInIoSpace = portAccess->InIoSpace;
  2695. physicalPortLength = hwDeviceExtension->RegisterLength;
  2696. status = VideoPortMapMemory(hwDeviceExtension,
  2697. hwDeviceExtension->PhysicalRegisterAddress,
  2698. &physicalPortLength,
  2699. &(portAccess->MappedInIoSpace),
  2700. &(portAccess->VirtualAddress));
  2701. if (status == NO_ERROR) {
  2702. portAccess++;
  2703. portAccess->VirtualAddress = (PVOID) NULL; // Requested VA
  2704. portAccess->InIoSpace = hwDeviceExtension->MmIoSpace;
  2705. portAccess->MappedInIoSpace = portAccess->InIoSpace;
  2706. physicalPortLength = hwDeviceExtension->MmIoLength;
  2707. status = VideoPortMapMemory(hwDeviceExtension,
  2708. hwDeviceExtension->PhysicalMmIoAddress,
  2709. &physicalPortLength,
  2710. &(portAccess->MappedInIoSpace),
  2711. &(portAccess->VirtualAddress));
  2712. }
  2713. }
  2714. break;
  2715. case IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES:
  2716. VideoDebugPrint((2, "S3StartIO - FreePublicAccessRanges\n"));
  2717. {
  2718. PVIDEO_MEMORY mappedMemory;
  2719. if (RequestPacket->InputBufferLength < 2 * sizeof(VIDEO_MEMORY)) {
  2720. status = ERROR_INSUFFICIENT_BUFFER;
  2721. break;
  2722. }
  2723. status = NO_ERROR;
  2724. mappedMemory = RequestPacket->InputBuffer;
  2725. if (mappedMemory->RequestedVirtualAddress != NULL) {
  2726. status = VideoPortUnmapMemory(hwDeviceExtension,
  2727. mappedMemory->
  2728. RequestedVirtualAddress,
  2729. 0);
  2730. }
  2731. if (status == NO_ERROR) {
  2732. mappedMemory++;
  2733. status = VideoPortUnmapMemory(hwDeviceExtension,
  2734. mappedMemory->
  2735. RequestedVirtualAddress,
  2736. 0);
  2737. }
  2738. }
  2739. break;
  2740. case IOCTL_VIDEO_QUERY_AVAIL_MODES:
  2741. VideoDebugPrint((2, "S3StartIO - QueryAvailableModes\n"));
  2742. if (RequestPacket->OutputBufferLength <
  2743. (RequestPacket->StatusBlock->Information =
  2744. hwDeviceExtension->NumAvailableModes
  2745. * sizeof(VIDEO_MODE_INFORMATION)) ) {
  2746. VideoDebugPrint((1, "\n*** NOT ENOUGH MEMORY FOR OUTPUT ***\n\n"));
  2747. status = ERROR_INSUFFICIENT_BUFFER;
  2748. } else {
  2749. modeInformation = RequestPacket->OutputBuffer;
  2750. if (hwDeviceExtension->BiosPresent) {
  2751. FrequencyTable = hwDeviceExtension->Int10FrequencyTable;
  2752. } else {
  2753. FrequencyTable = hwDeviceExtension->FixedFrequencyTable;
  2754. }
  2755. for (FrequencyEntry = FrequencyTable;
  2756. FrequencyEntry->BitsPerPel != 0;
  2757. FrequencyEntry++) {
  2758. if (FrequencyEntry->ModeValid) {
  2759. *modeInformation =
  2760. FrequencyEntry->ModeEntry->ModeInformation;
  2761. modeInformation->Frequency =
  2762. FrequencyEntry->ScreenFrequency;
  2763. modeInformation->ModeIndex =
  2764. FrequencyEntry->ModeIndex;
  2765. modeInformation++;
  2766. }
  2767. }
  2768. status = NO_ERROR;
  2769. }
  2770. break;
  2771. case IOCTL_VIDEO_QUERY_CURRENT_MODE:
  2772. VideoDebugPrint((2, "S3StartIO - QueryCurrentModes\n"));
  2773. if (RequestPacket->OutputBufferLength <
  2774. (RequestPacket->StatusBlock->Information =
  2775. sizeof(VIDEO_MODE_INFORMATION)) ) {
  2776. status = ERROR_INSUFFICIENT_BUFFER;
  2777. } else {
  2778. *((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer) =
  2779. hwDeviceExtension->ActiveModeEntry->ModeInformation;
  2780. ((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer)->Frequency =
  2781. hwDeviceExtension->ActiveFrequencyEntry->ScreenFrequency;
  2782. status = NO_ERROR;
  2783. }
  2784. break;
  2785. case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
  2786. VideoDebugPrint((2, "S3StartIO - QueryNumAvailableModes\n"));
  2787. //
  2788. // Find out the size of the data to be put in the the buffer and
  2789. // return that in the status information (whether or not the
  2790. // information is there). If the buffer passed in is not large
  2791. // enough return an appropriate error code.
  2792. //
  2793. if (RequestPacket->OutputBufferLength <
  2794. (RequestPacket->StatusBlock->Information =
  2795. sizeof(VIDEO_NUM_MODES)) ) {
  2796. status = ERROR_INSUFFICIENT_BUFFER;
  2797. } else {
  2798. ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->NumModes =
  2799. hwDeviceExtension->NumAvailableModes;
  2800. ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->ModeInformationLength =
  2801. sizeof(VIDEO_MODE_INFORMATION);
  2802. status = NO_ERROR;
  2803. }
  2804. break;
  2805. case IOCTL_VIDEO_SET_CURRENT_MODE:
  2806. VideoDebugPrint((2, "S3StartIO - SetCurrentMode\n"));
  2807. //
  2808. // Check if the size of the data in the input buffer is large enough.
  2809. //
  2810. if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE)) {
  2811. status = ERROR_INSUFFICIENT_BUFFER;
  2812. break;
  2813. }
  2814. //
  2815. // Assume failure for now.
  2816. //
  2817. status = ERROR_INVALID_PARAMETER;
  2818. //
  2819. // Find the correct entries in the S3_VIDEO_MODES and S3_VIDEO_FREQUENCIES
  2820. // tables that correspond to this mode number. (Remember that each
  2821. // mode in the S3_VIDEO_MODES table can have a number of possible
  2822. // frequencies associated with it.)
  2823. //
  2824. modeNumber = ((PVIDEO_MODE) RequestPacket->InputBuffer)->RequestedMode;
  2825. if (modeNumber >= hwDeviceExtension->NumTotalModes) {
  2826. break;
  2827. }
  2828. if (hwDeviceExtension->BiosPresent) {
  2829. FrequencyEntry = &hwDeviceExtension->Int10FrequencyTable[modeNumber];
  2830. if (!(FrequencyEntry->ModeValid)) {
  2831. break;
  2832. }
  2833. ModeEntry = FrequencyEntry->ModeEntry;
  2834. //
  2835. // At this point, 'ModeEntry' and 'FrequencyEntry' point to the
  2836. // necessary table entries required for setting the requested mode.
  2837. //
  2838. VideoPortZeroMemory(&biosArguments, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
  2839. //
  2840. // Unlock the S3 registers.
  2841. //
  2842. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x4838);
  2843. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xA039);
  2844. //
  2845. // Use register 52 before every Int 10 modeset to set the refresh
  2846. // rate. If the card doesn't support it, or we don't know what
  2847. // values to use, the requested frequency will be '1', which means
  2848. // 'use the hardware default refresh.'
  2849. //
  2850. if (FrequencyEntry->ScreenFrequency != 1) {
  2851. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x52);
  2852. OriginalRegPrimary = VideoPortReadPortUchar(CRT_DATA_REG);
  2853. ModeControlByte = OriginalRegPrimary;
  2854. ModeControlByte &= ~FrequencyEntry->Int10.FrequencyPrimaryMask;
  2855. ModeControlByte |= FrequencyEntry->Int10.FrequencyPrimarySet;
  2856. VideoPortWritePortUchar(CRT_DATA_REG, ModeControlByte);
  2857. if (FrequencyEntry->Int10.FrequencySecondaryMask != 0) {
  2858. VideoPortWritePortUchar(CRT_ADDRESS_REG,
  2859. hwDeviceExtension->FrequencySecondaryIndex);
  2860. OriginalRegSecondary = VideoPortReadPortUchar(CRT_DATA_REG);
  2861. ModeControlByte = OriginalRegSecondary;
  2862. ModeControlByte &= ~FrequencyEntry->Int10.FrequencySecondaryMask;
  2863. ModeControlByte |= FrequencyEntry->Int10.FrequencySecondarySet;
  2864. VideoPortWritePortUchar(CRT_DATA_REG, ModeControlByte);
  2865. }
  2866. }
  2867. //
  2868. // To do 24bpp on the #9 968 set bit 7 in register 41 before every
  2869. // Int 10 modeset. If not doing 24bpp, clear that bit.
  2870. //
  2871. if ((hwDeviceExtension->BoardID == S3_NUMBER_NINE) &&
  2872. (hwDeviceExtension->SubTypeID == SUBTYPE_968)) {
  2873. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x41);
  2874. OriginalRegPrimary = VideoPortReadPortUchar(CRT_DATA_REG);
  2875. ModeControlByte = OriginalRegPrimary;
  2876. if (ModeEntry->ModeInformation.BitsPerPlane == 24) {
  2877. ModeControlByte |= 0x80;
  2878. } else {
  2879. ModeControlByte &= ~0x80;
  2880. }
  2881. VideoPortWritePortUchar(CRT_DATA_REG, ModeControlByte);
  2882. }
  2883. //
  2884. // Turn off the screen to work around a bug in some
  2885. // s3 bios's. (The symptom of the bug is we loop
  2886. // forever in the bios after trying to set a mode.)
  2887. //
  2888. VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x1);
  2889. VideoPortWritePortUchar(SEQ_DATA_REG,
  2890. (UCHAR)(VideoPortReadPortUchar(SEQ_DATA_REG) | 0x20));
  2891. //
  2892. // First try the modeset with the 'Contiguous' mode:
  2893. //
  2894. biosArguments.Ebx = ModeEntry->Int10ModeNumberContiguous;
  2895. biosArguments.Eax = 0x4f02;
  2896. status = VideoPortInt10(HwDeviceExtension, &biosArguments);
  2897. if (status != NO_ERROR) {
  2898. VideoDebugPrint((1, "S3: first int10 call FAILED\n"));
  2899. }
  2900. if ((status == NO_ERROR) && (biosArguments.Eax & 0xff00) == 0) {
  2901. //
  2902. // The contiguous mode set succeeded.
  2903. //
  2904. ModeEntry->ModeInformation.ScreenStride =
  2905. ModeEntry->ScreenStrideContiguous;
  2906. } else {
  2907. //
  2908. // Try again with the 'Noncontiguous' mode:
  2909. //
  2910. biosArguments.Ebx = ModeEntry->Int10ModeNumberNoncontiguous;
  2911. biosArguments.Eax = 0x4f02;
  2912. status = VideoPortInt10(HwDeviceExtension, &biosArguments);
  2913. if (status != NO_ERROR)
  2914. {
  2915. VideoDebugPrint((1, "S3: second int10 call FAILED\n"));
  2916. }
  2917. //
  2918. // If the video port called succeeded, check the register return
  2919. // code. Some HP BIOSes always return failure even when the
  2920. // int 10 works fine, so we ignore its return code.
  2921. //
  2922. if ((status == NO_ERROR) &&
  2923. ((hwDeviceExtension->BoardID != S3_HP) &&
  2924. ((biosArguments.Eax & 0xff00) != 0))) {
  2925. status = ERROR_INVALID_PARAMETER;
  2926. }
  2927. }
  2928. if (FrequencyEntry->ScreenFrequency != 1) {
  2929. //
  2930. // Unlock the S3 registers.
  2931. //
  2932. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x4838);
  2933. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xA039);
  2934. //
  2935. // If the user has been running the Display Applet and we're
  2936. // reverting back to 'hardware default setting,' we have to
  2937. // restore the refresh registers to their original settings.
  2938. //
  2939. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x52);
  2940. VideoPortWritePortUchar(CRT_DATA_REG, OriginalRegPrimary);
  2941. VideoPortWritePortUchar(CRT_ADDRESS_REG,
  2942. hwDeviceExtension->FrequencySecondaryIndex);
  2943. VideoPortWritePortUchar(CRT_DATA_REG, OriginalRegSecondary);
  2944. }
  2945. }
  2946. if (status != NO_ERROR) {
  2947. VideoDebugPrint((1, "S3: Trying fixed mode-set\n"));
  2948. //
  2949. // A problem occured during the int10. Let's see if we can recover.
  2950. //
  2951. #ifndef S3_USE_FIXED_TABLES
  2952. //
  2953. // If we are only supposed to use int10, then this is total
  2954. // failure. Just leave.
  2955. //
  2956. break;
  2957. #endif
  2958. //
  2959. // Let see if we are using a fixed mode table number
  2960. //
  2961. if (!hwDeviceExtension->BiosPresent) {
  2962. FrequencyEntry = &hwDeviceExtension->FixedFrequencyTable[modeNumber];
  2963. } else {
  2964. PS3_VIDEO_FREQUENCIES oldFrequencyEntry = FrequencyEntry;
  2965. PS3_VIDEO_FREQUENCIES newFrequencyEntry;
  2966. PS3_VIDEO_FREQUENCIES bestFrequencyEntry;
  2967. //
  2968. // Okay, we constructed our original mode list assuming
  2969. // we could use Int 10, but we have just discovered the
  2970. // Int 10 didn't work -- probably because there was a
  2971. // problem with the BIOS emulator. To recover, we will now
  2972. // try to find the best mode in the Fixed Frequency table to
  2973. // match the requested mode.
  2974. //
  2975. FrequencyEntry = NULL;
  2976. bestFrequencyEntry = NULL;
  2977. for (newFrequencyEntry = &hwDeviceExtension->FixedFrequencyTable[0];
  2978. newFrequencyEntry->BitsPerPel != 0;
  2979. newFrequencyEntry++) {
  2980. //
  2981. // Check for a matching mode.
  2982. //
  2983. if ( (newFrequencyEntry->BitsPerPel ==
  2984. oldFrequencyEntry->BitsPerPel) &&
  2985. (newFrequencyEntry->ScreenWidth ==
  2986. oldFrequencyEntry->ScreenWidth) ) {
  2987. if (FrequencyEntry == NULL) {
  2988. //
  2989. // Remember the first mode that matched, ignoring
  2990. // the frequency.
  2991. //
  2992. FrequencyEntry = newFrequencyEntry;
  2993. }
  2994. if (newFrequencyEntry->ScreenFrequency <=
  2995. oldFrequencyEntry->ScreenFrequency) {
  2996. //
  2997. // Ideally, we would like to choose the frequency
  2998. // that is closest to, but less than or equal to,
  2999. // the requested frequency.
  3000. //
  3001. if ( (bestFrequencyEntry == NULL) ||
  3002. (bestFrequencyEntry->ScreenFrequency <
  3003. newFrequencyEntry->ScreenFrequency) ) {
  3004. bestFrequencyEntry = newFrequencyEntry;
  3005. }
  3006. }
  3007. }
  3008. }
  3009. //
  3010. // Use the preferred frequency setting, if there is one.
  3011. //
  3012. if (bestFrequencyEntry != NULL) {
  3013. FrequencyEntry = bestFrequencyEntry;
  3014. }
  3015. //
  3016. // If we have no valid mode, we must return failure
  3017. //
  3018. if (FrequencyEntry == NULL) {
  3019. VideoDebugPrint((1, "S3: no valid Fixed Frequency mode\n"));
  3020. status = ERROR_INVALID_PARAMETER;
  3021. break;
  3022. }
  3023. //
  3024. // Our new ModeEntry is the same as the old.
  3025. //
  3026. FrequencyEntry->ModeEntry = oldFrequencyEntry->ModeEntry;
  3027. FrequencyEntry->ModeValid = TRUE;
  3028. VideoDebugPrint((1, "S3: Selected Fixed Frequency mode from int 10:\n"));
  3029. VideoDebugPrint((1, " Bits Per Pel: %d\n", FrequencyEntry->BitsPerPel));
  3030. VideoDebugPrint((1, " Screen Width: %d\n", FrequencyEntry->ScreenWidth));
  3031. VideoDebugPrint((1, " Frequency: %d\n", FrequencyEntry->ScreenFrequency));
  3032. }
  3033. ModeEntry = FrequencyEntry->ModeEntry;
  3034. //
  3035. // NOTE:
  3036. // We have to set the ActiveFrequencyEntry since the SetHWMode
  3037. // function depends on this variable to set the CRTC registers.
  3038. // So lets set it here, and it will get reset to the same
  3039. // value after we set the mode.
  3040. //
  3041. hwDeviceExtension->ActiveFrequencyEntry = FrequencyEntry;
  3042. //
  3043. // If it failed, we may not be able to perform int10 due
  3044. // to BIOS emulation problems.
  3045. //
  3046. // Then just do a table mode-set. First we need to find the
  3047. // right mode table in the fixed Frequency tables.
  3048. //
  3049. //
  3050. // Select the Enhanced mode init depending upon the type of
  3051. // chip found.
  3052. if ( (hwDeviceExtension->BoardID == S3_NUMBER_NINE) &&
  3053. (ModeEntry->ModeInformation.VisScreenWidth == 1280) ) {
  3054. SetHWMode(hwDeviceExtension, S3_928_1280_Enhanced_Mode);
  3055. } else {
  3056. //
  3057. // Use defaults for all other boards
  3058. //
  3059. switch(hwDeviceExtension->ChipID) {
  3060. case S3_911:
  3061. SetHWMode(hwDeviceExtension, S3_911_Enhanced_Mode);
  3062. break;
  3063. case S3_801:
  3064. SetHWMode(hwDeviceExtension, S3_801_Enhanced_Mode);
  3065. break;
  3066. case S3_928:
  3067. SetHWMode(hwDeviceExtension, S3_928_Enhanced_Mode);
  3068. break;
  3069. case S3_864:
  3070. SetHWMode(hwDeviceExtension, S3_864_Enhanced_Mode);
  3071. Set864MemoryTiming(hwDeviceExtension);
  3072. break;
  3073. default:
  3074. VideoDebugPrint((1, "S3: Bad chip type for these boards"));
  3075. break;
  3076. }
  3077. }
  3078. }
  3079. //
  3080. // Call Int 10, function 0x4f06 to obtain the correct screen pitch
  3081. // of all S3's except the 911/924.
  3082. //
  3083. if ((hwDeviceExtension->ChipID != S3_911) &&
  3084. (hwDeviceExtension->BiosPresent)) {
  3085. VideoPortZeroMemory(&biosArguments,sizeof(VIDEO_X86_BIOS_ARGUMENTS));
  3086. biosArguments.Ebx = 0x0001;
  3087. biosArguments.Eax = 0x4f06;
  3088. status = VideoPortInt10(HwDeviceExtension, &biosArguments);
  3089. //
  3090. // Check to see if the Bios supported this function, and if so
  3091. // update the screen stride for this mode.
  3092. //
  3093. if ((status == NO_ERROR) && (biosArguments.Eax & 0xffff) == 0x004f) {
  3094. ModeEntry->ModeInformation.ScreenStride =
  3095. biosArguments.Ebx;
  3096. } else {
  3097. //
  3098. // We will use the default value in the mode table.
  3099. //
  3100. }
  3101. }
  3102. //
  3103. // Save the mode since we know the rest will work.
  3104. //
  3105. hwDeviceExtension->ActiveModeEntry = ModeEntry;
  3106. hwDeviceExtension->ActiveFrequencyEntry = FrequencyEntry;
  3107. //
  3108. // Record the fact that we are in an S3 mode, and
  3109. // that we need to be reset.
  3110. //
  3111. hwDeviceExtension->bNeedReset = TRUE;
  3112. //////////////////////////////////////////////////////////////////
  3113. // Update VIDEO_MODE_INFORMATION fields
  3114. //
  3115. // Now that we've set the mode, we now know the screen stride, and
  3116. // so can update some fields in the VIDEO_MODE_INFORMATION
  3117. // structure for this mode. The S3 display driver is expected to
  3118. // call IOCTL_VIDEO_QUERY_CURRENT_MODE to query these corrected
  3119. // values.
  3120. //
  3121. //
  3122. // Calculate the bitmap width.
  3123. // We currently assume the bitmap width is equivalent to the stride.
  3124. //
  3125. {
  3126. LONG x;
  3127. x = ModeEntry->ModeInformation.BitsPerPlane;
  3128. //
  3129. // you waste 16 bps even when you only use 15 for info.
  3130. //
  3131. if( x == 15 )
  3132. {
  3133. x = 16;
  3134. }
  3135. ModeEntry->ModeInformation.VideoMemoryBitmapWidth =
  3136. (ModeEntry->ModeInformation.ScreenStride * 8) / x;
  3137. }
  3138. //
  3139. // If we're in a mode that the BIOS doesn't really support, it may
  3140. // have reported back a bogus screen width.
  3141. //
  3142. if (ModeEntry->ModeInformation.VideoMemoryBitmapWidth <
  3143. ModeEntry->ModeInformation.VisScreenWidth) {
  3144. VideoDebugPrint((1, "S3: BIOS returned invalid screen width\n"));
  3145. status = ERROR_INVALID_PARAMETER;
  3146. break;
  3147. }
  3148. //
  3149. // Calculate the bitmap height.
  3150. //
  3151. ModeEntry->ModeInformation.VideoMemoryBitmapHeight =
  3152. hwDeviceExtension->AdapterMemorySize /
  3153. ModeEntry->ModeInformation.ScreenStride;
  3154. //
  3155. // The current position registers in the current S3 chips are
  3156. // limited to 12 bits of precision, with the range [0, 4095].
  3157. // Consequently, we must clamp the bitmap height so that we don't
  3158. // attempt to do any drawing beyond that range.
  3159. //
  3160. ModeEntry->ModeInformation.VideoMemoryBitmapHeight =
  3161. MIN(4096, ModeEntry->ModeInformation.VideoMemoryBitmapHeight);
  3162. //////////////////////////////////////////////////////////////////
  3163. // Unlock the S3 registers, we need to unlock the registers a second
  3164. // time since the interperter has them locked when it returns to us.
  3165. //
  3166. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x4838);
  3167. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xA039);
  3168. //////////////////////////////////////////////////////////////////
  3169. // Warm up the hardware for the new mode, and work around any
  3170. // BIOS bugs.
  3171. //
  3172. if ((hwDeviceExtension->ChipID == S3_801) &&
  3173. (hwDeviceExtension->AdapterMemorySize == 0x080000)) {
  3174. //
  3175. // On 801/805 chipsets with 512k of memory we must AND
  3176. // register 0x54 with 0x7.
  3177. //
  3178. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x54);
  3179. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3180. byte &= 0x07;
  3181. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3182. }
  3183. if (ModeEntry->ModeInformation.BitsPerPlane > 8) {
  3184. //
  3185. // Make sure 16-bit memory reads/writes are enabled.
  3186. //
  3187. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x31);
  3188. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3189. byte |= 0x04;
  3190. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3191. }
  3192. //
  3193. // Set the colours for the built-in S3 pointer.
  3194. //
  3195. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xff0e);
  3196. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x000f);
  3197. if (hwDeviceExtension->ChipID >= S3_864) {
  3198. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x45);
  3199. VideoPortReadPortUchar(CRT_DATA_REG);
  3200. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x4A);
  3201. VideoPortWritePortUchar(CRT_DATA_REG, 0xFF);
  3202. VideoPortWritePortUchar(CRT_DATA_REG, 0xFF);
  3203. VideoPortWritePortUchar(CRT_DATA_REG, 0xFF);
  3204. VideoPortWritePortUchar(CRT_DATA_REG, 0xFF);
  3205. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x45);
  3206. VideoPortReadPortUchar(CRT_DATA_REG);
  3207. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x4B);
  3208. VideoPortWritePortUchar(CRT_DATA_REG, 0x00);
  3209. VideoPortWritePortUchar(CRT_DATA_REG, 0x00);
  3210. VideoPortWritePortUchar(CRT_DATA_REG, 0x00);
  3211. VideoPortWritePortUchar(CRT_DATA_REG, 0x00);
  3212. }
  3213. if (hwDeviceExtension->ChipID > S3_911) {
  3214. //
  3215. // Set the address for the frame buffer window and set the window
  3216. // size.
  3217. //
  3218. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x59);
  3219. VideoPortWritePortUchar(CRT_DATA_REG,
  3220. (UCHAR) (hwDeviceExtension->PhysicalFrameAddress.LowPart >> 24));
  3221. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5A);
  3222. VideoPortWritePortUchar(CRT_DATA_REG,
  3223. (UCHAR) (hwDeviceExtension->PhysicalFrameAddress.LowPart >> 16));
  3224. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x58);
  3225. byte = VideoPortReadPortUchar(CRT_DATA_REG) & ~0x3;
  3226. switch (hwDeviceExtension->FrameLength)
  3227. {
  3228. case 0x400000:
  3229. case 0x800000:
  3230. byte |= 0x3;
  3231. break;
  3232. case 0x200000:
  3233. byte |= 0x2;
  3234. break;
  3235. case 0x100000:
  3236. byte |= 0x1;
  3237. break;
  3238. case 0x010000:
  3239. break;
  3240. default:
  3241. byte |= 0x3;
  3242. break;
  3243. }
  3244. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3245. }
  3246. if (hwDeviceExtension->Capabilities & CAPS_NEW_MMIO) {
  3247. //
  3248. // Enable 'new memory-mapped I/O':
  3249. //
  3250. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x53);
  3251. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3252. byte |= 0x18;
  3253. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3254. }
  3255. if ((ModeEntry->ModeInformation.DriverSpecificAttributeFlags &
  3256. CAPS_BT485_POINTER) &&
  3257. (hwDeviceExtension->ChipID == S3_928)) {
  3258. //
  3259. // Some of the Number Nine boards do not set the chip up correctly
  3260. // for an external cursor. We must OR in the bits, because if we
  3261. // don't the Metheus board will not initialize.
  3262. //
  3263. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x45);
  3264. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3265. byte |= 0x20;
  3266. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3267. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x55);
  3268. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3269. byte |= 0x20;
  3270. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3271. }
  3272. //
  3273. // Some BIOSes don't disable linear addressing by default, so
  3274. // make sure we do it here.
  3275. //
  3276. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x58);
  3277. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3278. byte &= ~0x10;
  3279. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3280. //
  3281. // Enable the Graphics engine.
  3282. //
  3283. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x40);
  3284. byte = VideoPortReadPortUchar(CRT_DATA_REG);
  3285. byte |= 0x01;
  3286. VideoPortWritePortUchar(CRT_DATA_REG, byte);
  3287. status = NO_ERROR;
  3288. break;
  3289. case IOCTL_VIDEO_SET_COLOR_REGISTERS:
  3290. VideoDebugPrint((2, "S3StartIO - SetColorRegs\n"));
  3291. clutBuffer = RequestPacket->InputBuffer;
  3292. status = S3SetColorLookup(HwDeviceExtension,
  3293. (PVIDEO_CLUT) RequestPacket->InputBuffer,
  3294. RequestPacket->InputBufferLength);
  3295. break;
  3296. case IOCTL_VIDEO_RESET_DEVICE:
  3297. VideoDebugPrint((2, "S3StartIO - RESET_DEVICE\n"));
  3298. //
  3299. // Prep the S3 card to return to a VGA mode
  3300. //
  3301. S3ResetHw(HwDeviceExtension, 0, 0);
  3302. VideoDebugPrint((2, "S3 RESET_DEVICE - About to do int10\n"));
  3303. //
  3304. // Do an Int10 to mode 3 will put the board to a known state.
  3305. //
  3306. VideoPortZeroMemory(&biosArguments, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
  3307. biosArguments.Eax = 0x0003;
  3308. VideoPortInt10(HwDeviceExtension,
  3309. &biosArguments);
  3310. VideoDebugPrint((2, "S3 RESET_DEVICE - Did int10\n"));
  3311. status = NO_ERROR;
  3312. break;
  3313. case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
  3314. VideoDebugPrint((2, "S3StartIO - ShareVideoMemory\n"));
  3315. if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION)) ||
  3316. (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
  3317. VideoDebugPrint((1, "IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INSUFFICIENT_BUFFER\n"));
  3318. status = ERROR_INSUFFICIENT_BUFFER;
  3319. break;
  3320. }
  3321. pShareMemory = RequestPacket->InputBuffer;
  3322. if ( (pShareMemory->ViewOffset > hwDeviceExtension->AdapterMemorySize) ||
  3323. ((pShareMemory->ViewOffset + pShareMemory->ViewSize) >
  3324. hwDeviceExtension->AdapterMemorySize) ) {
  3325. VideoDebugPrint((1, "IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INVALID_PARAMETER\n"));
  3326. status = ERROR_INVALID_PARAMETER;
  3327. break;
  3328. }
  3329. RequestPacket->StatusBlock->Information =
  3330. sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
  3331. //
  3332. // Beware: the input buffer and the output buffer are the same
  3333. // buffer, and therefore data should not be copied from one to the
  3334. // other
  3335. //
  3336. virtualAddress = pShareMemory->ProcessHandle;
  3337. sharedViewSize = pShareMemory->ViewSize;
  3338. inIoSpace = hwDeviceExtension->PhysicalFrameIoSpace;
  3339. //
  3340. // NOTE: we are ignoring ViewOffset
  3341. //
  3342. shareAddress.QuadPart =
  3343. hwDeviceExtension->PhysicalFrameAddress.QuadPart;
  3344. if (hwDeviceExtension->Capabilities & CAPS_NEW_MMIO) {
  3345. //
  3346. // With 'new memory-mapped I/O', the frame buffer is always
  3347. // mapped in linearly.
  3348. //
  3349. //
  3350. // Performance:
  3351. //
  3352. // Enable USWC on the P6 processor.
  3353. // We only do it for the frame buffer - memory mapped registers can
  3354. // not be mapped USWC because write combining the registers would
  3355. // cause very bad things to happen !
  3356. //
  3357. inIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  3358. //
  3359. // Unlike the MAP_MEMORY IOCTL, in this case we can not map extra
  3360. // address space since the application could actually use the
  3361. // pointer we return to it to touch locations in the address space
  3362. // that do not have actual video memory in them.
  3363. //
  3364. // An app doing this would cause the machine to crash.
  3365. //
  3366. // However, because the caching policy for USWC in the P6 is on
  3367. // *physical* addresses, this memory mapping will "piggy back" on
  3368. // the normal frame buffer mapping, and therefore also benefit
  3369. // from USWC ! Cool side-effect !!!
  3370. //
  3371. status = VideoPortMapMemory(hwDeviceExtension,
  3372. shareAddress,
  3373. &sharedViewSize,
  3374. &inIoSpace,
  3375. &virtualAddress);
  3376. pShareMemoryInformation = RequestPacket->OutputBuffer;
  3377. pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
  3378. pShareMemoryInformation->VirtualAddress = virtualAddress;
  3379. pShareMemoryInformation->SharedViewSize = sharedViewSize;
  3380. } else {
  3381. status = ERROR_INVALID_PARAMETER;
  3382. }
  3383. break;
  3384. case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
  3385. VideoDebugPrint((2, "S3StartIO - UnshareVideoMemory\n"));
  3386. if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY)) {
  3387. status = ERROR_INSUFFICIENT_BUFFER;
  3388. break;
  3389. }
  3390. pShareMemory = RequestPacket->InputBuffer;
  3391. status = VideoPortUnmapMemory(hwDeviceExtension,
  3392. pShareMemory->RequestedVirtualAddress,
  3393. pShareMemory->ProcessHandle);
  3394. break;
  3395. case IOCTL_VIDEO_S3_QUERY_STREAMS_PARAMETERS:
  3396. VideoDebugPrint((2, "S3StartIO - QueryStreamsParameters\n"));
  3397. //
  3398. // This is a private, non-standard IOCTL so that the display driver
  3399. // can query the appropriate minimum stretch ratio and FIFO value
  3400. // for using the streams overlay processor in a particular mode.
  3401. //
  3402. if ((RequestPacket->InputBufferLength < sizeof(VIDEO_QUERY_STREAMS_MODE)) ||
  3403. (RequestPacket->OutputBufferLength < sizeof(VIDEO_QUERY_STREAMS_PARAMETERS))) {
  3404. status = ERROR_INSUFFICIENT_BUFFER;
  3405. break;
  3406. }
  3407. status = QueryStreamsParameters(hwDeviceExtension,
  3408. RequestPacket->InputBuffer,
  3409. RequestPacket->OutputBuffer);
  3410. if (status == NO_ERROR) {
  3411. RequestPacket->StatusBlock->Information =
  3412. sizeof(VIDEO_QUERY_STREAMS_PARAMETERS);
  3413. }
  3414. break;
  3415. case IOCTL_PRIVATE_GET_FUNCTIONAL_UNIT:
  3416. VideoDebugPrint((2, "S3StartIO - GetFunctionalUnit\n"));
  3417. if (RequestPacket->OutputBufferLength <
  3418. (RequestPacket->StatusBlock->Information =
  3419. sizeof(FUNCTIONAL_UNIT_INFO)) ) {
  3420. status = ERROR_INSUFFICIENT_BUFFER;
  3421. } else {
  3422. ((PFUNCTIONAL_UNIT_INFO)RequestPacket->OutputBuffer)->FunctionalUnitID =
  3423. hwDeviceExtension->FunctionalUnitID;
  3424. ((PFUNCTIONAL_UNIT_INFO)RequestPacket->OutputBuffer)->Reserved = 0;
  3425. status = NO_ERROR;
  3426. }
  3427. break;
  3428. //
  3429. // if we get here, an invalid IoControlCode was specified.
  3430. //
  3431. default:
  3432. VideoDebugPrint((1, "Fell through S3 startIO routine - invalid command\n"));
  3433. status = ERROR_INVALID_FUNCTION;
  3434. break;
  3435. }
  3436. VideoDebugPrint((2, "Leaving S3 startIO routine\n"));
  3437. RequestPacket->StatusBlock->Status = status;
  3438. return TRUE;
  3439. } // end S3StartIO()
  3440. VP_STATUS
  3441. S3SetColorLookup(
  3442. PHW_DEVICE_EXTENSION HwDeviceExtension,
  3443. PVIDEO_CLUT ClutBuffer,
  3444. ULONG ClutBufferSize
  3445. )
  3446. /*++
  3447. Routine Description:
  3448. This routine sets a specified portion of the color lookup table settings.
  3449. Arguments:
  3450. HwDeviceExtension - Pointer to the miniport driver's device extension.
  3451. ClutBufferSize - Length of the input buffer supplied by the user.
  3452. ClutBuffer - Pointer to the structure containing the color lookup table.
  3453. Return Value:
  3454. None.
  3455. --*/
  3456. {
  3457. USHORT i;
  3458. //
  3459. // Check if the size of the data in the input buffer is large enough.
  3460. //
  3461. if ( (ClutBufferSize < sizeof(VIDEO_CLUT) - sizeof(ULONG)) ||
  3462. (ClutBufferSize < sizeof(VIDEO_CLUT) +
  3463. (sizeof(ULONG) * (ClutBuffer->NumEntries - 1)) ) ) {
  3464. return ERROR_INSUFFICIENT_BUFFER;
  3465. }
  3466. //
  3467. // Check to see if the parameters are valid.
  3468. //
  3469. if ( (ClutBuffer->NumEntries == 0) ||
  3470. (ClutBuffer->FirstEntry > VIDEO_MAX_COLOR_REGISTER) ||
  3471. (ClutBuffer->FirstEntry + ClutBuffer->NumEntries >
  3472. VIDEO_MAX_COLOR_REGISTER + 1) ) {
  3473. return ERROR_INVALID_PARAMETER;
  3474. }
  3475. if (HwDeviceExtension->Capabilities & CAPS_WAIT_ON_PALETTE) {
  3476. //
  3477. // On some DACs, the hardware pointer 'sparkles' unless we first
  3478. // wait for vertical retrace.
  3479. //
  3480. while (VideoPortReadPortUchar(SYSTEM_CONTROL_REG) & 0x08)
  3481. ;
  3482. while (!(VideoPortReadPortUchar(SYSTEM_CONTROL_REG) & 0x08))
  3483. ;
  3484. //
  3485. // Then pause a little more. 0x400 is the lowest value that made
  3486. // any remaining sparkle disappear on my PCI P90.
  3487. //
  3488. // Unfortunately, I have discovered that this is not a complete
  3489. // solution -- there is still sparkle if the mouse is positioned
  3490. // near the top of the screen. A more complete solution would
  3491. // probably be to turn the mouse off entirely if it's in that
  3492. // range.
  3493. //
  3494. for (i = 0x400; i != 0; i--) {
  3495. VideoPortReadPortUchar(SYSTEM_CONTROL_REG);
  3496. }
  3497. }
  3498. //
  3499. // Set CLUT registers directly on the hardware
  3500. //
  3501. for (i = 0; i < ClutBuffer->NumEntries; i++) {
  3502. VideoPortWritePortUchar(DAC_ADDRESS_WRITE_PORT, (UCHAR) (ClutBuffer->FirstEntry + i));
  3503. VideoPortWritePortUchar(DAC_DATA_REG_PORT, (UCHAR) (ClutBuffer->LookupTable[i].RgbArray.Red));
  3504. VideoPortWritePortUchar(DAC_DATA_REG_PORT, (UCHAR) (ClutBuffer->LookupTable[i].RgbArray.Green));
  3505. VideoPortWritePortUchar(DAC_DATA_REG_PORT, (UCHAR) (ClutBuffer->LookupTable[i].RgbArray.Blue));
  3506. }
  3507. return NO_ERROR;
  3508. } // end S3SetColorLookup()
  3509. VOID
  3510. SetHWMode(
  3511. PHW_DEVICE_EXTENSION HwDeviceExtension,
  3512. PUSHORT pusCmdStream
  3513. )
  3514. /*++
  3515. Routine Description:
  3516. Interprets the appropriate command array to set up VGA registers for the
  3517. requested mode. Typically used to set the VGA into a particular mode by
  3518. programming all of the registers
  3519. Arguments:
  3520. HwDeviceExtension - Pointer to the miniport driver's device extension.
  3521. pusCmdStream - pointer to a command stream to execute.
  3522. Return Value:
  3523. The status of the operation (can only fail on a bad command); TRUE for
  3524. success, FALSE for failure.
  3525. --*/
  3526. {
  3527. ULONG ulCmd;
  3528. ULONG ulPort;
  3529. UCHAR jValue;
  3530. USHORT usValue;
  3531. ULONG culCount;
  3532. ULONG ulIndex,
  3533. Microseconds;
  3534. ULONG mappedAddressIndex = 2; // fool Prefix
  3535. ULONG mappedAddressOffset = 0x3c0; // fool Prefix
  3536. //
  3537. // If there is no command string, just return
  3538. //
  3539. if (!pusCmdStream) {
  3540. return;
  3541. }
  3542. while ((ulCmd = *pusCmdStream++) != EOD) {
  3543. //
  3544. // Determine major command type
  3545. //
  3546. switch (ulCmd & 0xF0) {
  3547. case RESET_CR5C:
  3548. if (HwDeviceExtension->BiosPresent == FALSE)
  3549. {
  3550. UCHAR value, oldvalue;
  3551. //
  3552. // Reset the upper four bits of the General Out Port Reg
  3553. // with the value it had after the POST.
  3554. //
  3555. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5c);
  3556. value = VideoPortReadPortUchar(CRT_DATA_REG);
  3557. oldvalue = value;
  3558. value &= 0x0f;
  3559. value |= HwDeviceExtension->CR5C;
  3560. VideoPortWritePortUchar(CRT_DATA_REG, value);
  3561. VideoDebugPrint((2, "S3: CRC5 was 0x%x and we "
  3562. "have set it to 0x%x\n",
  3563. oldvalue, value));
  3564. }
  3565. break;
  3566. case SELECTACCESSRANGE:
  3567. //
  3568. // Determine which address range to use for commands that follow
  3569. //
  3570. switch (ulCmd & 0x0F) {
  3571. case VARIOUSVGA:
  3572. //
  3573. // Used for registers in the range 0x3c0 - 0x3cf
  3574. //
  3575. mappedAddressIndex = 2;
  3576. mappedAddressOffset = 0x3c0;
  3577. break;
  3578. case SYSTEMCONTROL:
  3579. //
  3580. // Used for registers in the range 0x3d4 - 0x3df
  3581. //
  3582. mappedAddressIndex = 3;
  3583. mappedAddressOffset = 0x3d4;
  3584. break;
  3585. case ADVANCEDFUNCTIONCONTROL:
  3586. //
  3587. // Used for registers in the range 0x4ae8-0x4ae9
  3588. //
  3589. mappedAddressIndex = 5;
  3590. mappedAddressOffset = 0x4ae8;
  3591. break;
  3592. }
  3593. break;
  3594. case OWM:
  3595. ulPort = *pusCmdStream++;
  3596. culCount = *pusCmdStream++;
  3597. while (culCount--) {
  3598. usValue = *pusCmdStream++;
  3599. VideoPortWritePortUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort),
  3600. usValue);
  3601. }
  3602. break;
  3603. // Basic input/output command
  3604. case INOUT:
  3605. // Determine type of inout instruction
  3606. if (!(ulCmd & IO)) {
  3607. // Out instruction
  3608. // Single or multiple outs?
  3609. if (!(ulCmd & MULTI)) {
  3610. // Single out
  3611. // Byte or word out?
  3612. if (!(ulCmd & BW)) {
  3613. // Single byte out
  3614. ulPort = *pusCmdStream++;
  3615. jValue = (UCHAR) *pusCmdStream++;
  3616. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3617. jValue);
  3618. } else {
  3619. // Single word out
  3620. ulPort = *pusCmdStream++;
  3621. usValue = *pusCmdStream++;
  3622. VideoPortWritePortUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort),
  3623. usValue);
  3624. }
  3625. } else {
  3626. // Output a string of values
  3627. // Byte or word outs?
  3628. if (!(ulCmd & BW)) {
  3629. // String byte outs. Do in a loop; can't use
  3630. // VideoPortWritePortBufferUchar because the data
  3631. // is in USHORT form
  3632. ulPort = *pusCmdStream++;
  3633. culCount = *pusCmdStream++;
  3634. while (culCount--) {
  3635. jValue = (UCHAR) *pusCmdStream++;
  3636. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3637. jValue);
  3638. }
  3639. } else {
  3640. // String word outs
  3641. ulPort = *pusCmdStream++;
  3642. culCount = *pusCmdStream++;
  3643. VideoPortWritePortBufferUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort),
  3644. pusCmdStream,
  3645. culCount);
  3646. pusCmdStream += culCount;
  3647. }
  3648. }
  3649. } else {
  3650. // In instruction
  3651. // Currently, string in instructions aren't supported; all
  3652. // in instructions are handled as single-byte ins
  3653. // Byte or word in?
  3654. if (!(ulCmd & BW)) {
  3655. // Single byte in
  3656. ulPort = *pusCmdStream++;
  3657. jValue = VideoPortReadPortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort);
  3658. } else {
  3659. // Single word in
  3660. ulPort = *pusCmdStream++;
  3661. usValue = VideoPortReadPortUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort));
  3662. }
  3663. }
  3664. break;
  3665. // Higher-level input/output commands
  3666. case METAOUT:
  3667. // Determine type of metaout command, based on minor command field
  3668. switch (ulCmd & 0x0F) {
  3669. // Indexed outs
  3670. case INDXOUT:
  3671. ulPort = *pusCmdStream++;
  3672. culCount = *pusCmdStream++;
  3673. ulIndex = *pusCmdStream++;
  3674. while (culCount--) {
  3675. usValue = (USHORT) (ulIndex +
  3676. (((ULONG)(*pusCmdStream++)) << 8));
  3677. VideoPortWritePortUshort((PUSHORT)((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort),
  3678. usValue);
  3679. ulIndex++;
  3680. }
  3681. break;
  3682. // Masked out (read, AND, XOR, write)
  3683. case MASKOUT:
  3684. ulPort = *pusCmdStream++;
  3685. jValue = VideoPortReadPortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort);
  3686. jValue &= *pusCmdStream++;
  3687. jValue ^= *pusCmdStream++;
  3688. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3689. jValue);
  3690. break;
  3691. // Attribute Controller out
  3692. case ATCOUT:
  3693. ulPort = *pusCmdStream++;
  3694. culCount = *pusCmdStream++;
  3695. ulIndex = *pusCmdStream++;
  3696. while (culCount--) {
  3697. // Write Attribute Controller index
  3698. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3699. (UCHAR)ulIndex);
  3700. // Write Attribute Controller data
  3701. jValue = (UCHAR) *pusCmdStream++;
  3702. VideoPortWritePortUchar((PUCHAR)HwDeviceExtension->MappedAddress[mappedAddressIndex] - mappedAddressOffset + ulPort,
  3703. jValue);
  3704. ulIndex++;
  3705. }
  3706. break;
  3707. case DELAY:
  3708. Microseconds = (ULONG) *pusCmdStream++;
  3709. VideoPortStallExecution(Microseconds);
  3710. break;
  3711. case VBLANK:
  3712. Wait_VSync(HwDeviceExtension);
  3713. break;
  3714. //
  3715. // This function in setmode is pageable !!!
  3716. // it is only used to set high res modes.
  3717. //
  3718. case SETCLK:
  3719. Set_Oem_Clock(HwDeviceExtension);
  3720. break;
  3721. case SETCRTC:
  3722. //
  3723. // NOTE:
  3724. // beware: recursive call ...
  3725. //
  3726. SetHWMode(HwDeviceExtension,
  3727. HwDeviceExtension->ActiveFrequencyEntry->
  3728. Fixed.CRTCTable[HwDeviceExtension->ChipID]);
  3729. break;
  3730. // None of the above; error
  3731. default:
  3732. return;
  3733. }
  3734. break;
  3735. // NOP
  3736. case NCMD:
  3737. break;
  3738. // Unknown command; error
  3739. default:
  3740. return;
  3741. }
  3742. }
  3743. return;
  3744. } // end SetHWMode()
  3745. LONG
  3746. CompareRom(
  3747. PUCHAR Rom,
  3748. PUCHAR String
  3749. )
  3750. /*++
  3751. Routine Description:
  3752. Compares a string to that in the ROM. Returns -1 if Rom < String, 0
  3753. if Rom == String, 1 if Rom > String.
  3754. Arguments:
  3755. Rom - Rom pointer.
  3756. String - String pointer.
  3757. Return Value:
  3758. None
  3759. --*/
  3760. {
  3761. UCHAR jString;
  3762. UCHAR jRom;
  3763. while (*String) {
  3764. jString = *String;
  3765. jRom = VideoPortReadRegisterUchar(Rom);
  3766. if (jRom != jString) {
  3767. return(jRom < jString ? -1 : 1);
  3768. }
  3769. String++;
  3770. Rom++;
  3771. }
  3772. return(0);
  3773. }
  3774. VOID
  3775. ZeroMemAndDac(
  3776. PHW_DEVICE_EXTENSION HwDeviceExtension
  3777. )
  3778. /*++
  3779. Routine Description:
  3780. Initialize the DAC to 0 (black).
  3781. Arguments:
  3782. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  3783. Return Value:
  3784. None
  3785. --*/
  3786. {
  3787. ULONG i;
  3788. //
  3789. // Turn off the screen at the DAC.
  3790. //
  3791. VideoPortWritePortUchar(DAC_PIXEL_MASK_REG, 0x0);
  3792. for (i = 0; i < 256; i++) {
  3793. VideoPortWritePortUchar(DAC_ADDRESS_WRITE_PORT, (UCHAR)i);
  3794. VideoPortWritePortUchar(DAC_DATA_REG_PORT, 0x0);
  3795. VideoPortWritePortUchar(DAC_DATA_REG_PORT, 0x0);
  3796. VideoPortWritePortUchar(DAC_DATA_REG_PORT, 0x0);
  3797. }
  3798. //
  3799. // Zero the memory.
  3800. //
  3801. //
  3802. // The zeroing of video memory should be implemented at a later time to
  3803. // ensure that no information remains in video memory at shutdown, or
  3804. // while swtiching to fullscren mode (for security reasons).
  3805. //
  3806. //
  3807. // Turn on the screen at the DAC
  3808. //
  3809. VideoPortWritePortUchar(DAC_PIXEL_MASK_REG, 0x0ff);
  3810. return;
  3811. }
  3812. VP_STATUS
  3813. Set_Oem_Clock(
  3814. PHW_DEVICE_EXTENSION HwDeviceExtension
  3815. )
  3816. /*++
  3817. Routine Description:
  3818. Set the clock chip on each of the supported cards.
  3819. Arguments:
  3820. HwDeviceExtension - Pointer to the miniport driver's device extension.
  3821. Return Value:
  3822. Always TRUE
  3823. --*/
  3824. {
  3825. ULONG ul;
  3826. ULONG screen_width;
  3827. UCHAR cr5C;
  3828. ULONG clock_numbers;
  3829. switch(HwDeviceExtension->BoardID) {
  3830. case S3_NUMBER_NINE:
  3831. VideoPortStallExecution(1000);
  3832. // Jerry said to make the M clock not multiple of the P clock
  3833. // on the 3 meg (level 12) board. This solves the shimmy
  3834. // problem.
  3835. if (HwDeviceExtension->AdapterMemorySize == 0x00300000) {
  3836. ul = 49000000;
  3837. clock_numbers = calc_clock(ul, 3);
  3838. set_clock(HwDeviceExtension, clock_numbers);
  3839. VideoPortStallExecution(3000);
  3840. }
  3841. ul = HwDeviceExtension->ActiveFrequencyEntry->Fixed.Clock;
  3842. clock_numbers = calc_clock(ul, 2);
  3843. set_clock(HwDeviceExtension, clock_numbers);
  3844. VideoPortStallExecution(3000);
  3845. break;
  3846. case S3_IBM_PS2:
  3847. // Read the current screen frequency and width
  3848. ul = HwDeviceExtension->ActiveFrequencyEntry->ScreenFrequency;
  3849. screen_width = HwDeviceExtension->ActiveFrequencyEntry->ScreenWidth;
  3850. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3851. cr5C = VideoPortReadPortUchar( CRT_DATA_REG );
  3852. cr5C &= 0xCF;
  3853. switch (screen_width) {
  3854. case 640:
  3855. if (ul == 60) {
  3856. cr5C |= 0x00;
  3857. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3858. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3859. } else { // 72Hz
  3860. cr5C |= 0x20;
  3861. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3862. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3863. } /* endif */
  3864. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3865. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x00);
  3866. VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)0xEF);
  3867. break;
  3868. case 800:
  3869. if (ul == 60) {
  3870. cr5C |= 0x00;
  3871. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3872. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3873. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3874. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x05);
  3875. } else { // 72Hz
  3876. cr5C |= 0x10;
  3877. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3878. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3879. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3880. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x02);
  3881. } /* endif */
  3882. VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)0x2F);
  3883. break;
  3884. case 1024:
  3885. if (ul == 60) {
  3886. cr5C |= 0x00;
  3887. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3888. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3889. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3890. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x05);
  3891. VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)0xEF);
  3892. } else { // 72Hz
  3893. cr5C |= 0x20;
  3894. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5C);
  3895. VideoPortWritePortUchar(CRT_DATA_REG, cr5C);
  3896. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3897. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)0x05);
  3898. VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)0x2F);
  3899. } /* endif */
  3900. break;
  3901. default:
  3902. break;
  3903. } /* endswitch */
  3904. break;
  3905. //
  3906. // Generic S3 board.
  3907. //
  3908. case S3_GENERIC:
  3909. default:
  3910. //
  3911. // If the board has an SDAC then assume it also has an 864 (for now)
  3912. // this could be made better later by checking ChipID too, it appears
  3913. // that the display driver will need to be made 864 specific to get
  3914. // the best possible performance and this one may need to be specific
  3915. // before this is all done so I am not making it bulletproof yet
  3916. //
  3917. if( HwDeviceExtension->DacID == S3_SDAC ) {
  3918. InitializeSDAC( HwDeviceExtension );
  3919. } else {
  3920. ul = HwDeviceExtension->ActiveFrequencyEntry->Fixed.Clock;
  3921. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x42);
  3922. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) ul);
  3923. }
  3924. break;
  3925. }
  3926. return TRUE;
  3927. }
  3928. VP_STATUS
  3929. Wait_VSync(
  3930. PHW_DEVICE_EXTENSION HwDeviceExtension
  3931. )
  3932. /*++
  3933. Routine Description:
  3934. Wait for the vertical blanking interval on the chip
  3935. Arguments:
  3936. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  3937. Return Value:
  3938. Always TRUE
  3939. --*/
  3940. {
  3941. ULONG i;
  3942. UCHAR byte;
  3943. // It's real possible that this routine will get called
  3944. // when the 911 is in a zombie state, meaning there is no
  3945. // vertical sync being generated. This is why we have some long
  3946. // time out loops here.
  3947. // First wait for getting into vertical blanking.
  3948. for (i = 0; i < 0x100000; i++) {
  3949. byte = VideoPortReadPortUchar(SYSTEM_CONTROL_REG);
  3950. if (byte & 0x08)
  3951. break;
  3952. }
  3953. //
  3954. // We are either in a vertical blaning interval or we have timmed out.
  3955. // Wait for the Vertical display interval.
  3956. // This is done to make sure we exit this routine at the beginning
  3957. // of a vertical blanking interval, and not in the middle or near
  3958. // the end of one.
  3959. //
  3960. for (i = 0; i < 0x100000; i++) {
  3961. byte = VideoPortReadPortUchar(SYSTEM_CONTROL_REG);
  3962. if (!(byte & 0x08))
  3963. break;
  3964. }
  3965. //
  3966. // Now wait to get into the vertical blank interval again.
  3967. //
  3968. for (i = 0; i < 0x100000; i++) {
  3969. byte = VideoPortReadPortUchar(SYSTEM_CONTROL_REG);
  3970. if (byte & 0x08)
  3971. break;
  3972. }
  3973. return (TRUE);
  3974. }
  3975. BOOLEAN
  3976. Set864MemoryTiming(
  3977. PHW_DEVICE_EXTENSION HwDeviceExtension
  3978. )
  3979. /*++
  3980. Routine Description:
  3981. Sets L, M and N timing parameters, also sets and enables the
  3982. Start Display FIFO register
  3983. Arguments:
  3984. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  3985. Return Value:
  3986. TRUE if success, FALSE if failure
  3987. --*/
  3988. {
  3989. ULONG MIndex, ColorDepth, ScreenWidth, failure = 0;
  3990. USHORT data16;
  3991. UCHAR data8, old38, old39;
  3992. //
  3993. // unlock registers
  3994. //
  3995. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x38);
  3996. old38 = VideoPortReadPortUchar( CRT_DATA_REG);
  3997. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x39);
  3998. old39 = VideoPortReadPortUchar( CRT_DATA_REG);
  3999. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0x4838);
  4000. VideoPortWritePortUshort(CRT_ADDRESS_REG, 0xA039);
  4001. //
  4002. // make sure this is an 864
  4003. //
  4004. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x30);
  4005. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4006. if ((data8 & 0xf0) != 0xc0)
  4007. failure = 1;
  4008. //
  4009. // make sure there is an entry in the M parameter table for this mode
  4010. //
  4011. MIndex = (HwDeviceExtension->AdapterMemorySize < 0x200000) ? 0 : 12;
  4012. switch (HwDeviceExtension->ActiveFrequencyEntry->ScreenWidth) {
  4013. case 640:
  4014. MIndex += 0;
  4015. break;
  4016. case 800:
  4017. MIndex += 4;
  4018. break;
  4019. case 1024:
  4020. MIndex += 8;
  4021. break;
  4022. default:
  4023. failure = 1;
  4024. break;
  4025. }
  4026. switch (HwDeviceExtension->ActiveFrequencyEntry->BitsPerPel) {
  4027. case 8:
  4028. MIndex += 0;
  4029. break;
  4030. case 16:
  4031. MIndex += 2;
  4032. break;
  4033. default:
  4034. failure = 1;
  4035. break;
  4036. }
  4037. switch (HwDeviceExtension->ActiveFrequencyEntry->ScreenFrequency) {
  4038. case 60:
  4039. MIndex += 0;
  4040. break;
  4041. case 72:
  4042. MIndex += 1;
  4043. break;
  4044. default:
  4045. failure = 1;
  4046. break;
  4047. }
  4048. if (failure) {
  4049. // reset lock registers to previous state
  4050. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x38);
  4051. VideoPortWritePortUchar(CRT_DATA_REG, old38);
  4052. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x39);
  4053. VideoPortWritePortUchar(CRT_DATA_REG, old39);
  4054. return (FALSE);
  4055. }
  4056. //
  4057. // set and enable L parameter, 1 Mb frame buffer configurations are
  4058. // restricted to a 32 bit data path and therefore make twice as many
  4059. // transfers
  4060. //
  4061. ScreenWidth = HwDeviceExtension->ActiveFrequencyEntry->ScreenWidth;
  4062. ColorDepth = HwDeviceExtension->ActiveFrequencyEntry->BitsPerPel;
  4063. if (HwDeviceExtension->AdapterMemorySize < 0x200000)
  4064. data16 = (USHORT) ((ScreenWidth * (ColorDepth / 8)) / 4);
  4065. else
  4066. data16 = (USHORT) ((ScreenWidth * (ColorDepth / 8)) / 8);
  4067. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x62);
  4068. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) (data16 & 0xff));
  4069. data16 = (data16 >> 8) & 0x07;
  4070. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x61);
  4071. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) ((data16 & 0x07) | 0x80));
  4072. //
  4073. // set Start Display FIFO register
  4074. //
  4075. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5d);
  4076. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4077. data16 = data8 & 0x01;
  4078. data16 <<= 8;
  4079. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x00);
  4080. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4081. data16 |= data8;
  4082. data16 -= 5; // typical CR3B is CR0 - 5 (with extension bits)
  4083. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x3b);
  4084. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) (data16 & 0xff));
  4085. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x5d);
  4086. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4087. data8 &= 0xbf;
  4088. data8 = data8 | (UCHAR) ((data16 & 0x100) >> 2);
  4089. VideoPortWritePortUchar(CRT_DATA_REG, data8);
  4090. //
  4091. // enable Start Display FIFO register
  4092. //
  4093. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x34);
  4094. data8 = VideoPortReadPortUchar(CRT_DATA_REG);
  4095. data8 |= 0x10;
  4096. VideoPortWritePortUchar(CRT_DATA_REG, data8);
  4097. //
  4098. // set M parameter
  4099. //
  4100. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x54);
  4101. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) MParameterTable[MIndex]);
  4102. //
  4103. // set N parameter
  4104. //
  4105. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x60);
  4106. VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR) 0xff);
  4107. //
  4108. // restore lock registers to previous state
  4109. //
  4110. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x38);
  4111. VideoPortWritePortUchar(CRT_DATA_REG, old38);
  4112. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x39);
  4113. VideoPortWritePortUchar(CRT_DATA_REG, old39);
  4114. return (TRUE);
  4115. }
  4116. VP_STATUS
  4117. QueryStreamsParameters(
  4118. PHW_DEVICE_EXTENSION HwDeviceExtension,
  4119. VIDEO_QUERY_STREAMS_MODE *pStreamsMode,
  4120. VIDEO_QUERY_STREAMS_PARAMETERS *pStreamsParameters
  4121. )
  4122. /*++
  4123. Routine Description:
  4124. Queries various attributes of the card for later determine streams
  4125. parameters for minimum horizontal stretch and FIFO control
  4126. Arguments:
  4127. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  4128. RefreshRate - Supplies the exact refresh rate (a default rate of '1' will
  4129. not do).
  4130. pWidthRatio - Returns the corresponding minimum horizontal stretch factor,
  4131. expressed as a multiple of 1000.
  4132. pFifoValue - Returns the corresponding FIFO setting.
  4133. Return Value:
  4134. TRUE if success, FALSE if failure
  4135. --*/
  4136. {
  4137. ULONG BitsPerPel;
  4138. ULONG ScreenWidth;
  4139. ULONG RefreshRate;
  4140. UCHAR MemoryFlags;
  4141. ULONG n;
  4142. ULONG m;
  4143. ULONG r;
  4144. ULONG mclock;
  4145. ULONG MemorySpeed;
  4146. K2TABLE* pEntry;
  4147. ULONG MatchRefreshRate;
  4148. ULONG MatchMemorySpeed;
  4149. //
  4150. // Copy the input parameters and round 15 up to 16.
  4151. //
  4152. BitsPerPel = (pStreamsMode->BitsPerPel + 1) & ~7;
  4153. ScreenWidth = pStreamsMode->ScreenWidth;
  4154. RefreshRate = pStreamsMode->RefreshRate;
  4155. //
  4156. // Determine the memory type and memory size.
  4157. //
  4158. VideoPortWritePortUchar(CRT_ADDRESS_REG, 0x36);
  4159. MemoryFlags = (VideoPortReadPortUchar(CRT_DATA_REG) & 0x0c) >> 2;
  4160. if (HwDeviceExtension->AdapterMemorySize != 0x100000) {
  4161. MemoryFlags |= MEM_2MB;
  4162. }
  4163. //
  4164. // Unlock sequencer registers.
  4165. //
  4166. VideoPortWritePortUshort(SEQ_ADDRESS_REG, 0x0608);
  4167. //
  4168. // Get memory speed, using some inexplicable code from S3.
  4169. //
  4170. VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x10);
  4171. n = VideoPortReadPortUchar(SEQ_DATA_REG);
  4172. VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x11);
  4173. m = VideoPortReadPortUchar(SEQ_DATA_REG) & 0x7f;
  4174. MemorySpeed = n | (m << 8);
  4175. switch (MemorySpeed) {
  4176. case 0x1A40: // Known power-on default value
  4177. case 0x2841: // 50MHz
  4178. MemorySpeed = 50;
  4179. break;
  4180. case 0x4142: // 60MHz
  4181. MemorySpeed = 60;
  4182. break;
  4183. case 0x3643: // 40MHz
  4184. MemorySpeed = 40;
  4185. break;
  4186. default: // All others:
  4187. r = (n >> 5) & 0x03;
  4188. if (r == 0)
  4189. r = 1;
  4190. else
  4191. r = 2 << (r-1);
  4192. n = n & 0x1f;
  4193. mclock = ((m + 2) * 14318L) / (((n + 2) * r) * 100L);
  4194. MemorySpeed = mclock / 10;
  4195. if ((mclock % 10) >= 5)
  4196. MemorySpeed++;
  4197. if (MemorySpeed < 40)
  4198. MemorySpeed = 40;
  4199. break;
  4200. }
  4201. pEntry = &K2WidthRatio[0];
  4202. MatchRefreshRate = 0;
  4203. MatchMemorySpeed = 0;
  4204. while (pEntry->ScreenWidth != 0) {
  4205. //
  4206. // First find an exact match based on resolution, bits-per-pel,
  4207. // memory type and size.
  4208. //
  4209. if ((pEntry->ScreenWidth == ScreenWidth) &&
  4210. (pEntry->BitsPerPel == BitsPerPel) &&
  4211. (pEntry->MemoryFlags == MemoryFlags)) {
  4212. //
  4213. // Now find the entry with the refresh rate and memory speed the
  4214. // closest to, but not more than, our refresh rate and memory
  4215. // speed.
  4216. //
  4217. if ((pEntry->RefreshRate <= RefreshRate) &&
  4218. (pEntry->RefreshRate >= MatchRefreshRate) &&
  4219. (pEntry->MemorySpeed <= MemorySpeed) &&
  4220. (pEntry->MemorySpeed >= MatchMemorySpeed)) {
  4221. MatchRefreshRate = pEntry->RefreshRate;
  4222. MatchMemorySpeed = pEntry->MemorySpeed;
  4223. pStreamsParameters->MinOverlayStretch = pEntry->Value;
  4224. }
  4225. }
  4226. pEntry++;
  4227. }
  4228. if (MatchRefreshRate == 0) {
  4229. return ERROR_INVALID_PARAMETER;
  4230. }
  4231. pEntry = &K2FifoValue[0];
  4232. MatchRefreshRate = 0;
  4233. MatchMemorySpeed = 0;
  4234. while (pEntry->ScreenWidth != 0) {
  4235. //
  4236. // First find an exact match based on resolution, bits-per-pel,
  4237. // memory type and size.
  4238. //
  4239. if ((pEntry->ScreenWidth == ScreenWidth) &&
  4240. (pEntry->BitsPerPel == BitsPerPel) &&
  4241. (pEntry->MemoryFlags == MemoryFlags)) {
  4242. //
  4243. // Now find the entry with the refresh rate and memory speed the
  4244. // closest to, but not more than, our refresh rate and memory
  4245. // speed.
  4246. //
  4247. if ((pEntry->RefreshRate <= RefreshRate) &&
  4248. (pEntry->RefreshRate >= MatchRefreshRate) &&
  4249. (pEntry->MemorySpeed <= MemorySpeed) &&
  4250. (pEntry->MemorySpeed >= MatchMemorySpeed)) {
  4251. MatchRefreshRate = pEntry->RefreshRate;
  4252. MatchMemorySpeed = pEntry->MemorySpeed;
  4253. pStreamsParameters->FifoValue = pEntry->Value;
  4254. }
  4255. }
  4256. pEntry++;
  4257. }
  4258. if (MatchRefreshRate == 0) {
  4259. return ERROR_INVALID_PARAMETER;
  4260. }
  4261. return NO_ERROR;
  4262. }
  4263. /*****************************************************************************
  4264. *
  4265. * FUNCTION NAME: isMach()
  4266. *
  4267. * DESCRIPTIVE NAME:
  4268. *
  4269. * FUNCTION: Determine if system is an IBM Mach
  4270. *
  4271. *
  4272. * NOTES: Query the Vital Product Data (VPD) area
  4273. * F000:FFA0 in ROM.
  4274. * MACH Systems have "N", "P", "R", or "T" at location D
  4275. * i.e. at F000:FFAD location
  4276. *
  4277. * EXIT: return code FALSE if not an IBM MACH System
  4278. * return code TRUE if a IBM MACH System
  4279. *
  4280. * INTERNAL REFERENCES:
  4281. * ROUTINES:
  4282. *
  4283. * EXTERNAL REFERENCES:
  4284. * ROUTINES:
  4285. *
  4286. ****************************************************************************/
  4287. BOOLEAN isMach(PHW_DEVICE_EXTENSION HwDeviceExtension)
  4288. {
  4289. BOOLEAN ret = FALSE;
  4290. PVOID MappedVPDAddr = NULL;
  4291. PHYSICAL_ADDRESS VPDPhysAddr;
  4292. VPDPhysAddr.LowPart = 0x000fffad ;
  4293. VPDPhysAddr.HighPart = 0x00000000 ;
  4294. // Get the mapped address of the physical address F000:FFA0
  4295. MappedVPDAddr = VideoPortGetDeviceBase(HwDeviceExtension,
  4296. VPDPhysAddr,
  4297. 0x20,
  4298. 0);
  4299. if (MappedVPDAddr != NULL)
  4300. {
  4301. if ((VideoPortScanRom(HwDeviceExtension,
  4302. MappedVPDAddr,
  4303. 1,
  4304. "N"))||
  4305. (VideoPortScanRom(HwDeviceExtension,
  4306. MappedVPDAddr,
  4307. 1,
  4308. "P"))||
  4309. (VideoPortScanRom(HwDeviceExtension,
  4310. MappedVPDAddr,
  4311. 1,
  4312. "R"))||
  4313. (VideoPortScanRom(HwDeviceExtension,
  4314. MappedVPDAddr,
  4315. 1,
  4316. "T")))
  4317. {
  4318. VideoPortFreeDeviceBase(HwDeviceExtension,
  4319. MappedVPDAddr);
  4320. ret = TRUE;
  4321. }
  4322. }
  4323. return(ret);
  4324. }
  4325. VOID
  4326. WorkAroundForMach(
  4327. PHW_DEVICE_EXTENSION HwDeviceExtension
  4328. )
  4329. /*++
  4330. Routine Description:
  4331. This routine will attempt to determine if we are running on an
  4332. IBM Mach system. If so, and and 868 card was detected, we
  4333. will treat the card as an 864.
  4334. Arguments:
  4335. HwDeviceExtension - pointer to the miniports device extension.
  4336. Return:
  4337. none.
  4338. --*/
  4339. {
  4340. if ((HwDeviceExtension->SubTypeID == SUBTYPE_868) &&
  4341. isMach(HwDeviceExtension))
  4342. {
  4343. VideoDebugPrint((1, "S3 868 detected on IBM Mach. Treat as 864.\n"));
  4344. HwDeviceExtension->ChipID = S3_864;
  4345. HwDeviceExtension->SubTypeID = SUBTYPE_864;
  4346. }
  4347. }