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.

2059 lines
60 KiB

  1. /***************************************************************************\
  2. *
  3. * ************************
  4. * * MINIPORT SAMPLE CODE *
  5. * ************************
  6. *
  7. * Module Name:
  8. *
  9. * perm3.c
  10. *
  11. * Abstract:
  12. *
  13. * This module contains the code that implements the Permedia 3 miniport
  14. * driver
  15. *
  16. * Environment:
  17. *
  18. * Kernel mode
  19. *
  20. *
  21. * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
  22. * Copyright (c) 1995-2003 Microsoft Corporation. All Rights Reserved.
  23. *
  24. \***************************************************************************/
  25. #include "perm3.h"
  26. #include "string.h"
  27. #if defined(ALLOC_PRAGMA)
  28. #pragma alloc_text(PAGE,DriverEntry)
  29. #pragma alloc_text(PAGE,Perm3FindAdapter)
  30. #pragma alloc_text(PAGE,Perm3AssignResources)
  31. #pragma alloc_text(PAGE,Perm3ConfigurePci)
  32. #pragma alloc_text(PAGE,GetBoardCapabilities)
  33. #pragma alloc_text(PAGE,Perm3Initialize)
  34. #pragma alloc_text(PAGE,SetHardwareInfoRegistries)
  35. #pragma alloc_text(PAGE,UlongToString)
  36. #pragma alloc_text(PAGE,MapResource)
  37. #pragma alloc_text(PAGE,ProbeRAMSize)
  38. #pragma alloc_text(PAGE,InitializePostRegisters)
  39. #pragma alloc_text(PAGE,ConstructValidModesList)
  40. #pragma alloc_text(PAGE,Perm3RegistryCallback)
  41. #pragma alloc_text(PAGE,BuildInitializationTable)
  42. #pragma alloc_text(PAGE,CopyROMInitializationTable)
  43. #pragma alloc_text(PAGE,GenerateInitializationTable)
  44. #pragma alloc_text(PAGE,ProcessInitializationTable)
  45. #endif
  46. ULONG
  47. DriverEntry (
  48. PVOID Context1,
  49. PVOID Context2
  50. )
  51. /*+++
  52. Routine Description:
  53. DriverEntry is the initial entry point into the video miniport driver.
  54. Arguments:
  55. Context1
  56. First context value passed by the operating system. This is the
  57. value with which the miniport driver calls VideoPortInitialize().
  58. Context2
  59. Second context value passed by the operating system. This is the
  60. value with which the miniport driver calls VideoPortInitialize().
  61. Return Value:
  62. Status from VideoPortInitialize()
  63. ---*/
  64. {
  65. VIDEO_HW_INITIALIZATION_DATA hwInitData;
  66. ULONG initializationStatus;
  67. //
  68. // Zero out structure.
  69. //
  70. VideoPortZeroMemory(&hwInitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));
  71. //
  72. // Set entry points.
  73. //
  74. hwInitData.HwFindAdapter = Perm3FindAdapter;
  75. hwInitData.HwInitialize = Perm3Initialize;
  76. hwInitData.HwStartIO = Perm3StartIO;
  77. hwInitData.HwResetHw = Perm3ResetHW;
  78. hwInitData.HwInterrupt = Perm3VideoInterrupt;
  79. hwInitData.HwGetPowerState = Perm3GetPowerState;
  80. hwInitData.HwSetPowerState = Perm3SetPowerState;
  81. hwInitData.HwGetVideoChildDescriptor = Perm3GetChildDescriptor;
  82. hwInitData.HwQueryInterface = Perm3QueryInterface;
  83. //
  84. // Declare the legacy resources
  85. //
  86. hwInitData.HwLegacyResourceList = Perm3LegacyResourceList;
  87. hwInitData.HwLegacyResourceCount = Perm3LegacyResourceEntries;
  88. //
  89. // This device only supports the PCI bus.
  90. //
  91. hwInitData.AdapterInterfaceType = PCIBus;
  92. //
  93. // Determine the size required for the device extension.
  94. //
  95. hwInitData.HwDeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
  96. //
  97. // Specify sizes of structure and extension.
  98. //
  99. hwInitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
  100. initializationStatus = VideoPortInitialize (Context1,
  101. Context2,
  102. &hwInitData,
  103. NULL);
  104. #ifdef SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA
  105. //
  106. // This check will only be compiled under a Windows XP build environment where
  107. // the size of VIDEO_HW_INITIALIZATION_DATA has changed relative to Windows 2000
  108. // and therefore SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA is defined in order to
  109. // be able to load (in case of need) under Windows 2000
  110. //
  111. if(initializationStatus != NO_ERROR) {
  112. //
  113. // This is to make sure the driver could load on Win2k as well
  114. //
  115. hwInitData.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
  116. //
  117. // We will only support QueryInterface on WinXP
  118. //
  119. hwInitData.HwQueryInterface = NULL;
  120. initializationStatus = VideoPortInitialize(Context1,
  121. Context2,
  122. &hwInitData,
  123. NULL);
  124. }
  125. #endif // SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA
  126. return initializationStatus;
  127. } // end DriverEntry()
  128. VP_STATUS
  129. Perm3FindAdapter (
  130. PVOID HwDeviceExtension,
  131. PVOID HwContext,
  132. PWSTR ArgumentString,
  133. PVIDEO_PORT_CONFIG_INFO ConfigInfo,
  134. PUCHAR Again
  135. )
  136. /*+++
  137. Routine Description:
  138. This routine gets the access ranges for a device on an enumerable
  139. bus and, if necessary, determines the device type.
  140. Arguments:
  141. HwDeviceExtension
  142. Points to the driver's per-device storage area.
  143. HwContext
  144. Is NULL and should be ignored by the miniport.
  145. ArgumentString
  146. Suuplies a NULL terminated ASCII string. This string originates
  147. from the user. This pointer can be NULL.
  148. ConfigInfo
  149. Points to a VIDEO_PORT_CONFIG_INFO structure. The video port driver
  150. allocates memory for and initializes this structure with any known
  151. configuration information, such as values the miniport driver set
  152. in the VIDEO_HW_INITIALIZATION_DATA and the SystemIoBusNumber.
  153. Again
  154. Should be ignored by the miniport driver.
  155. Return Value:
  156. This routine must return one of the following status codes:
  157. NO_ERROR
  158. Indicates success.
  159. ERROR_INVALID_PARAMETER
  160. Indicates that the adapter could not be properly configured or
  161. information was inconsistent. (NOTE: This does not mean that the
  162. adapter could not be initialized. Miniports must not attempt to
  163. initialize the adapter in this routine.)
  164. ERROR_DEV_NOT_EXIST
  165. Indicates, for a non-enumerable bus, that the miniport driver could
  166. not find the device.
  167. ---*/
  168. {
  169. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  170. VideoDebugPrint((3, "Perm3: Perm3FindAdapter called for bus %d. hwDeviceExtension at 0x%x\n",
  171. ConfigInfo->SystemIoBusNumber, hwDeviceExtension));
  172. //
  173. // Make sure the size of the structure is at least as large as what we
  174. // are expecting.
  175. //
  176. if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) {
  177. VideoDebugPrint((0, "Perm3: bad size for VIDEO_PORT_CONFIG_INFO\n"));
  178. return (ERROR_INVALID_PARAMETER);
  179. }
  180. if(!Perm3ConfigurePci(hwDeviceExtension)) {
  181. VideoDebugPrint((0, "Perm3: Perm3ConfigurePci failed! \n"));
  182. return (ERROR_INVALID_PARAMETER);
  183. }
  184. if (!Perm3AssignResources(hwDeviceExtension)) {
  185. VideoDebugPrint((0, "Perm3: Perm3AssignResources failed! \n"));
  186. return (ERROR_INVALID_PARAMETER);
  187. }
  188. //
  189. // For I2C support we want to be able to associate a hwId with a
  190. // child device. Use the new VideoPortGetAssociatedDeviceID call
  191. // to get this information.
  192. //
  193. // This call will return NULL on Win2k but this is ok, because we
  194. // won't expose QueryInterface on Win2k, and thus will not try
  195. // to use this function.
  196. //
  197. hwDeviceExtension->WinXpVideoPortGetAssociatedDeviceID =
  198. ConfigInfo->VideoPortGetProcAddress(hwDeviceExtension,
  199. "VideoPortGetAssociatedDeviceID");
  200. hwDeviceExtension->WinXpSp1VideoPortRegisterBugcheckCallback =
  201. ConfigInfo->VideoPortGetProcAddress(hwDeviceExtension,
  202. "VideoPortRegisterBugcheckCallback");
  203. //
  204. // Clear out the Emulator entries and the state size since this driver
  205. // does not support them.
  206. //
  207. ConfigInfo->NumEmulatorAccessEntries = 0;
  208. ConfigInfo->EmulatorAccessEntries = NULL;
  209. ConfigInfo->EmulatorAccessEntriesContext = 0;
  210. //
  211. // This driver does not do SAVE/RESTORE of hardware state.
  212. //
  213. ConfigInfo->HardwareStateSize = 0;
  214. ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = 0x000A0000;
  215. ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0x00000000;
  216. ConfigInfo->VdmPhysicalVideoMemoryLength = 0x00020000;
  217. //
  218. // Will be initialized in BuildInitializationTable
  219. //
  220. hwDeviceExtension->culTableEntries = 0;
  221. //
  222. // Will be initialized in ConstructValidModesList
  223. //
  224. hwDeviceExtension->pFrequencyDefault = NULL;
  225. //
  226. // We'll set this TRUE when in InitializeVideo after programming the VTG
  227. //
  228. hwDeviceExtension->bVTGRunning = FALSE;
  229. //
  230. // Set up the defaults to indicate that we couldn't allocate a buffer
  231. //
  232. hwDeviceExtension->LineDMABuffer.virtAddr = 0;
  233. hwDeviceExtension->LineDMABuffer.size = 0;
  234. hwDeviceExtension->LineDMABuffer.cacheEnabled = FALSE;
  235. hwDeviceExtension->BiosVersionMajorNumber = 0xffffffff;
  236. hwDeviceExtension->BiosVersionMinorNumber = 0xffffffff;
  237. hwDeviceExtension->ChipClockSpeed = 0;
  238. hwDeviceExtension->ChipClockSpeedAlt = 0;
  239. hwDeviceExtension->RefClockSpeed = 0;
  240. hwDeviceExtension->bMonitorPoweredOn = TRUE;
  241. hwDeviceExtension->PreviousPowerState = VideoPowerOn;
  242. if ((ConfigInfo->BusInterruptLevel | ConfigInfo->BusInterruptVector) != 0) {
  243. hwDeviceExtension->Capabilities |= CAPS_INTERRUPTS;
  244. }
  245. if (hwDeviceExtension->deviceInfo.DeviceId == PERMEDIA4_ID) {
  246. hwDeviceExtension->Capabilities |= CAPS_DISABLE_OVERLAY;
  247. }
  248. //
  249. // If the support is present; register a bugcheck callback
  250. //
  251. // Release Note:
  252. //
  253. // Due to the way that data is collected, the size of the bugcheck data
  254. // collection buffer needs to be padded by BUGCHECK_DATA_SIZE_RESERVED.
  255. // Thus if you want to collect X bytes of data, you need to request
  256. // X + BUGCHECK_DATA_SIZE_RESERVED.
  257. // For XPSP1 and Windows Server 2003 the limit for X is 0xF70 bytes.
  258. //
  259. if (hwDeviceExtension->WinXpSp1VideoPortRegisterBugcheckCallback) {
  260. hwDeviceExtension->WinXpSp1VideoPortRegisterBugcheckCallback(
  261. hwDeviceExtension,
  262. 0xEA,
  263. Perm3BugcheckCallback,
  264. PERM3_BUGCHECK_DATA_SIZE + BUGCHECK_DATA_SIZE_RESERVED);
  265. }
  266. return(NO_ERROR);
  267. } // end Perm3FindAdapter()
  268. BOOLEAN
  269. Perm3AssignResources(
  270. PHW_DEVICE_EXTENSION hwDeviceExtension
  271. )
  272. /*+++
  273. Routine Description:
  274. This routine allocates resources required by a device
  275. ---*/
  276. {
  277. VIDEO_ACCESS_RANGE *aAccessRanges = hwDeviceExtension->PciAccessRange;
  278. ULONG cAccessRanges = sizeof(hwDeviceExtension->PciAccessRange) / sizeof(VIDEO_ACCESS_RANGE);
  279. VP_STATUS status;
  280. VideoPortZeroMemory((PVOID)aAccessRanges,
  281. cAccessRanges * sizeof(VIDEO_ACCESS_RANGE));
  282. status = VideoPortGetAccessRanges(hwDeviceExtension,
  283. 0,
  284. NULL,
  285. cAccessRanges,
  286. aAccessRanges,
  287. NULL,
  288. NULL,
  289. (PULONG) &(hwDeviceExtension->pciSlot));
  290. if (status != NO_ERROR) {
  291. VideoDebugPrint((0, "Perm3: VideoPortGetAccessRanges failed. error 0x%x\n", status));
  292. return(FALSE);
  293. }
  294. return(TRUE);
  295. }
  296. BOOLEAN
  297. Perm3ConfigurePci(
  298. PVOID HwDeviceExtension
  299. )
  300. /*+++
  301. Routine Description:
  302. This routine gets information from PCI config space and turn on memory
  303. and busmaster enable bits.
  304. Return Value:
  305. TRUE if successful
  306. ---*/
  307. {
  308. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  309. PCI_COMMON_CONFIG PciConfig;
  310. PCI_COMMON_CONFIG *PciData = &PciConfig;
  311. ULONG ul;
  312. UCHAR *ajPciData;
  313. UCHAR ChipCapPtr;
  314. //
  315. // When accessing the chip's PCI config region, be sure not to
  316. // touch the indirect access registers. Gamma has an EEPROM access
  317. // reigter @ 0x80, Perm3 have indirect access registers from 0xF8.
  318. //
  319. ul = VideoPortGetBusData(hwDeviceExtension,
  320. PCIConfiguration,
  321. 0,
  322. PciData,
  323. 0,
  324. 80);
  325. if(ul == 0) {
  326. VideoDebugPrint((0, "Perm3: VideoPortGetBusData Failed \n"));
  327. return (FALSE);
  328. }
  329. hwDeviceExtension->deviceInfo.VendorId = PciConfig.VendorID;
  330. hwDeviceExtension->deviceInfo.DeviceId = PciConfig.DeviceID;
  331. hwDeviceExtension->deviceInfo.RevisionId = PciConfig.RevisionID;
  332. hwDeviceExtension->deviceInfo.SubsystemId = PciConfig.u.type0.SubSystemID;
  333. hwDeviceExtension->deviceInfo.SubsystemVendorId = PciConfig.u.type0.SubVendorID;
  334. hwDeviceExtension->deviceInfo.GammaRevId = 0;
  335. hwDeviceExtension->deviceInfo.DeltaRevId = 0;
  336. //
  337. // in multi-adapter systems we need to check if the device is
  338. // decoding VGA resource
  339. //
  340. VideoPortGetVgaStatus( HwDeviceExtension, &ul);
  341. hwDeviceExtension->bVGAEnabled = (ul & DEVICE_VGA_ENABLED) ? TRUE : FALSE;
  342. //
  343. // Find the board capabilities
  344. //
  345. hwDeviceExtension->Perm3Capabilities =
  346. GetBoardCapabilities(hwDeviceExtension,
  347. PciData->u.type0.SubVendorID,
  348. PciData->u.type0.SubSystemID);
  349. //
  350. // Determin if it is a AGP card by searching the AGP_CAP_ID
  351. //
  352. ajPciData = (UCHAR *)PciData;
  353. ChipCapPtr = ajPciData[AGP_CAP_PTR_OFFSET];
  354. hwDeviceExtension->bIsAGP = FALSE;
  355. while (ChipCapPtr && (ajPciData[ChipCapPtr] != AGP_CAP_ID)) {
  356. //
  357. // follow the next ptr
  358. //
  359. ChipCapPtr = ajPciData[ChipCapPtr+1];
  360. }
  361. if(ajPciData[ChipCapPtr] == AGP_CAP_ID) {
  362. hwDeviceExtension->bIsAGP = TRUE;
  363. }
  364. PciData->LatencyTimer = 0xff;
  365. PciData->Command |= (PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER);
  366. ul = VideoPortSetBusData(HwDeviceExtension,
  367. PCIConfiguration,
  368. 0,
  369. PciData,
  370. 0,
  371. PCI_COMMON_HDR_LENGTH);
  372. if (ul < PCI_COMMON_HDR_LENGTH) {
  373. return (FALSE);
  374. }
  375. return (TRUE);
  376. }
  377. ULONG
  378. GetBoardCapabilities(
  379. PHW_DEVICE_EXTENSION hwDeviceExtension,
  380. ULONG SubvendorID,
  381. ULONG SubdeviceID
  382. )
  383. /*+++
  384. Routine Description:
  385. Return a list of capabilities of the perm3 board.
  386. ---*/
  387. {
  388. PERM3_CAPS Perm3Caps = 0;
  389. if (SubvendorID == SUBVENDORID_3DLABS) {
  390. //
  391. // Check for SGRAM and DFP
  392. //
  393. switch (SubdeviceID) {
  394. case SUBDEVICEID_P3_VX1_1600SW:
  395. Perm3Caps |= PERM3_DFP;
  396. break;
  397. }
  398. }
  399. return (Perm3Caps);
  400. }
  401. BOOLEAN
  402. Perm3Initialize(
  403. PVOID HwDeviceExtension
  404. )
  405. /*+++
  406. Routine Description:
  407. This routine does one time initialization of the device
  408. Arguments:
  409. HwDeviceExtension
  410. Points to the driver's per-device storage area.
  411. Return Value:
  412. TRUE if successful
  413. ---*/
  414. {
  415. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  416. VP_STATUS vpStatus;
  417. ULONG ul;
  418. pPerm3ControlRegMap pCtrlRegs;
  419. VideoDebugPrint((3, "Perm3: Perm3Initialize called, hwDeviceExtension = %p\n", hwDeviceExtension));
  420. //
  421. // Map the control register, framebufer and initialize memory control
  422. // registers on the way
  423. //
  424. if(!MapResource(hwDeviceExtension)) {
  425. VideoDebugPrint((0, "Perm3: failed to map the framebuffer and control registers\n"));
  426. return(FALSE);
  427. }
  428. //
  429. // At this time ctrlRegBase should be initialized
  430. //
  431. pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  432. hwDeviceExtension->pRamdac = &(pCtrlRegs->ExternalVideo);
  433. hwDeviceExtension->DacId = P3RD_RAMDAC;
  434. hwDeviceExtension->deviceInfo.ActualDacId = P3RD_RAMDAC;
  435. hwDeviceExtension->deviceInfo.BoardId = PERMEDIA3_BOARD;
  436. if(!hwDeviceExtension->bIsAGP) {
  437. ul = VideoPortReadRegisterUlong(CHIP_CONFIG);
  438. ul &= ~(1 << 9);
  439. VideoPortWriteRegisterUlong(CHIP_CONFIG, ul);
  440. }
  441. //
  442. // Save hardware information to the registry
  443. //
  444. SetHardwareInfoRegistries(hwDeviceExtension);
  445. ConstructValidModesList(hwDeviceExtension,
  446. &hwDeviceExtension->monitorInfo);
  447. if (hwDeviceExtension->monitorInfo.numAvailableModes == 0) {
  448. VideoDebugPrint((0, "Perm3: No video modes available\n"));
  449. return(FALSE);
  450. }
  451. //
  452. // if we have interrupts available do any interrupt initialization.
  453. //
  454. if (hwDeviceExtension->Capabilities & CAPS_INTERRUPTS) {
  455. if (!Perm3InitializeInterruptBlock(hwDeviceExtension))
  456. hwDeviceExtension->Capabilities &= ~CAPS_INTERRUPTS;
  457. }
  458. return TRUE;
  459. } // end Perm3Initialize()
  460. VOID
  461. SetHardwareInfoRegistries(
  462. PHW_DEVICE_EXTENSION hwDeviceExtension
  463. )
  464. /*+++
  465. Routine Description:
  466. Determine the hardware information and save them in the registry
  467. ---*/
  468. {
  469. PWSTR pwszChip, pwszDAC, pwszAdapterString, pwszBiosString, pwsz;
  470. ULONG cbChip, cbDAC, cbAdapterString, cbBiosString, ul;
  471. WCHAR StringBuffer[60];
  472. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  473. //
  474. // Get the device name
  475. //
  476. cbChip = sizeof(L"3Dlabs PERMEDIA 3");
  477. pwszChip = L"3Dlabs PERMEDIA 3";
  478. //
  479. // Get the board name
  480. //
  481. if(hwDeviceExtension->deviceInfo.SubsystemVendorId == SUBVENDORID_3DLABS){
  482. switch (hwDeviceExtension->deviceInfo.SubsystemId) {
  483. case SUBDEVICEID_P3_32D_AGP:
  484. cbAdapterString = sizeof(L"3Dlabs Permedia3 Create!");
  485. pwszAdapterString = L"3Dlabs Permedia3 Create!";
  486. break;
  487. case SUBDEVICEID_P3_VX1_AGP:
  488. case SUBDEVICEID_P3_VX1_PCI:
  489. cbAdapterString = sizeof(L"3Dlabs Oxygen VX1");
  490. pwszAdapterString = L"3Dlabs Oxygen VX1";
  491. break;
  492. case SUBDEVICEID_P3_VX1_1600SW:
  493. cbAdapterString = sizeof(L"3Dlabs Oxygen VX1 1600SW");
  494. pwszAdapterString = L"3Dlabs Oxygen VX1 1600SW";
  495. break;
  496. default:
  497. cbAdapterString = sizeof(L"3Dlabs PERMEDIA 3");
  498. pwszAdapterString = L"3Dlabs PERMEDIA 3";
  499. break;
  500. }
  501. } else {
  502. //
  503. // Non-3Dlabs board, just call it a P3
  504. //
  505. cbAdapterString = sizeof(L"PERMEDIA 3");
  506. pwszAdapterString = L"PERMEDIA 3";
  507. }
  508. //
  509. // Get the RAMDAC name
  510. //
  511. pwszDAC = L"3Dlabs P3RD";
  512. cbDAC = sizeof(L"3Dlabs P3RD");
  513. //
  514. // get the BIOS version number string
  515. //
  516. pwszBiosString = StringBuffer;
  517. cbBiosString = sizeof(L"Version ");
  518. VideoPortMoveMemory((PVOID)StringBuffer, (PVOID)(L"Version "), cbBiosString);
  519. pwsz = pwszBiosString + (cbBiosString >> 1) - 1; // position on L'\0';
  520. if(hwDeviceExtension->BiosVersionMajorNumber != 0xffffffff) {
  521. ul = UlongToString(hwDeviceExtension->BiosVersionMajorNumber, pwsz);
  522. cbBiosString += ul << 1;
  523. pwsz += ul;
  524. *pwsz++ = L'.';
  525. cbBiosString += sizeof(L'.');
  526. ul = UlongToString(hwDeviceExtension->BiosVersionMinorNumber, pwsz);
  527. cbBiosString += ul << 1;
  528. }
  529. //
  530. // We now have a complete hardware description of the hardware.
  531. // Save the information to the registry so it can be used by
  532. // configuration programs - such as the display applet.
  533. //
  534. VideoPortSetRegistryParameters(hwDeviceExtension,
  535. L"HardwareInformation.ChipType",
  536. pwszChip,
  537. cbChip);
  538. VideoPortSetRegistryParameters(hwDeviceExtension,
  539. L"HardwareInformation.DacType",
  540. pwszDAC,
  541. cbDAC);
  542. VideoPortSetRegistryParameters(hwDeviceExtension,
  543. L"HardwareInformation.MemorySize",
  544. &hwDeviceExtension->AdapterMemorySize,
  545. sizeof(ULONG));
  546. VideoPortSetRegistryParameters(hwDeviceExtension,
  547. L"HardwareInformation.AdapterString",
  548. pwszAdapterString,
  549. cbAdapterString);
  550. VideoPortSetRegistryParameters(hwDeviceExtension,
  551. L"HardwareInformation.BiosString",
  552. pwszBiosString,
  553. cbBiosString);
  554. }
  555. ULONG
  556. UlongToString(
  557. ULONG i,
  558. PWSTR pwsz
  559. )
  560. /*+++
  561. Arguments:
  562. i
  563. Input number
  564. pwsz
  565. Output wide string: it is the user's responsibility to ensure this
  566. is wide enough
  567. Return Value:
  568. Number of wide characters returned in pwsz
  569. ---*/
  570. {
  571. ULONG j, k;
  572. BOOLEAN bSignificantDigit = FALSE;
  573. ULONG cwch = 0;
  574. if(i == 0) {
  575. *pwsz++ = L'0';
  576. ++cwch;
  577. } else {
  578. //
  579. // maxmium 10^n representable in a ulong
  580. //
  581. j = 1000000000;
  582. while(i || j) {
  583. if(i && i >= j) {
  584. k = i / j;
  585. i -= k * j;
  586. bSignificantDigit = TRUE;
  587. } else {
  588. k = 0;
  589. }
  590. if(k || bSignificantDigit) {
  591. *pwsz++ = L'0' + (WCHAR)k;
  592. ++cwch;
  593. }
  594. j /= 10;
  595. }
  596. }
  597. *pwsz = L'\0';
  598. return(cwch);
  599. }
  600. BOOLEAN
  601. MapResource(
  602. PHW_DEVICE_EXTENSION hwDeviceExtension
  603. )
  604. /*+++
  605. Routine Description:
  606. Get the mapped addresses of the control registers and framebuffer
  607. Arguments:
  608. HwDeviceExtension
  609. Points to the driver's per-device storage area.
  610. Return Value:
  611. TRUE if successful
  612. ---*/
  613. {
  614. VIDEO_ACCESS_RANGE *pciAccessRange = hwDeviceExtension->PciAccessRange;
  615. ULONG fbMappedSize, fbRealSize;
  616. ULONG sz;
  617. pPerm3ControlRegMap pCtrlRegs;
  618. //
  619. // Map Control Registers
  620. //
  621. pCtrlRegs =
  622. VideoPortGetDeviceBase(hwDeviceExtension,
  623. pciAccessRange[PCI_CTRL_BASE_INDEX].RangeStart,
  624. pciAccessRange[PCI_CTRL_BASE_INDEX].RangeLength,
  625. pciAccessRange[PCI_CTRL_BASE_INDEX].RangeInIoSpace);
  626. if (pCtrlRegs == NULL) {
  627. VideoDebugPrint((0, "Perm3: map control register failed\n"));
  628. return FALSE;
  629. }
  630. hwDeviceExtension->ctrlRegBase[0] = pCtrlRegs;
  631. //
  632. // Map Framebuffer
  633. //
  634. pciAccessRange[PCI_FB_BASE_INDEX].RangeInIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  635. hwDeviceExtension->pFramebuffer =
  636. VideoPortGetDeviceBase(hwDeviceExtension,
  637. pciAccessRange[PCI_FB_BASE_INDEX].RangeStart,
  638. pciAccessRange[PCI_FB_BASE_INDEX].RangeLength,
  639. pciAccessRange[PCI_FB_BASE_INDEX].RangeInIoSpace);
  640. if(hwDeviceExtension->pFramebuffer == NULL) {
  641. //
  642. // If we failed to map the whole range for some reason then try to
  643. // map part of it. We reduce the amount we map till we succeed
  644. // or the size gets to zero in which case we really have failed.
  645. //
  646. for (sz = pciAccessRange[PCI_FB_BASE_INDEX].RangeLength;
  647. sz > 0;
  648. sz -= 1024*1024) {
  649. pciAccessRange[PCI_FB_BASE_INDEX].RangeInIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  650. hwDeviceExtension->pFramebuffer =
  651. VideoPortGetDeviceBase(hwDeviceExtension,
  652. pciAccessRange[PCI_FB_BASE_INDEX].RangeStart,
  653. sz,
  654. pciAccessRange[PCI_FB_BASE_INDEX].RangeInIoSpace);
  655. if(hwDeviceExtension->pFramebuffer != NULL) {
  656. pciAccessRange[PCI_FB_BASE_INDEX].RangeLength = sz;
  657. break;
  658. }
  659. }
  660. //
  661. // if sz is zero, well we tried ...
  662. //
  663. if (sz == 0) {
  664. VideoDebugPrint((0, "Perm3: map framebuffer failed\n"));
  665. return(FALSE);
  666. }
  667. }
  668. VideoDebugPrint((3, "Perm3: FB mapped at 0x%x for length 0x%x (%s)\n",
  669. hwDeviceExtension->pFramebuffer,
  670. pciAccessRange[PCI_FB_BASE_INDEX].RangeLength,
  671. pciAccessRange[PCI_FB_BASE_INDEX].RangeInIoSpace ? "I/O Ports" : "MemMapped"));
  672. //
  673. // Initialize the RAM registers and then probe the framebuffer size
  674. //
  675. InitializePostRegisters(hwDeviceExtension);
  676. fbMappedSize = pciAccessRange[PCI_FB_BASE_INDEX].RangeLength;
  677. if ((fbRealSize = ProbeRAMSize (hwDeviceExtension,
  678. hwDeviceExtension->pFramebuffer,
  679. fbMappedSize)) == 0 ) {
  680. VideoPortFreeDeviceBase(hwDeviceExtension,
  681. hwDeviceExtension->pFramebuffer);
  682. VideoDebugPrint((0, "perm3: ProbeRAMSize returned 0\n"));
  683. return (FALSE);
  684. }
  685. if (fbRealSize < fbMappedSize) {
  686. pciAccessRange[PCI_FB_BASE_INDEX].RangeLength = fbRealSize;
  687. VideoDebugPrint((3, "perm3: RAM dynamically resized to length 0x%x\n",
  688. fbRealSize));
  689. }
  690. //
  691. // Finally, if the RAM size is actually smaller than the region that
  692. // we mapped, remap to the smaller size to save on page table entries.
  693. //
  694. if (fbMappedSize > pciAccessRange[PCI_FB_BASE_INDEX].RangeLength) {
  695. VideoPortFreeDeviceBase(hwDeviceExtension,
  696. hwDeviceExtension->pFramebuffer);
  697. pciAccessRange[PCI_FB_BASE_INDEX].RangeInIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  698. if ((hwDeviceExtension->pFramebuffer =
  699. VideoPortGetDeviceBase(hwDeviceExtension,
  700. pciAccessRange[PCI_FB_BASE_INDEX].RangeStart,
  701. pciAccessRange[PCI_FB_BASE_INDEX].RangeLength,
  702. pciAccessRange[PCI_FB_BASE_INDEX].RangeInIoSpace
  703. )) == NULL) {
  704. //
  705. // This shouldn't happen but we'd better check
  706. //
  707. VideoDebugPrint((0, "Perm3: Remap of framebuffer to smaller size failed!\n"));
  708. return FALSE;
  709. }
  710. VideoDebugPrint((3, "Perm3: Remapped framebuffer memory to 0x%x, size 0x%x\n",
  711. hwDeviceExtension->pFramebuffer,
  712. pciAccessRange[PCI_FB_BASE_INDEX].RangeLength));
  713. }
  714. //
  715. // Record the size of the video memory.
  716. //
  717. hwDeviceExtension->PhysicalFrameIoSpace = 0;
  718. hwDeviceExtension->AdapterMemorySize =
  719. pciAccessRange[PCI_FB_BASE_INDEX].RangeLength;
  720. //
  721. // Record Frame buffer information
  722. //
  723. hwDeviceExtension->PhysicalFrameAddress =
  724. pciAccessRange[PCI_FB_BASE_INDEX].RangeStart;
  725. hwDeviceExtension->FrameLength =
  726. pciAccessRange[PCI_FB_BASE_INDEX].RangeLength;
  727. //
  728. // Record Control Register information
  729. //
  730. hwDeviceExtension->PhysicalRegisterAddress =
  731. pciAccessRange[PCI_CTRL_BASE_INDEX].RangeStart;
  732. hwDeviceExtension->RegisterLength =
  733. pciAccessRange[PCI_CTRL_BASE_INDEX].RangeLength;
  734. hwDeviceExtension->RegisterSpace =
  735. pciAccessRange[PCI_CTRL_BASE_INDEX].RangeInIoSpace;
  736. return(TRUE);
  737. }
  738. ULONG
  739. ProbeRAMSize(
  740. PHW_DEVICE_EXTENSION hwDeviceExtension,
  741. PULONG FBBaseAddress,
  742. ULONG FBMappedSize
  743. )
  744. /*+++
  745. Routine Description:
  746. Dynamically size the on-board memory for the Permedia3
  747. Arguments:
  748. HwDeviceExtension
  749. Supplies a pointer to the miniport's device extension.
  750. FBBaseAddress
  751. Starting address of framebuffer
  752. FBMappedSize
  753. Mapped size
  754. Return Value:
  755. Size, in bytes, of the memory.
  756. ---*/
  757. {
  758. PULONG pV, pVStart, pVEnd;
  759. ULONG realFBLength, testPattern, probeSize, temp, startLong1, startLong2;
  760. ULONG_PTR ulPtr;
  761. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  762. //
  763. // Dynamically size the SGRAM/SDRAM. Sample every 128K. We start
  764. // at the end of memory and work our way up writing the address into
  765. // memory at that address. We do this every 'probeSize' DWORDS.
  766. // We then validate the data by reading it back again, starting from
  767. // the end of memory working our way up until we read a value back
  768. // from memory that matches the address that we are at.
  769. //
  770. // Note that this algorithm does a destructive test of memory !!
  771. //
  772. testPattern = 0x55aa33cc;
  773. probeSize = (128 * 1024 / sizeof(ULONG)); // In DWords
  774. pVStart = (PULONG)FBBaseAddress;
  775. pVEnd = (PULONG)((ULONG_PTR)pVStart + (ULONG_PTR)FBMappedSize);
  776. //
  777. // Check out address zero, just in case the memory is really messed up.
  778. // We also save away the first 2 long words and restore them at the end,
  779. // otherwise our boot screen looks wonky.
  780. //
  781. startLong1 = VideoPortReadRegisterUlong(pVStart);
  782. startLong2 = VideoPortReadRegisterUlong(pVStart+1);
  783. VideoPortWriteRegisterUlong(pVStart, testPattern);
  784. VideoPortWriteRegisterUlong(pVStart+1, 0);
  785. if ((temp = VideoPortReadRegisterUlong(pVStart)) != testPattern) {
  786. VideoDebugPrint((0, "Perm3: Cannot access SGRAM/SDRAM. Expected 0x%x, got 0x%x\n", testPattern, temp));
  787. realFBLength = 0;
  788. } else {
  789. //
  790. // Restore first 2 long words otherwise we end up with a corrupt
  791. // VGA boot screen
  792. //
  793. VideoPortWriteRegisterUlong(pVStart, startLong1);
  794. VideoPortWriteRegisterUlong(pVStart+1, startLong2);
  795. //
  796. // Write the memory address at the memory address, starting from the
  797. // end of memory and working our way down.
  798. //
  799. for (pV = pVEnd - probeSize; pV >= pVStart; pV -= probeSize) {
  800. ulPtr = (ULONG_PTR)pV & 0xFFFFFFFF;
  801. VideoPortWriteRegisterUlong(pV, (ULONG) ulPtr);
  802. }
  803. //
  804. // Read the data at the memory address, starting from the end of memory
  805. // and working our way down. If the address is correct then we stop and
  806. // work out the memory size.
  807. //
  808. for (pV = pVEnd - probeSize; pV >= pVStart; pV -= probeSize) {
  809. ulPtr = (ULONG_PTR)pV & 0xFFFFFFFF;
  810. if (VideoPortReadRegisterUlong(pV) == (ULONG) ulPtr) {
  811. pV += probeSize;
  812. break;
  813. }
  814. }
  815. realFBLength = (ULONG)((PUCHAR) pV - (PUCHAR) pVStart);
  816. }
  817. //
  818. // Restore first 2 long words again, otherwise we end up with a corrupt
  819. // VGA boot screen
  820. //
  821. VideoPortWriteRegisterUlong(pVStart, startLong1);
  822. VideoPortWriteRegisterUlong(pVStart+1, startLong2);
  823. VideoDebugPrint((3, "Perm3: ProbeRAMSize returning length %d (0x%x) bytes\n", realFBLength, realFBLength));
  824. return (realFBLength);
  825. }
  826. VOID
  827. InitializePostRegisters(
  828. PHW_DEVICE_EXTENSION hwDeviceExtension
  829. )
  830. {
  831. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  832. //
  833. // Build the initialization table if it is empty
  834. //
  835. if (hwDeviceExtension->culTableEntries == 0) {
  836. BuildInitializationTable(hwDeviceExtension);
  837. }
  838. ASSERT(hwDeviceExtension->culTableEntries != 0);
  839. ProcessInitializationTable(hwDeviceExtension);
  840. VideoPortWriteRegisterUlong(APERTURE_ONE, 0x0);
  841. VideoPortWriteRegisterUlong(APERTURE_TWO, 0x0);
  842. VideoPortWriteRegisterUlong(BYPASS_WRITE_MASK, 0xFFFFFFFF);
  843. }
  844. VOID
  845. ConstructValidModesList(
  846. PVOID HwDeviceExtension,
  847. MONITOR_INFO *mi
  848. )
  849. /*+++
  850. Routine Description:
  851. Here we prune valid modes, based on rules according to the chip
  852. capabilities and memory requirements.
  853. ---*/
  854. {
  855. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  856. PPERM3_VIDEO_FREQUENCIES FrequencyEntry;
  857. PPERM3_VIDEO_MODES ModeEntry;
  858. BOOLEAN AllowForZBuffer;
  859. LONG AdapterMemorySize;
  860. ULONG ModeIndex, i;
  861. ULONG localBufferSizeInBytes = 2;
  862. AllowForZBuffer = TRUE;
  863. mi->numAvailableModes = 0;
  864. //
  865. // Since there are a number of frequencies possible for each
  866. // distinct resolution/colour depth, we cycle through the
  867. // frequency table and find the appropriate mode entry for that
  868. // frequency entry.
  869. //
  870. if (!BuildFrequencyList(hwDeviceExtension, mi))
  871. return;
  872. for (FrequencyEntry = mi->frequencyTable, ModeIndex = 0;
  873. FrequencyEntry->BitsPerPel != 0;
  874. FrequencyEntry++, ModeIndex++) {
  875. //
  876. // Find the mode for this entry. First, assume we won't find one.
  877. //
  878. FrequencyEntry->ModeValid = FALSE;
  879. FrequencyEntry->ModeIndex = ModeIndex;
  880. for (ModeEntry = Perm3Modes, i = 0;
  881. i < NumPerm3VideoModes;
  882. ModeEntry++, i++) {
  883. if ((FrequencyEntry->BitsPerPel ==
  884. ModeEntry->ModeInformation.BitsPerPlane) &&
  885. (FrequencyEntry->ScreenHeight ==
  886. ModeEntry->ModeInformation.VisScreenHeight) &&
  887. (FrequencyEntry->ScreenWidth ==
  888. ModeEntry->ModeInformation.VisScreenWidth)) {
  889. AdapterMemorySize = (LONG)hwDeviceExtension->AdapterMemorySize;
  890. //
  891. // Allow for a Z buffer on Permedia3. It's always 16 bits deep.
  892. //
  893. if (AllowForZBuffer) {
  894. AdapterMemorySize -=
  895. (LONG)(ModeEntry->ModeInformation.VisScreenWidth *
  896. ModeEntry->ModeInformation.VisScreenHeight *
  897. localBufferSizeInBytes);
  898. }
  899. //
  900. // If we need to be double buffered then we only have half this
  901. // remainder for the visible screen. 12bpp is special since
  902. // each pixel contains both front and back.
  903. //
  904. if ((FrequencyEntry->BitsPerPel != 12))
  905. AdapterMemorySize /= 2;
  906. //
  907. // We've found a mode table entry that matches this frequency
  908. // table entry. Now we'll figure out if we can actually do
  909. // this mode/frequency combination. For now, assume we'll
  910. // succeed.
  911. //
  912. FrequencyEntry->ModeEntry = ModeEntry;
  913. FrequencyEntry->ModeValid = TRUE;
  914. VideoDebugPrint((3, "Perm3: Trying mode: %dbpp, w x h %d x %d @ %dHz... ",
  915. ModeEntry->ModeInformation.BitsPerPlane,
  916. ModeEntry->ModeInformation.VisScreenWidth,
  917. ModeEntry->ModeInformation.VisScreenHeight,
  918. FrequencyEntry->ScreenFrequency
  919. ));
  920. //
  921. // Rule: Refuses to handle <60Hz refresh.
  922. //
  923. if( (FrequencyEntry->ScreenFrequency < 60) &&
  924. !(hwDeviceExtension->Perm3Capabilities & PERM3_DFP_MON_ATTACHED) ) {
  925. FrequencyEntry->ModeValid = FALSE;
  926. }
  927. if( (hwDeviceExtension->Perm3Capabilities & PERM3_DFP_MON_ATTACHED) &&
  928. (FrequencyEntry->BitsPerPel == 8) ) {
  929. FrequencyEntry->ModeValid = FALSE;
  930. }
  931. //
  932. // Rule: On Perm3, if this is an eight-bit mode that requires
  933. // us to use byte doubling then the pixel-clock validation is
  934. // more strict because we have to double the pixel clock.
  935. //
  936. if (FrequencyEntry->BitsPerPel == 8) {
  937. VESA_TIMING_STANDARD VESATimings;
  938. //
  939. // Get the timing parameters for this mode.
  940. //
  941. if (GetVideoTiming(HwDeviceExtension,
  942. ModeEntry->ModeInformation.VisScreenWidth,
  943. ModeEntry->ModeInformation.VisScreenHeight,
  944. FrequencyEntry->ScreenFrequency,
  945. FrequencyEntry->BitsPerPel,
  946. &VESATimings)) {
  947. if ( P3RD_CHECK_BYTE_DOUBLING (hwDeviceExtension,
  948. FrequencyEntry->BitsPerPel,
  949. &VESATimings) &&
  950. (VESATimings.pClk << 1) > P3_MAX_PIXELCLOCK ) {
  951. VideoDebugPrint((3, "Perm3: Bad 8BPP pixelclock\n"));
  952. FrequencyEntry->ModeValid = FALSE;
  953. }
  954. } else {
  955. VideoDebugPrint((0, "Perm3: GetVideoTiming failed\n"));
  956. FrequencyEntry->ModeValid = FALSE;
  957. }
  958. }
  959. //
  960. // Rule: Do not support 15BPP (555 mode)
  961. //
  962. if ( FrequencyEntry->BitsPerPel == 15 ) {
  963. FrequencyEntry->ModeValid = FALSE;
  964. }
  965. ModeEntry->ModeInformation.ScreenStride = ModeEntry->ScreenStrideContiguous;
  966. //
  967. // Rule: We have to have enough memory to handle the mode.
  968. //
  969. if ((LONG)(ModeEntry->ModeInformation.VisScreenHeight *
  970. ModeEntry->ModeInformation.ScreenStride) >
  971. AdapterMemorySize) {
  972. FrequencyEntry->ModeValid = FALSE;
  973. }
  974. //
  975. // Rule: No 12 bpp, only need 60Hz at 1280 true color.
  976. //
  977. {
  978. ULONG pixelData;
  979. ULONG DacDepth = FrequencyEntry->BitsPerPel;
  980. //
  981. // We need the proper pixel size to calculate timing values
  982. //
  983. if (DacDepth == 15) {
  984. DacDepth = 16;
  985. } else if (DacDepth == 12) {
  986. DacDepth = 32;
  987. }
  988. pixelData = FrequencyEntry->PixelClock * (DacDepth / 8);
  989. if ((( FrequencyEntry->PixelClock > P3_MAX_PIXELCLOCK ||
  990. pixelData > P3_MAX_PIXELDATA ))) {
  991. FrequencyEntry->ModeValid = FALSE;
  992. }
  993. }
  994. //
  995. // Do not supports 24bpp
  996. //
  997. if(FrequencyEntry->BitsPerPel == 24) {
  998. FrequencyEntry->ModeValid = FALSE;
  999. }
  1000. //
  1001. // For Permedia4, no mode smaller than 640x400 is supported
  1002. //
  1003. if (hwDeviceExtension->deviceInfo.DeviceId == PERMEDIA4_ID ) {
  1004. if ((FrequencyEntry->ScreenWidth < 640) ||
  1005. (FrequencyEntry->ScreenHeight < 400)) {
  1006. FrequencyEntry->ModeValid = FALSE;
  1007. }
  1008. }
  1009. //
  1010. // Don't forget to count it if it's still a valid mode after
  1011. // applying all those rules.
  1012. //
  1013. if ( FrequencyEntry->ModeValid ) {
  1014. if (hwDeviceExtension->pFrequencyDefault == NULL &&
  1015. ModeEntry->ModeInformation.BitsPerPlane == 8 &&
  1016. ModeEntry->ModeInformation.VisScreenWidth == 640 &&
  1017. ModeEntry->ModeInformation.VisScreenHeight == 480 ) {
  1018. hwDeviceExtension->pFrequencyDefault = FrequencyEntry;
  1019. }
  1020. ModeEntry->ModeInformation.ModeIndex = mi->numAvailableModes++;
  1021. }
  1022. //
  1023. // We've found a mode for this frequency entry, so we
  1024. // can break out of the mode loop:
  1025. //
  1026. break;
  1027. }
  1028. }
  1029. }
  1030. mi->numTotalModes = ModeIndex;
  1031. VideoDebugPrint((3, "perm3: %d total modes\n", ModeIndex));
  1032. VideoDebugPrint((3, "perm3: %d total valid modes\n", mi->numAvailableModes));
  1033. }
  1034. VP_STATUS
  1035. Perm3RegistryCallback(
  1036. PVOID HwDeviceExtension,
  1037. PVOID Context,
  1038. PWSTR ValueName,
  1039. PVOID ValueData,
  1040. ULONG ValueLength
  1041. )
  1042. /*+++
  1043. Routine Description:
  1044. This routine is used to read back various registry values.
  1045. Arguments:
  1046. HwDeviceExtension
  1047. Supplies a pointer to the miniport's device extension.
  1048. Context
  1049. Context value passed to the get registry parameters routine.
  1050. If this is not null assume it's a ULONG* and save the data value in it.
  1051. ValueName
  1052. Name of the value requested.
  1053. ValueData
  1054. Pointer to the requested data.
  1055. ValueLength
  1056. Length of the requested data.
  1057. Return Value:
  1058. If the variable doesn't exist return an error,
  1059. else if a context is supplied assume it's a PULONG and fill in the value
  1060. and return no error, else if the value is non-zero return an error.
  1061. ---*/
  1062. {
  1063. if (ValueLength) {
  1064. if (Context) {
  1065. *(ULONG *)Context = *(PULONG)ValueData;
  1066. } else if (*((PULONG)ValueData) != 0) {
  1067. return ERROR_INVALID_PARAMETER;
  1068. }
  1069. return NO_ERROR;
  1070. } else {
  1071. return ERROR_INVALID_PARAMETER;
  1072. }
  1073. } // end Perm3RegistryCallback()
  1074. BOOLEAN
  1075. Perm3ResetHW(
  1076. PVOID HwDeviceExtension,
  1077. ULONG Columns,
  1078. ULONG Rows
  1079. )
  1080. /*+++
  1081. Routine Description:
  1082. This routine resets the adapter to character mode.
  1083. THIS FUNCTION CANNOT BE PAGED.
  1084. Arguments:
  1085. hwDeviceExtension
  1086. Points to the miniport's per-adapter storage area.
  1087. Columns
  1088. Specifies the number of columns of the mode to be set up.
  1089. Rows
  1090. Specifies the number of rows of the mode to be set up.
  1091. Return Value:
  1092. We always return FALSE to force the HAL to do an INT10 reset.
  1093. ---*/
  1094. {
  1095. //
  1096. // return false so the HAL does an INT10 mode 3
  1097. //
  1098. return(FALSE);
  1099. }
  1100. VOID
  1101. BuildInitializationTable(
  1102. PHW_DEVICE_EXTENSION hwDeviceExtension
  1103. )
  1104. /*+++
  1105. Routine Description:
  1106. Read the ROM, if any is present, and extract any data needed for
  1107. chip set-up
  1108. Arguments:
  1109. HwDeviceExtension
  1110. Points to the driver's per-device storage area.
  1111. ---*/
  1112. {
  1113. PVOID romAddress;
  1114. romAddress = VideoPortGetRomImage(hwDeviceExtension,
  1115. NULL,
  1116. 0,
  1117. ROM_MAPPED_LENGTH);
  1118. if (romAddress) {
  1119. //
  1120. // We'll take a copy of the initialization table in the exansion
  1121. // ROM now so that we can run through the initialization ourselves,
  1122. // later on
  1123. //
  1124. CopyROMInitializationTable(hwDeviceExtension, romAddress);
  1125. //
  1126. // Free the ROM address since we do not need it anymore.
  1127. //
  1128. romAddress = VideoPortGetRomImage(hwDeviceExtension, NULL, 0, 0);
  1129. }
  1130. if (hwDeviceExtension->culTableEntries == 0) {
  1131. //
  1132. // No initialization table, but Perm3 really needs one in order
  1133. // to come out of sleep mode correctly.
  1134. //
  1135. GenerateInitializationTable(hwDeviceExtension);
  1136. }
  1137. }
  1138. VOID
  1139. CopyROMInitializationTable(
  1140. PHW_DEVICE_EXTENSION hwDeviceExtension,
  1141. PVOID pvROMAddress
  1142. )
  1143. /*+++
  1144. Routine Description:
  1145. This function should be called for devices that have an expansion ROM
  1146. which contains a register initialisation table. The function assumes
  1147. the ROM is present.
  1148. Arguments:
  1149. HwDeviceExtension
  1150. Points to the device extension of the device whose ROM is to be read
  1151. pvROMAddress
  1152. Base address of the expansion ROM. This function assumes that the
  1153. offset to the initialization table is defined at 0x1c from the
  1154. beginning of ROM
  1155. ---*/
  1156. {
  1157. PULONG pulROMTable;
  1158. PULONG pul;
  1159. ULONG cEntries;
  1160. ULONG ul, regHdr;
  1161. hwDeviceExtension->culTableEntries = 0;
  1162. //
  1163. // The 2-byte offset to the initialization table is given at 0x1c
  1164. // from the start of ROM
  1165. //
  1166. ul = VideoPortReadRegisterUshort((USHORT *)(0x1c + (PCHAR)pvROMAddress));
  1167. pulROMTable = (PULONG)(ul + (PCHAR)pvROMAddress);
  1168. //
  1169. // The table header (32 bits) has an identification code and a count
  1170. // of the number of entries in the table
  1171. //
  1172. regHdr = VideoPortReadRegisterUlong(pulROMTable++);
  1173. while ((regHdr >> 16) == 0x3d3d) {
  1174. ULONG BiosID = (regHdr >> 8) & 0xFF;
  1175. switch (BiosID){
  1176. case 0:
  1177. //
  1178. // BIOS partition 0
  1179. // ----------------
  1180. // This BIOS region holds the memory timings for Perm3 chip.
  1181. // We also look up the version number.
  1182. //
  1183. //
  1184. // the 2-byte BIOS version number in in the form of
  1185. // <MajorNum>.<MinorNum>
  1186. //
  1187. hwDeviceExtension->BiosVersionMajorNumber =
  1188. (ULONG)VideoPortReadRegisterUchar((PCHAR)(0x7 + (PCHAR)pvROMAddress) );
  1189. hwDeviceExtension->BiosVersionMinorNumber =
  1190. (ULONG)VideoPortReadRegisterUchar((PCHAR)(0x8 + (PCHAR)pvROMAddress));
  1191. //
  1192. // number of register address & data pairs
  1193. //
  1194. cEntries = regHdr & 0xffff;
  1195. if(cEntries > 0) {
  1196. //
  1197. // This assert, and the one after the copy should ensure
  1198. // we don't write past the end of the table
  1199. //
  1200. PERM3_ASSERT( cEntries * sizeof(ULONG) * 2 <= sizeof(hwDeviceExtension->aulInitializationTable),
  1201. "Perm3: too many initialization entries\n");
  1202. //
  1203. // Each entry contains two 32-bit words
  1204. //
  1205. pul = hwDeviceExtension->aulInitializationTable;
  1206. ul = cEntries << 1;
  1207. //
  1208. // Make sure we don't run out of the range
  1209. //
  1210. if( ul <= MAX_REGISTER_INITIALIZATION_TABLE_ULONGS &&
  1211. ul * sizeof(ULONG) + (ULONG)((PCHAR)pulROMTable - (PCHAR)pvROMAddress) <=
  1212. ROM_MAPPED_LENGTH ) {
  1213. while(ul--) {
  1214. *pul++ = VideoPortReadRegisterUlong(pulROMTable);
  1215. ++pulROMTable;
  1216. }
  1217. hwDeviceExtension->culTableEntries =
  1218. (ULONG)(pul - (ULONG *)hwDeviceExtension->aulInitializationTable) >> 1;
  1219. PERM3_ASSERT( cEntries == hwDeviceExtension->culTableEntries,
  1220. "Perm3: generated different size init table to that expected\n");
  1221. #if DBG
  1222. //
  1223. // Output the initialization table
  1224. //
  1225. pul = hwDeviceExtension->aulInitializationTable;
  1226. ul = hwDeviceExtension->culTableEntries;
  1227. while(ul--) {
  1228. ULONG ulReg;
  1229. ULONG ulRegData;
  1230. ulReg = *pul++;
  1231. ulRegData = *pul++;
  1232. VideoDebugPrint((3, "Perm3: CopyROMInitializationTable: register %08.8Xh with %08.8Xh\n",
  1233. ulReg, ulRegData));
  1234. }
  1235. #endif
  1236. }
  1237. }
  1238. break;
  1239. case 1:
  1240. //
  1241. // BIOS partition 1
  1242. // ----------------
  1243. // This BIOS region holds the extended clock settings
  1244. // for Perm3 chips.
  1245. //
  1246. PERM3_ASSERT((regHdr & 0xffff) == 0x0103,
  1247. "Perm3: Extended table doesn't have right cnt/ID\n");
  1248. if ((ULONG)((PUCHAR)pulROMTable - (PUCHAR)pvROMAddress) + 5 * sizeof(ULONG) <=
  1249. ROM_MAPPED_LENGTH) {
  1250. //
  1251. // Some Perm3 boards have a whole set of clocks defined in
  1252. // the BIOS. The high nibble defines the source for the
  1253. // clock, this isn't relevant for anything but MCLK and
  1254. // SCLK on Perm3.
  1255. //
  1256. hwDeviceExtension->bHaveExtendedClocks = TRUE;
  1257. hwDeviceExtension->ulPXRXCoreClock =
  1258. ( VideoPortReadRegisterUlong(pulROMTable++) & 0xFFFFFF ) * 1000 * 1000;
  1259. hwDeviceExtension->ulPXRXMemoryClock =
  1260. VideoPortReadRegisterUlong(pulROMTable++);
  1261. hwDeviceExtension->ulPXRXMemoryClockSrc =
  1262. (hwDeviceExtension->ulPXRXMemoryClock >> 28) << 4;
  1263. hwDeviceExtension->ulPXRXMemoryClock =
  1264. (hwDeviceExtension->ulPXRXMemoryClock & 0xFFFFFF) * 1000 * 1000;
  1265. hwDeviceExtension->ulPXRXSetupClock =
  1266. VideoPortReadRegisterUlong(pulROMTable++);
  1267. hwDeviceExtension->ulPXRXSetupClockSrc =
  1268. (hwDeviceExtension->ulPXRXSetupClock >> 28) << 4;
  1269. hwDeviceExtension->ulPXRXSetupClock =
  1270. (hwDeviceExtension->ulPXRXSetupClock & 0xFFFFFF) * 1000 * 1000;
  1271. hwDeviceExtension->ulPXRXGammaClock =
  1272. (VideoPortReadRegisterUlong(pulROMTable++) & 0xFFFFFF) * 1000 * 1000;
  1273. hwDeviceExtension->ulPXRXCoreClockAlt =
  1274. (VideoPortReadRegisterUlong(pulROMTable++) & 0xFFFFFF) * 1000 * 1000;
  1275. VideoDebugPrint((3, "Perm3: core clock %d, core clock alt %d\n",
  1276. hwDeviceExtension->ulPXRXCoreClock,
  1277. hwDeviceExtension->ulPXRXCoreClockAlt));
  1278. VideoDebugPrint((3, "Perm3: Mem clock %d, mem clock src 0x%x\n",
  1279. hwDeviceExtension->ulPXRXMemoryClock,
  1280. hwDeviceExtension->ulPXRXMemoryClockSrc));
  1281. VideoDebugPrint((3, "Perm3: setup clock %d, setup clock src 0x%x\n",
  1282. hwDeviceExtension->ulPXRXSetupClock,
  1283. hwDeviceExtension->ulPXRXSetupClockSrc));
  1284. VideoDebugPrint((3, "Perm3: Gamma clock %d\n",
  1285. hwDeviceExtension->ulPXRXGammaClock));
  1286. }
  1287. break;
  1288. default:
  1289. VideoDebugPrint((3, "Perm3: Extended table doesn't have right cnt/ID !\n"));
  1290. }
  1291. if ((ULONG)((PUCHAR)pulROMTable - (PUCHAR)pvROMAddress) >=
  1292. ROM_MAPPED_LENGTH) {
  1293. break;
  1294. }
  1295. regHdr = VideoPortReadRegisterUlong(pulROMTable++);
  1296. }
  1297. }
  1298. VOID
  1299. GenerateInitializationTable(
  1300. PHW_DEVICE_EXTENSION hwDeviceExtension
  1301. )
  1302. /*+++
  1303. Routine Description:
  1304. Creates a register initialization table (called if we can't read one
  1305. from ROM). If VGA is enabled the registers are already initialized so
  1306. we just read them back, otherwise we have to use default values
  1307. Arguments:
  1308. HwDeviceExtension
  1309. Points to the driver's per-device storage area.
  1310. ---*/
  1311. {
  1312. ULONG cEntries;
  1313. PULONG pul;
  1314. ULONG ul;
  1315. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  1316. hwDeviceExtension->culTableEntries = 0;
  1317. cEntries = 4;
  1318. //
  1319. // This assert, and the one after the copy should ensure we don't
  1320. // write past the end of the table
  1321. //
  1322. PERM3_ASSERT(cEntries * sizeof(ULONG) * 2 <= sizeof(hwDeviceExtension->aulInitializationTable),
  1323. "Perm3: too many initialization entries\n");
  1324. //
  1325. // Each entry contains two 32-bit words
  1326. //
  1327. pul = hwDeviceExtension->aulInitializationTable;
  1328. if (hwDeviceExtension->bVGAEnabled) {
  1329. //
  1330. // No initialization table but VGA is running so our key
  1331. // registers have been initialized to sensible values
  1332. //
  1333. //
  1334. // key entries are: ROM control, Boot Address, Memory Config
  1335. // and VStream Config
  1336. //
  1337. *pul++ = CTRL_REG_OFFSET(PXRX_LOCAL_MEM_CAPS);
  1338. *pul++ = VideoPortReadRegisterUlong(PXRX_LOCAL_MEM_CAPS);
  1339. *pul++ = CTRL_REG_OFFSET(PXRX_LOCAL_MEM_CONTROL);
  1340. *pul++ = VideoPortReadRegisterUlong(PXRX_LOCAL_MEM_CONTROL);
  1341. *pul++ = CTRL_REG_OFFSET(PXRX_LOCAL_MEM_REFRESH);
  1342. *pul++ = VideoPortReadRegisterUlong(PXRX_LOCAL_MEM_REFRESH);
  1343. *pul++ = CTRL_REG_OFFSET(PXRX_LOCAL_MEM_TIMING);
  1344. *pul++ = VideoPortReadRegisterUlong(PXRX_LOCAL_MEM_TIMING);
  1345. } else {
  1346. *pul++ = CTRL_REG_OFFSET(PXRX_LOCAL_MEM_CAPS);
  1347. *pul++ = 0x30E311B8;
  1348. *pul++ = CTRL_REG_OFFSET(PXRX_LOCAL_MEM_CONTROL);
  1349. *pul++ = 0x08000002; // figures for 80 MHz
  1350. *pul++ = CTRL_REG_OFFSET(PXRX_LOCAL_MEM_REFRESH);
  1351. *pul++ = 0x0000006B;
  1352. *pul++ = CTRL_REG_OFFSET(PXRX_LOCAL_MEM_TIMING);
  1353. *pul++ = 0x08501204;
  1354. }
  1355. hwDeviceExtension->culTableEntries =
  1356. (ULONG)(pul - (ULONG *)hwDeviceExtension->aulInitializationTable) >> 1;
  1357. #if DBG
  1358. if (cEntries != hwDeviceExtension->culTableEntries)
  1359. VideoDebugPrint((0, "Perm3: generated different size init table to that expected\n"));
  1360. //
  1361. // Output the initialization table
  1362. //
  1363. pul = hwDeviceExtension->aulInitializationTable;
  1364. ul = hwDeviceExtension->culTableEntries;
  1365. while(ul--) {
  1366. ULONG ulReg;
  1367. ULONG ulRegData;
  1368. ulReg = *pul++;
  1369. ulRegData = *pul++;
  1370. VideoDebugPrint((3, "Perm3: GenerateInitializationTable: register %08.8Xh with %08.8Xh\n",
  1371. ulReg, ulRegData));
  1372. }
  1373. #endif
  1374. }
  1375. VOID
  1376. ProcessInitializationTable(
  1377. PHW_DEVICE_EXTENSION hwDeviceExtension
  1378. )
  1379. /*+++
  1380. Routine Description:
  1381. This function processes the register initialization table
  1382. ---*/
  1383. {
  1384. PULONG pul;
  1385. ULONG cul;
  1386. ULONG ulRegAddr, ulRegData;
  1387. PULONG pulReg;
  1388. ULONG BaseAddrSelect;
  1389. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  1390. pul = (PULONG)hwDeviceExtension->aulInitializationTable;
  1391. cul = hwDeviceExtension->culTableEntries;
  1392. while(cul--) {
  1393. ulRegAddr = *pul++;
  1394. ulRegData = *pul++;
  1395. BaseAddrSelect = ulRegAddr >> 29;
  1396. if(BaseAddrSelect == 0) {
  1397. //
  1398. // The offset is from the start of the control registers
  1399. //
  1400. pulReg = (PULONG)((ULONG_PTR)pCtrlRegs + (ulRegAddr & 0x3FFFFF));
  1401. } else {
  1402. continue;
  1403. }
  1404. VideoDebugPrint((3, "ProcessInitializationTable: initializing (region %d) register %08.8Xh with %08.8Xh\n",
  1405. BaseAddrSelect, pulReg, ulRegData));
  1406. VideoPortWriteRegisterUlong(pulReg, ulRegData);
  1407. }
  1408. //
  1409. // We need a small delay after initializing the above registers
  1410. //
  1411. VideoPortStallExecution(5);
  1412. }
  1413. /*++
  1414. Routine Description:
  1415. This function is called when a bugcheck EA occurs due to a failure in
  1416. the perm3 display driver. The callback allows the driver to collect
  1417. information that will make diagnosing the problem easier. This data
  1418. is then added to the dump file that the system creates when the crash
  1419. occurs.
  1420. Arguments:
  1421. HwDeviceExtension
  1422. Points to the device extension of the device whose ROM is to be read
  1423. BugcheckCode
  1424. The bugcheck code for which this callback is being invoked. Currently
  1425. this will always be 0xEA.
  1426. Buffer
  1427. The location into which you should write the data you want to append
  1428. to the dump file.
  1429. BufferSize
  1430. The size of the buffer supplied.
  1431. Returns:
  1432. none
  1433. Notes:
  1434. This routine can be called at any time, and at any IRQL level.
  1435. Thus you must not touch any pageable code or data in this function.
  1436. USE_SYSTEM_RESERVED_SPACE code is for testing the usage of reserved
  1437. space during the bugcheck callback
  1438. HANG_IN_CALLBACK code is for testing the bugcheck recovery mechanism's
  1439. response to a hang occuring in the bugcheck callback.
  1440. --*/
  1441. //#define HANG_IN_CALLBACK
  1442. //#define USE_SYSTEM_RESERVED_SPACE
  1443. VOID
  1444. Perm3BugcheckCallback(
  1445. PVOID HwDeviceExtension,
  1446. ULONG BugcheckCode,
  1447. PUCHAR Buffer,
  1448. ULONG BufferSize
  1449. )
  1450. {
  1451. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  1452. ULONG DataSize;
  1453. //
  1454. // Copy the data you want to append to the minidump here. You may want
  1455. // to collect data on the hardware state, driver state, or any other
  1456. // data that may help you diagnose the 0xEA via the dump file.
  1457. //
  1458. static char szStart[] = "This is the sample perm3 bugcheck data!";
  1459. static char szEnd[] = "End of Data!";
  1460. if (BufferSize <= BUGCHECK_DATA_SIZE_RESERVED) return;
  1461. DataSize = min(PERM3_BUGCHECK_DATA_SIZE,
  1462. BufferSize - BUGCHECK_DATA_SIZE_RESERVED);
  1463. #ifdef USE_SYSTEM_RESERVED_SPACE
  1464. ++DataSize;
  1465. #endif //USE_SYSTEM_RESERVED_SPACE
  1466. if (DataSize > (sizeof(szStart) + sizeof(szEnd))) {
  1467. memset(Buffer, (int)'.', DataSize);
  1468. memcpy(Buffer, szStart, sizeof(szStart) - 1);
  1469. memcpy(Buffer + DataSize - sizeof(szEnd), szEnd, sizeof(szEnd));
  1470. }
  1471. else {
  1472. strncpy(Buffer, szStart, DataSize);
  1473. }
  1474. #ifdef HANG_IN_CALLBACK
  1475. while (1);
  1476. #endif // HANG_IN_CALLBACK
  1477. }