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.

1424 lines
43 KiB

  1. /***************************************************************************\
  2. *
  3. * ************************
  4. * * MINIPORT SAMPLE CODE *
  5. * ************************
  6. *
  7. * Module Name:
  8. *
  9. * perm3io.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. #pragma alloc_text(PAGE,Perm3StartIO)
  27. #pragma alloc_text(PAGE,Perm3RetrieveGammaCallback)
  28. #pragma alloc_text(PAGE,SetCurrentVideoMode)
  29. #pragma alloc_text(PAGE,Perm3SetColorLookup)
  30. #pragma alloc_text(PAGE,Perm3GetClockSpeeds)
  31. #pragma alloc_text(PAGE,ZeroMemAndDac)
  32. #pragma alloc_text(PAGE,ReadChipClockSpeedFromROM)
  33. BOOLEAN
  34. Perm3StartIO(
  35. PVOID HwDeviceExtension,
  36. PVIDEO_REQUEST_PACKET RequestPacket
  37. )
  38. /*+++
  39. Routine Description:
  40. This routine is the main execution routine for the miniport driver. It
  41. accepts a Video Request Packet, performs the request, and then returns
  42. with the appropriate status.
  43. Arguments:
  44. HwDeviceExtension
  45. Supplies a pointer to the miniport's device extension.
  46. RequestPacket
  47. Pointer to the video request packet. This structure contains all
  48. the parameters originally passed to EngDeviceIoControl.
  49. Return Value:
  50. Return TRUE indicating that it has completed the request.
  51. ---*/
  52. {
  53. VP_STATUS status;
  54. ULONG inIoSpace;
  55. PVIDEO_MODE_INFORMATION modeInformation;
  56. PVIDEO_MEMORY_INFORMATION memoryInformation;
  57. PVIDEO_CLUT clutBuffer;
  58. ULONG RequestedMode;
  59. ULONG modeNumber;
  60. ULONG ulValue;
  61. PVIDEOPARAMETERS pVideoParams;
  62. HANDLE ProcessHandle;
  63. PPERM3_VIDEO_MODES ModeEntry;
  64. PERM3_VIDEO_FREQUENCIES FrequencyEntry;
  65. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  66. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  67. VIDEO_X86_BIOS_ARGUMENTS biosArguments;
  68. //
  69. // Switch on the IoContolCode in the RequestPacket. It indicates which
  70. // function must be performed by the driver.
  71. //
  72. switch (RequestPacket->IoControlCode) {
  73. case IOCTL_VIDEO_QUERY_REGISTRY_DWORD:
  74. VideoDebugPrint((3, "Perm3: got IOCTL_VIDEO_QUERY_REGISTRY_DWORD\n"));
  75. if ( RequestPacket->OutputBufferLength <
  76. (RequestPacket->StatusBlock->Information = sizeof(ULONG))) {
  77. status = ERROR_INSUFFICIENT_BUFFER;
  78. break;
  79. }
  80. status = VideoPortGetRegistryParameters(HwDeviceExtension,
  81. RequestPacket->InputBuffer,
  82. FALSE,
  83. Perm3RegistryCallback,
  84. &ulValue );
  85. if (status != NO_ERROR) {
  86. VideoDebugPrint((1, "Perm3: Reading registry entry %S failed\n",
  87. RequestPacket->InputBuffer));
  88. status = ERROR_INVALID_PARAMETER;
  89. break;
  90. }
  91. *(PULONG)(RequestPacket->OutputBuffer) = ulValue;
  92. break;
  93. case IOCTL_VIDEO_REG_SAVE_GAMMA_LUT:
  94. VideoDebugPrint((3, "Perm3: got IOCTL_VIDEO_REG_SAVE_GAMMA_LUT\n"));
  95. if ( RequestPacket->InputBufferLength <
  96. (RequestPacket->StatusBlock->Information = MAX_CLUT_SIZE)) {
  97. status = ERROR_INSUFFICIENT_BUFFER;
  98. break;
  99. }
  100. status = VideoPortSetRegistryParameters(HwDeviceExtension,
  101. L"DisplayGammaLUT",
  102. RequestPacket->InputBuffer,
  103. MAX_CLUT_SIZE);
  104. if (status != NO_ERROR) {
  105. VideoDebugPrint((0, "Perm3: VideoPortSetRegistryParameters failed to save gamma LUT\n"));
  106. }
  107. break;
  108. case IOCTL_VIDEO_REG_RETRIEVE_GAMMA_LUT:
  109. VideoDebugPrint((3, "Perm3: got IOCTL_VIDEO_REG_RETRIEVE_GAMMA_LUT\n"));
  110. if ( RequestPacket->OutputBufferLength <
  111. (RequestPacket->StatusBlock->Information = MAX_CLUT_SIZE)) {
  112. status = ERROR_INSUFFICIENT_BUFFER;
  113. break;
  114. }
  115. status = VideoPortGetRegistryParameters(HwDeviceExtension,
  116. L"DisplayGammaLUT",
  117. FALSE,
  118. Perm3RetrieveGammaCallback,
  119. RequestPacket->InputBuffer);
  120. if (status != NO_ERROR) {
  121. VideoDebugPrint((0, "Perm3: VideoPortGetRegistryParameters failed to retrieve gamma LUT\n"));
  122. }
  123. break;
  124. case IOCTL_VIDEO_MAP_INTERRUPT_CMD_BUF:
  125. {
  126. PPERM3_INTERRUPT_CTRLBUF pIntrCtrl;
  127. VideoDebugPrint((3, "Perm3: got IOCTL_VIDEO_MAP_INTERRUPT_CMD_BUF\n"));
  128. if (RequestPacket->OutputBufferLength <
  129. (RequestPacket->StatusBlock->Information = sizeof(PVOID))) {
  130. status = ERROR_INSUFFICIENT_BUFFER;
  131. break;
  132. }
  133. pIntrCtrl = &hwDeviceExtension->InterruptControl;
  134. if (!(hwDeviceExtension->Capabilities & CAPS_INTERRUPTS)) {
  135. status = ERROR_INVALID_PARAMETER;
  136. break;
  137. }
  138. //
  139. // display driver is in kernel so our address is valid
  140. //
  141. *(PVOID*)RequestPacket->OutputBuffer = &pIntrCtrl->ControlBlock;
  142. status = NO_ERROR;
  143. break;
  144. }
  145. case IOCTL_VIDEO_QUERY_DEVICE_INFO:
  146. VideoDebugPrint((3, "Perm3: QUERY_deviceInfo\n"));
  147. if ( RequestPacket->OutputBufferLength !=
  148. (RequestPacket->StatusBlock->Information = sizeof(Perm3_Device_Info))) {
  149. VideoDebugPrint((0, "Perm3: the requested size of device info is wrong!\n"));
  150. status = ERROR_INSUFFICIENT_BUFFER;
  151. break;
  152. }
  153. //
  154. // Copy our local PCI info to the output buffer
  155. //
  156. VideoPortMoveMemory( RequestPacket->OutputBuffer,
  157. &hwDeviceExtension->deviceInfo,
  158. sizeof(Perm3_Device_Info) );
  159. status = NO_ERROR;
  160. break;
  161. case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
  162. VideoDebugPrint((3, "Perm3: MapVideoMemory\n"));
  163. if ( (RequestPacket->OutputBufferLength <
  164. (RequestPacket->StatusBlock->Information =
  165. sizeof(VIDEO_MEMORY_INFORMATION))) ||
  166. (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
  167. status = ERROR_INSUFFICIENT_BUFFER;
  168. break;
  169. }
  170. memoryInformation = RequestPacket->OutputBuffer;
  171. memoryInformation->VideoRamBase = ((PVIDEO_MEMORY)
  172. (RequestPacket->InputBuffer))->RequestedVirtualAddress;
  173. memoryInformation->VideoRamLength =
  174. hwDeviceExtension->FrameLength;
  175. inIoSpace = hwDeviceExtension->PhysicalFrameIoSpace;
  176. //
  177. // Performance:
  178. //
  179. // Enable USWC on the P6 processor.
  180. //
  181. // We only do it for the frame buffer. Memory mapped registers
  182. // usually can not be mapped USWC
  183. //
  184. inIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  185. status = VideoPortMapMemory(HwDeviceExtension,
  186. hwDeviceExtension->PhysicalFrameAddress,
  187. &(memoryInformation->VideoRamLength),
  188. &inIoSpace,
  189. &(memoryInformation->VideoRamBase));
  190. if (status != NO_ERROR) {
  191. VideoDebugPrint((0, "Perm3: VideoPortMapMemory failed with error %d\n", status));
  192. break;
  193. }
  194. memoryInformation->FrameBufferBase = memoryInformation->VideoRamBase;
  195. memoryInformation->FrameBufferLength = memoryInformation->VideoRamLength;
  196. break;
  197. case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
  198. VideoDebugPrint((3, "Perm3: UnMapVideoMemory\n"));
  199. if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) {
  200. status = ERROR_INSUFFICIENT_BUFFER;
  201. break;
  202. }
  203. status = VideoPortUnmapMemory (HwDeviceExtension,
  204. ((PVIDEO_MEMORY) (RequestPacket->InputBuffer))->RequestedVirtualAddress,
  205. 0);
  206. break;
  207. case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
  208. VideoDebugPrint((3, "Perm3: QueryPublicAccessRanges\n"));
  209. {
  210. PVIDEO_PUBLIC_ACCESS_RANGES portAccess;
  211. ULONG physicalPortLength;
  212. PVOID VirtualAddress;
  213. PHYSICAL_ADDRESS PhysicalAddress;
  214. ULONG requiredOPSize;
  215. //
  216. // Calculate minimum size of return buffer. There is
  217. // 1 public access range for single graphics chip systems.
  218. //
  219. requiredOPSize = sizeof(VIDEO_PUBLIC_ACCESS_RANGES);
  220. //
  221. // Validate the output buffer length
  222. //
  223. if ( (RequestPacket->OutputBufferLength <
  224. (RequestPacket->StatusBlock->Information = requiredOPSize)) ||
  225. (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))) {
  226. status = ERROR_INSUFFICIENT_BUFFER;
  227. break;
  228. }
  229. ProcessHandle = (HANDLE)(((PVIDEO_MEMORY)
  230. (RequestPacket->InputBuffer))->RequestedVirtualAddress);
  231. if (ProcessHandle != (HANDLE)0) {
  232. //
  233. // map 4K area for a process
  234. //
  235. VideoDebugPrint((3, "Mapping in 4K area from Control registers\n"));
  236. VirtualAddress = (PVOID)ProcessHandle;
  237. PhysicalAddress = hwDeviceExtension->PhysicalRegisterAddress;
  238. PhysicalAddress.LowPart += 0x2000;
  239. physicalPortLength = 0x1000;
  240. } else {
  241. VideoDebugPrint((3, "Mapping in all Control registers\n"));
  242. VirtualAddress = NULL;
  243. PhysicalAddress = hwDeviceExtension->PhysicalRegisterAddress;
  244. physicalPortLength = hwDeviceExtension->RegisterLength;
  245. }
  246. portAccess = RequestPacket->OutputBuffer;
  247. portAccess->VirtualAddress = VirtualAddress;
  248. portAccess->InIoSpace = hwDeviceExtension->RegisterSpace;
  249. portAccess->MappedInIoSpace = portAccess->InIoSpace;
  250. status = VideoPortMapMemory(HwDeviceExtension,
  251. PhysicalAddress,
  252. &physicalPortLength,
  253. &(portAccess->MappedInIoSpace),
  254. &(portAccess->VirtualAddress));
  255. }
  256. break;
  257. case IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES:
  258. VideoDebugPrint((3, "Perm3: FreePublicAccessRanges\n"));
  259. if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) {
  260. status = ERROR_INSUFFICIENT_BUFFER;
  261. break;
  262. }
  263. status = VideoPortUnmapMemory(HwDeviceExtension,
  264. ((PVIDEO_MEMORY)(RequestPacket->InputBuffer))->RequestedVirtualAddress,
  265. 0);
  266. break;
  267. case IOCTL_VIDEO_QUERY_AVAIL_MODES:
  268. VideoDebugPrint((3, "Perm3: QueryAvailableModes\n"));
  269. if (RequestPacket->OutputBufferLength <
  270. (RequestPacket->StatusBlock->Information =
  271. hwDeviceExtension->monitorInfo.numAvailableModes
  272. * sizeof(VIDEO_MODE_INFORMATION)) ) {
  273. status = ERROR_INSUFFICIENT_BUFFER;
  274. } else {
  275. PPERM3_VIDEO_FREQUENCIES pFrequencyEntry;
  276. modeInformation = RequestPacket->OutputBuffer;
  277. if (!hwDeviceExtension->monitorInfo.frequencyTable) {
  278. VideoDebugPrint((0, "Perm3: hwDeviceExtension->monitorInfo.frequencyTable is null!\n"));
  279. status = ERROR_INVALID_PARAMETER;
  280. } else {
  281. for (pFrequencyEntry = hwDeviceExtension->monitorInfo.frequencyTable;
  282. pFrequencyEntry->BitsPerPel != 0;
  283. pFrequencyEntry++) {
  284. if (pFrequencyEntry->ModeValid) {
  285. if( pFrequencyEntry->ModeEntry ) {
  286. *modeInformation = pFrequencyEntry->ModeEntry->ModeInformation;
  287. modeInformation->Frequency = pFrequencyEntry->ScreenFrequency;
  288. modeInformation->ModeIndex = pFrequencyEntry->ModeIndex;
  289. modeInformation++;
  290. }
  291. }
  292. }
  293. status = NO_ERROR;
  294. }
  295. }
  296. break;
  297. case IOCTL_VIDEO_QUERY_CURRENT_MODE:
  298. VideoDebugPrint((3, "Perm3: Query current mode. Current mode is %d\n",
  299. hwDeviceExtension->ActiveModeEntry->ModeInformation.ModeIndex));
  300. if (RequestPacket->OutputBufferLength <
  301. (RequestPacket->StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION))) {
  302. status = ERROR_INSUFFICIENT_BUFFER;
  303. } else {
  304. *((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer) =
  305. hwDeviceExtension->ActiveModeEntry->ModeInformation;
  306. ((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer)->Frequency =
  307. hwDeviceExtension->ActiveFrequencyEntry.ScreenFrequency;
  308. status = NO_ERROR;
  309. }
  310. break;
  311. case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
  312. VideoDebugPrint((3, "Perm3: QueryNumAvailableModes (= %d)\n",
  313. hwDeviceExtension->monitorInfo.numAvailableModes));
  314. //
  315. // Find out the size of the data to be put in the the buffer and
  316. // return that in the status information (whether or not the
  317. // information is there). If the buffer passed in is not large
  318. // enough return an appropriate error code.
  319. //
  320. if (RequestPacket->OutputBufferLength <
  321. (RequestPacket->StatusBlock->Information =
  322. sizeof(VIDEO_NUM_MODES)) ) {
  323. status = ERROR_INSUFFICIENT_BUFFER;
  324. } else {
  325. ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->NumModes =
  326. hwDeviceExtension->monitorInfo.numAvailableModes;
  327. ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->ModeInformationLength =
  328. sizeof(VIDEO_MODE_INFORMATION);
  329. status = NO_ERROR;
  330. }
  331. break;
  332. case IOCTL_VIDEO_SET_CURRENT_MODE:
  333. VideoDebugPrint((3, "Perm3: SetCurrentMode\n"));
  334. //
  335. // Check if the size of the data in the input buffer is large enough.
  336. //
  337. if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE)) {
  338. RequestPacket->StatusBlock->Information = sizeof(VIDEO_MODE);
  339. status = ERROR_INSUFFICIENT_BUFFER;
  340. break;
  341. }
  342. RequestedMode = ((PVIDEO_MODE) RequestPacket->InputBuffer)->RequestedMode;
  343. modeNumber = RequestedMode & ~VIDEO_MODE_NO_ZERO_MEMORY;
  344. if ((modeNumber >= hwDeviceExtension->monitorInfo.numTotalModes) ||
  345. !(hwDeviceExtension->monitorInfo.frequencyTable[modeNumber].ModeValid)) {
  346. RequestPacket->StatusBlock->Information = hwDeviceExtension->monitorInfo.numTotalModes;
  347. status = ERROR_INVALID_PARAMETER;
  348. break;
  349. }
  350. ulValue = ((RequestedMode & VIDEO_MODE_NO_ZERO_MEMORY) == 0);
  351. status = SetCurrentVideoMode(hwDeviceExtension, modeNumber, (BOOLEAN)ulValue);
  352. if(status != NO_ERROR) {
  353. RequestPacket->StatusBlock->Information = modeNumber;
  354. }
  355. break;
  356. case IOCTL_VIDEO_SET_COLOR_REGISTERS:
  357. VideoDebugPrint((3, "Perm3: SetColorRegs\n"));
  358. clutBuffer = (PVIDEO_CLUT) RequestPacket->InputBuffer;
  359. status = Perm3SetColorLookup(hwDeviceExtension,
  360. clutBuffer,
  361. RequestPacket->InputBufferLength,
  362. FALSE, // Only update if different from cache
  363. TRUE); // Update cache entries as well as RAMDAC
  364. break;
  365. case IOCTL_VIDEO_GET_COLOR_REGISTERS:
  366. {
  367. const int cchMinLUTSize = 256 * 3;
  368. UCHAR *pLUTBuffer = (char *)RequestPacket->OutputBuffer;
  369. UCHAR red, green, blue;
  370. int index;
  371. VideoDebugPrint((3, "Perm3: GetColorRegs\n"));
  372. if ((int)RequestPacket->OutputBufferLength < cchMinLUTSize) {
  373. RequestPacket->StatusBlock->Information = cchMinLUTSize;
  374. status = ERROR_INSUFFICIENT_BUFFER;
  375. } else {
  376. P3RDRAMDAC *pP3RDRegs = (P3RDRAMDAC *)hwDeviceExtension->pRamdac;
  377. P3RD_PALETTE_START_RD(0);
  378. for (index = 0; index < 256; ++index) {
  379. P3RD_READ_PALETTE (red, green, blue);
  380. *pLUTBuffer++ = red;
  381. *pLUTBuffer++ = green;
  382. *pLUTBuffer++ = blue;
  383. }
  384. status = NO_ERROR;
  385. RequestPacket->StatusBlock->Information = RequestPacket->OutputBufferLength;
  386. }
  387. }
  388. break;
  389. case IOCTL_VIDEO_RESET_DEVICE:
  390. VideoDebugPrint((3, "Perm3: RESET_DEVICE\n"));
  391. if(hwDeviceExtension->bVGAEnabled) {
  392. //
  393. // Only reset the device if the monitor is on. If it is off,
  394. // then executing the int10 will turn it back on.
  395. //
  396. if (hwDeviceExtension->bMonitorPoweredOn) {
  397. //
  398. // Do an Int10 to mode 3 will put the VGA to a known state.
  399. //
  400. VideoPortZeroMemory(&biosArguments, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
  401. biosArguments.Eax = 0x0003;
  402. VideoPortInt10(HwDeviceExtension, &biosArguments);
  403. }
  404. }
  405. status = NO_ERROR;
  406. break;
  407. case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
  408. {
  409. PVIDEO_SHARE_MEMORY pShareMemory;
  410. PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
  411. PHYSICAL_ADDRESS shareAddress;
  412. PVOID virtualAddress;
  413. ULONG sharedViewSize;
  414. VideoDebugPrint((3, "Perm3: ShareVideoMemory\n"));
  415. if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION)) ||
  416. (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
  417. VideoDebugPrint((0, "Perm3: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
  418. status = ERROR_INSUFFICIENT_BUFFER;
  419. break;
  420. }
  421. pShareMemory = RequestPacket->InputBuffer;
  422. if ( (pShareMemory->ViewOffset > hwDeviceExtension->AdapterMemorySize) ||
  423. ((pShareMemory->ViewOffset + pShareMemory->ViewSize) >
  424. hwDeviceExtension->AdapterMemorySize) ) {
  425. VideoDebugPrint((0, "Perm3: IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INVALID_PARAMETER\n"));
  426. status = ERROR_INVALID_PARAMETER;
  427. break;
  428. }
  429. RequestPacket->StatusBlock->Information =
  430. sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
  431. //
  432. // Beware: the input buffer and the output buffer are the same
  433. // buffer, and therefore data should not be copied from one to the
  434. // other
  435. //
  436. virtualAddress = pShareMemory->ProcessHandle;
  437. sharedViewSize = pShareMemory->ViewSize;
  438. inIoSpace = hwDeviceExtension->PhysicalFrameIoSpace;
  439. //
  440. // NOTE: we are ignoring ViewOffset
  441. //
  442. shareAddress.QuadPart =
  443. hwDeviceExtension->PhysicalFrameAddress.QuadPart;
  444. //
  445. // Performance:
  446. //
  447. // Enable USWC. We only do it for the frame buffer.
  448. // Memory mapped registers usually can not be mapped USWC
  449. //
  450. inIoSpace |= VIDEO_MEMORY_SPACE_P6CACHE;
  451. //
  452. // Unlike the MAP_MEMORY IOCTL, in this case we can not map extra
  453. // address space since the application could actually use the
  454. // pointer we return to it to touch locations in the address space
  455. // that do not have actual video memory in them.
  456. //
  457. // An app doing this would cause the machine to crash.
  458. //
  459. status = VideoPortMapMemory(hwDeviceExtension,
  460. shareAddress,
  461. &sharedViewSize,
  462. &inIoSpace,
  463. &virtualAddress);
  464. pShareMemoryInformation = RequestPacket->OutputBuffer;
  465. pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
  466. pShareMemoryInformation->VirtualAddress = virtualAddress;
  467. pShareMemoryInformation->SharedViewSize = sharedViewSize;
  468. }
  469. break;
  470. case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
  471. {
  472. PVIDEO_SHARE_MEMORY pShareMemory;
  473. VideoDebugPrint((3, "Perm3: UnshareVideoMemory\n"));
  474. if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY)) {
  475. status = ERROR_INSUFFICIENT_BUFFER;
  476. break;
  477. }
  478. pShareMemory = RequestPacket->InputBuffer;
  479. status = VideoPortUnmapMemory(hwDeviceExtension,
  480. pShareMemory->RequestedVirtualAddress,
  481. pShareMemory->ProcessHandle);
  482. }
  483. break;
  484. case IOCTL_VIDEO_QUERY_GENERAL_DMA_BUFFER:
  485. //
  486. // Return the line DMA buffer information. The
  487. // buffer size and virtual address will be zero if
  488. // the buffer couldn't be allocated.
  489. //
  490. if( (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = sizeof(GENERAL_DMA_BUFFER))) ||
  491. (RequestPacket->InputBufferLength != sizeof(ULONG)) ) {
  492. //
  493. // They've give us a duff buffer.
  494. //
  495. status = ERROR_INSUFFICIENT_BUFFER;
  496. } else {
  497. GENERAL_DMA_BUFFER *local = NULL, *remote = (PGENERAL_DMA_BUFFER) RequestPacket->OutputBuffer;
  498. ULONG *bufferNum = (PULONG) RequestPacket->InputBuffer;
  499. status = NO_ERROR;
  500. switch( *bufferNum ) {
  501. case 1:
  502. local = &hwDeviceExtension->LineDMABuffer;
  503. break;
  504. case 2:
  505. local = &hwDeviceExtension->P3RXDMABuffer;
  506. break;
  507. default:
  508. status = ERROR_INVALID_PARAMETER;
  509. break;
  510. }
  511. //
  512. // We need the buffer even if DMA/interrupts don't work
  513. //
  514. if(*bufferNum == 2 ||
  515. (local && hwDeviceExtension->Capabilities & CAPS_DMA_AVAILABLE)) {
  516. //
  517. // They've give us a correctly-sized buffer. So copy
  518. // the relevant buffer info.
  519. //
  520. *remote = *local;
  521. } else {
  522. remote->physAddr.LowPart = 0;
  523. remote->virtAddr = 0;
  524. remote->size = 0;
  525. }
  526. }
  527. break;
  528. case IOCTL_VIDEO_HANDLE_VIDEOPARAMETERS:
  529. VideoDebugPrint((3, "Perm3: HandleVideoParameters\n"));
  530. //
  531. // We don't support a tv connector so just return NO_ERROR here
  532. //
  533. pVideoParams = (PVIDEOPARAMETERS) (RequestPacket->InputBuffer);
  534. if (pVideoParams->dwCommand == VP_COMMAND_GET) {
  535. pVideoParams = (PVIDEOPARAMETERS) (RequestPacket->OutputBuffer);
  536. pVideoParams->dwFlags = 0;
  537. }
  538. RequestPacket->StatusBlock->Information = sizeof(VIDEOPARAMETERS);
  539. status = NO_ERROR;
  540. break;
  541. //
  542. // if we get here, an invalid IoControlCode was specified.
  543. //
  544. default:
  545. #if DBG
  546. VideoDebugPrint((3, "Perm3: Fell through perm3 startIO routine - invalid command (0x%x)\n", RequestPacket->IoControlCode));
  547. #endif
  548. status = ERROR_INVALID_FUNCTION;
  549. break;
  550. }
  551. RequestPacket->StatusBlock->Status = status;
  552. if( status != NO_ERROR )
  553. RequestPacket->StatusBlock->Information = 0;
  554. VideoDebugPrint((3, "Perm3: Leaving StartIO routine. Status = 0x%x, Information = 0x%x\n",
  555. RequestPacket->StatusBlock->Status, RequestPacket->StatusBlock->Information));
  556. return TRUE;
  557. } // end Perm3StartIO()
  558. VP_STATUS
  559. Perm3RetrieveGammaCallback(
  560. PVOID HwDeviceExtension,
  561. PVOID Context,
  562. PWSTR ValueName,
  563. PVOID ValueData,
  564. ULONG ValueLength
  565. )
  566. /*+++
  567. Routine Description:
  568. This routine is used to read back the gamma LUT from the registry.
  569. Arguments:
  570. HwDeviceExtension
  571. Supplies a pointer to the miniport's device extension.
  572. Context
  573. Context value passed to the get registry paramters routine
  574. ValueName
  575. Name of the value requested.
  576. ValueData
  577. Pointer to the requested data.
  578. ValueLength
  579. Length of the requested data.
  580. Return Value:
  581. if the variable doesn't exist return an error, else copy the gamma
  582. lut into the supplied pointer
  583. ---*/
  584. {
  585. if (ValueLength != MAX_CLUT_SIZE) {
  586. VideoDebugPrint((0, "Perm3: Perm3RetrieveGammaCallback got ValueLength of %d\n", ValueLength));
  587. return ERROR_INVALID_PARAMETER;
  588. }
  589. VideoPortMoveMemory(Context, ValueData, MAX_CLUT_SIZE);
  590. return NO_ERROR;
  591. } // end Perm3RetrieveGammaCallback()
  592. VP_STATUS
  593. SetCurrentVideoMode(
  594. PHW_DEVICE_EXTENSION hwDeviceExtension,
  595. ULONG modeNumber,
  596. BOOLEAN bZeroMemory
  597. )
  598. {
  599. PERM3_VIDEO_FREQUENCIES FrequencyEntry;
  600. PPERM3_VIDEO_MODES ModeEntry;
  601. ULONG ulValue;
  602. VP_STATUS rc = NO_ERROR;
  603. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  604. //
  605. // set the current mode, but turn off interrupts before we do so to
  606. // avoid any spurious video FIFO underrun errors - InitializeVideo can
  607. // opt to turn these on by setting hwDeviceExtension->IntEnable which
  608. // we'll load into INT_ENABLE before exiting from this routine
  609. //
  610. hwDeviceExtension->IntEnable = VideoPortReadRegisterUlong(INT_ENABLE);
  611. VideoPortWriteRegisterUlong( INT_ENABLE,
  612. hwDeviceExtension->IntEnable &
  613. ~(INTR_ERROR_SET | INTR_VBLANK_SET));
  614. //
  615. // disable stereo support
  616. //
  617. hwDeviceExtension->Capabilities &= ~CAPS_STEREO;
  618. //
  619. // Re-sample the clock speed. This allows us to change the clock speed
  620. // on the fly
  621. //
  622. Perm3GetClockSpeeds(hwDeviceExtension);
  623. FrequencyEntry = hwDeviceExtension->monitorInfo.frequencyTable[modeNumber];
  624. ModeEntry = FrequencyEntry.ModeEntry;
  625. //
  626. // At this point, 'ModeEntry' and 'FrequencyEntry' point to the necessary
  627. // table entries required for setting the requested mode.
  628. //
  629. //
  630. // Zero the DAC and the Screen buffer memory.
  631. //
  632. ulValue = modeNumber;
  633. if(!bZeroMemory)
  634. ulValue |= VIDEO_MODE_NO_ZERO_MEMORY;
  635. ZeroMemAndDac(hwDeviceExtension, ulValue);
  636. ModeEntry->ModeInformation.DriverSpecificAttributeFlags = hwDeviceExtension->Capabilities;
  637. //
  638. // For low resolution modes we may have to do various tricks
  639. // such as line doubling and getting the RAMDAC to zoom.
  640. // Record any such zoom in the Mode DeviceAttributes field.
  641. // Primarily this is to allow the display driver to compensate
  642. // when asked to move the cursor or change its shape.
  643. //
  644. // Currently, low res means lower than 512 pixels width.
  645. //
  646. if (FrequencyEntry.ScreenWidth < 512) {
  647. //
  648. // Permedia 3 does line doubling. If using a TVP we must
  649. // get it to zoom by 2 in X to get the pixel rate up.
  650. //
  651. ModeEntry->ModeInformation.DriverSpecificAttributeFlags |= CAPS_ZOOM_Y_BY2;
  652. }
  653. if (!InitializeVideo(hwDeviceExtension, &FrequencyEntry)) {
  654. VideoDebugPrint((0, "Perm3: InitializeVideo failed\n"));
  655. rc = ERROR_INVALID_PARAMETER;
  656. goto end;
  657. }
  658. //
  659. // Save the mode since we know the rest will work.
  660. //
  661. hwDeviceExtension->ActiveModeEntry = ModeEntry;
  662. hwDeviceExtension->ActiveFrequencyEntry = FrequencyEntry;
  663. //
  664. // Update VIDEO_MODE_INFORMATION fields
  665. //
  666. // Now that we've set the mode, we now know the screen stride, and
  667. // so can update some fields in the VIDEO_MODE_INFORMATION
  668. // structure for this mode. The Permedia 3 display driver is expected to
  669. // call IOCTL_VIDEO_QUERY_CURRENT_MODE to query these corrected
  670. // values.
  671. //
  672. //
  673. // Calculate the bitmap width (note the '+ 1' on BitsPerPlane is
  674. // so that '15bpp' works out right). 12bpp is special in that we
  675. // support it as sparse nibbles within a 32-bit pixel. ScreenStride
  676. // is in bytes; VideoMemoryBitmapWidth is measured in pixels;
  677. //
  678. if (ModeEntry->ModeInformation.BitsPerPlane != 12) {
  679. ModeEntry->ModeInformation.VideoMemoryBitmapWidth =
  680. ModeEntry->ModeInformation.ScreenStride / ((ModeEntry->ModeInformation.BitsPerPlane + 1) >> 3);
  681. } else {
  682. ModeEntry->ModeInformation.VideoMemoryBitmapWidth =
  683. ModeEntry->ModeInformation.ScreenStride >> 2;
  684. }
  685. ulValue = hwDeviceExtension->AdapterMemorySize;
  686. ModeEntry->ModeInformation.VideoMemoryBitmapHeight = ulValue / ModeEntry->ModeInformation.ScreenStride;
  687. end:
  688. //
  689. // set-up the interrupt enable
  690. //
  691. VideoPortWriteRegisterUlong(INT_ENABLE, hwDeviceExtension->IntEnable);
  692. return(rc);
  693. }
  694. VP_STATUS
  695. Perm3SetColorLookup(
  696. PHW_DEVICE_EXTENSION hwDeviceExtension,
  697. PVIDEO_CLUT ClutBuffer,
  698. ULONG ClutBufferSize,
  699. BOOLEAN ForceRAMDACWrite,
  700. BOOLEAN UpdateCache
  701. )
  702. /*+++
  703. Routine Description:
  704. This routine sets a specified portion of the color lookup table settings.
  705. Arguments:
  706. hwDeviceExtension
  707. Pointer to the miniport driver's device extension.
  708. ClutBufferSize
  709. Length of the input buffer supplied by the user.
  710. ClutBuffer
  711. Pointer to the structure containing the color lookup table.
  712. ForceRAMDACWrite
  713. When it is set to FALSE, only update if different from cache
  714. UpdateCache
  715. When it is set to TRUE, update cache entries as well as RAMDAC
  716. Return Value:
  717. VP_STATUS
  718. ---*/
  719. {
  720. USHORT i, j;
  721. //
  722. // Check if the size of the data in the input buffer is large enough.
  723. //
  724. if ( (ClutBufferSize < (sizeof(VIDEO_CLUT) - sizeof(ULONG))) ||
  725. (ClutBufferSize < (sizeof(VIDEO_CLUT) +
  726. (sizeof(ULONG) * (ClutBuffer->NumEntries - 1))) ) ) {
  727. VideoDebugPrint((0, "Perm3: Perm3SetColorLookup: insufficient buffer (was %d, min %d)\n",
  728. ClutBufferSize,
  729. (sizeof(VIDEO_CLUT) + (sizeof(ULONG) * (ClutBuffer->NumEntries - 1)))));
  730. return ERROR_INSUFFICIENT_BUFFER;
  731. }
  732. //
  733. // Check to see if the parameters are valid.
  734. //
  735. if ( (ClutBuffer->NumEntries == 0) ||
  736. (ClutBuffer->FirstEntry > VIDEO_MAX_COLOR_REGISTER) ||
  737. (ClutBuffer->FirstEntry + ClutBuffer->NumEntries >
  738. VIDEO_MAX_COLOR_REGISTER + 1) ) {
  739. VideoDebugPrint((0, "Perm3: Perm3SetColorLookup: invalid parameter\n"));
  740. return ERROR_INVALID_PARAMETER;
  741. }
  742. //
  743. // Set CLUT registers directly on the hardware.
  744. //
  745. {
  746. P3RDRAMDAC *pP3RDRegs = (P3RDRAMDAC *)hwDeviceExtension->pRamdac;
  747. PVIDEO_CLUT LUTCachePtr = &(hwDeviceExtension->LUTCache.LUTCache);
  748. //
  749. // RAMDAC Programming phase
  750. //
  751. for (i = 0, j = ClutBuffer->FirstEntry;
  752. i < ClutBuffer->NumEntries;
  753. i++, j++) {
  754. //
  755. // Update the RAMDAC entry if it has changed or if we have been
  756. // told to overwrite it.
  757. if (ForceRAMDACWrite ||
  758. ( LUTCachePtr->LookupTable[j].RgbLong !=
  759. ClutBuffer->LookupTable[i].RgbLong) ) {
  760. P3RD_LOAD_PALETTE_INDEX (j,
  761. ClutBuffer->LookupTable[i].RgbArray.Red,
  762. ClutBuffer->LookupTable[i].RgbArray.Green,
  763. ClutBuffer->LookupTable[i].RgbArray.Blue);
  764. }
  765. //
  766. // Update the cache, if instructed to do so
  767. //
  768. if (UpdateCache) {
  769. LUTCachePtr->LookupTable[j].RgbLong = ClutBuffer->LookupTable[i].RgbLong;
  770. }
  771. }
  772. }
  773. return NO_ERROR;
  774. }
  775. VOID
  776. Perm3GetClockSpeeds(
  777. PVOID HwDeviceExtension
  778. )
  779. /*+++
  780. Routine Description:
  781. Work out the chip clock speed and save in hwDeviceExtension.
  782. Arguments:
  783. hwDeviceExtension
  784. Supplies a pointer to the miniport's device extension.
  785. Return Value:
  786. On return the following values will be in hwDeviceExtension:
  787. ChipClockSpeed: this is the desired speed for the chip
  788. RefClockSpeed: this is the speed of the oscillator input on the board
  789. ---*/
  790. {
  791. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  792. ULONG ulValue;
  793. VP_STATUS status;
  794. //
  795. // force recalculation of clock speeds every time
  796. //
  797. hwDeviceExtension->ChipClockSpeed = 0;
  798. hwDeviceExtension->RefClockSpeed = 0;
  799. hwDeviceExtension->RefClockSpeed = 0;
  800. //
  801. // If a clock speed has been specified in the registry then validate it
  802. //
  803. status = VideoPortGetRegistryParameters(HwDeviceExtension,
  804. PERM3_REG_STRING_REFCLKSPEED,
  805. FALSE,
  806. Perm3RegistryCallback,
  807. &hwDeviceExtension->RefClockSpeed
  808. );
  809. if (status != NO_ERROR || hwDeviceExtension->RefClockSpeed == 0) {
  810. //
  811. // Use default setting
  812. //
  813. hwDeviceExtension->RefClockSpeed = 14318200;
  814. }
  815. status = VideoPortGetRegistryParameters(HwDeviceExtension,
  816. PERM3_REG_STRING_CORECLKSPEEDALT,
  817. FALSE,
  818. Perm3RegistryCallback,
  819. &hwDeviceExtension->ChipClockSpeedAlt
  820. );
  821. if (status != NO_ERROR || hwDeviceExtension->ChipClockSpeedAlt == 0) {
  822. //
  823. // If we have read the alt core clock speed from ROM then
  824. // we will have set hwDeviceExtension->bHaveExtendedClocks,
  825. // so use that value
  826. //
  827. if (hwDeviceExtension->bHaveExtendedClocks) {
  828. hwDeviceExtension->ChipClockSpeedAlt =
  829. hwDeviceExtension->ulPXRXCoreClockAlt;
  830. }
  831. //
  832. // If we haven't got a valid value then use the default
  833. //
  834. if (hwDeviceExtension->ChipClockSpeedAlt == 0) {
  835. hwDeviceExtension->ChipClockSpeedAlt =
  836. PERMEDIA3_DEFAULT_CLOCK_SPEED_ALT;
  837. }
  838. } else {
  839. hwDeviceExtension->ChipClockSpeedAlt *= 1000*1000;
  840. }
  841. //
  842. // Can override default chip clock speed in registry.
  843. //
  844. status = VideoPortGetRegistryParameters(HwDeviceExtension,
  845. PERM3_REG_STRING_CORECLKSPEED,
  846. FALSE,
  847. Perm3RegistryCallback,
  848. &hwDeviceExtension->ChipClockSpeed
  849. );
  850. //
  851. // If a clock speed has been specified in the registry
  852. // then validate it
  853. //
  854. if (status == NO_ERROR && hwDeviceExtension->ChipClockSpeed != 0) {
  855. hwDeviceExtension->ChipClockSpeed *= (1000*1000);
  856. if (hwDeviceExtension->ChipClockSpeed > PERMEDIA3_MAX_CLOCK_SPEED) {
  857. hwDeviceExtension->ChipClockSpeed = PERMEDIA3_MAX_CLOCK_SPEED;
  858. }
  859. } else {
  860. //
  861. // If the chip clock speed was not set in the registry
  862. // then read it from the ROM
  863. //
  864. if (hwDeviceExtension->ChipClockSpeed == 0) {
  865. //
  866. // On later BIOSes the core clock is in a different bit
  867. // of ROM and hwDeviceExtension->bHaveExtendedClocks will
  868. // be set to say that we have already read it from ROM.
  869. //
  870. if (hwDeviceExtension->bHaveExtendedClocks) {
  871. hwDeviceExtension->ChipClockSpeed =
  872. hwDeviceExtension->ulPXRXCoreClock;
  873. } else {
  874. ReadChipClockSpeedFromROM (
  875. hwDeviceExtension,
  876. &hwDeviceExtension->ChipClockSpeed );
  877. }
  878. //
  879. // If there isn't a clock-speed in the ROM then use
  880. // the defined default
  881. //
  882. if (hwDeviceExtension->ChipClockSpeed == 0) {
  883. hwDeviceExtension->ChipClockSpeed =
  884. PERMEDIA3_DEFAULT_CLOCK_SPEED;
  885. }
  886. }
  887. }
  888. VideoDebugPrint((3, "Perm3: Chip clock speed now set to %d Hz\n",
  889. hwDeviceExtension->ChipClockSpeed));
  890. VideoDebugPrint((3, "Perm3: Chip ALT clock speed now set to %d Hz\n",
  891. hwDeviceExtension->ChipClockSpeedAlt));
  892. VideoDebugPrint((3, "Perm3: Ref clock speed now set to %d Hz\n",
  893. hwDeviceExtension->RefClockSpeed));
  894. }
  895. VOID
  896. ZeroMemAndDac(
  897. PHW_DEVICE_EXTENSION hwDeviceExtension,
  898. ULONG RequestedMode
  899. )
  900. /*+++
  901. Routine Description:
  902. Initialize the DAC to 0 (black) and clear the framebuffer
  903. Arguments:
  904. hwDeviceExtension
  905. Supplies a pointer to the miniport's device extension.
  906. RequestedMode
  907. use the VIDEO_MODE_NO_ZERO_MEMORY bit to determine if the
  908. framebuffer should be cleared
  909. Return Value:
  910. None
  911. ---*/
  912. {
  913. ULONG i;
  914. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  915. P3RDRAMDAC *pP3RDRegs = (P3RDRAMDAC *)hwDeviceExtension->pRamdac;
  916. //
  917. // Turn off the screen at the DAC.
  918. //
  919. VideoDebugPrint((3, "Perm3: turning off readmask and zeroing LUT\n"));
  920. P3RD_SET_PIXEL_READMASK (0x0);
  921. P3RD_PALETTE_START_WR (0);
  922. for (i = 0; i <= VIDEO_MAX_COLOR_REGISTER; i++) {
  923. P3RD_LOAD_PALETTE (0, 0, 0);
  924. }
  925. if (!(RequestedMode & VIDEO_MODE_NO_ZERO_MEMORY)) {
  926. //
  927. // Zero the memory. Don't use Perm3 as we would have to save/restore
  928. // state and that's a pain. This is not time critical.
  929. //
  930. VideoPortZeroDeviceMemory(hwDeviceExtension->pFramebuffer,
  931. hwDeviceExtension->FrameLength);
  932. }
  933. //
  934. // Turn on the screen at the DAC
  935. //
  936. VideoDebugPrint((3, "Perm3: turning on readmask\n"));
  937. P3RD_SET_PIXEL_READMASK (0xff);
  938. LUT_CACHE_INIT();
  939. return;
  940. }
  941. VOID
  942. ReadChipClockSpeedFromROM (
  943. PHW_DEVICE_EXTENSION hwDeviceExtension,
  944. ULONG * pChipClkSpeed
  945. )
  946. /*+++
  947. Routine Description:
  948. Read the chip clock speed (in MHz) from the Video ROM BIOS
  949. (offset 0xA in the BIOS)
  950. Arguments:
  951. hwDeviceExtension - Supplies a pointer to the miniport's device extension.
  952. Return Value:
  953. none
  954. ---*/
  955. {
  956. //
  957. // Read the chip clock speed (in MHz) from the Video ROM BIOS (offset
  958. // 0xA in the BIOS)
  959. // This involves changing the aperture 2 register so aperture better
  960. // be completely idle or we could be in trouble; fortunately we only
  961. // call this function during a mode change and expect aperture 2 (the
  962. // FrameBuffer) to be idle
  963. //
  964. UCHAR clkSpeed;
  965. ULONG Default;
  966. UCHAR *p = (UCHAR *)hwDeviceExtension->pFramebuffer;
  967. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  968. Default = VideoPortReadRegisterUlong(APERTURE_TWO);
  969. //
  970. // r/w via aperture 2 actually go to ROM
  971. //
  972. VideoPortWriteRegisterUlong(APERTURE_TWO, Default | 0x200);
  973. //
  974. // If we have a valid ROM then read the clock pseed
  975. //
  976. if (VideoPortReadRegisterUshort ((USHORT *) p) == 0xAA55) {
  977. //
  978. // Get the clock speed
  979. //
  980. clkSpeed = VideoPortReadRegisterUchar(&(p[0xA]));
  981. //
  982. // Some boards, such as ones by Creative, have been know to set offset
  983. // 0xA to random-ish values. Creative use the following test to determine
  984. // whether they have a sensible value, so that is what we will use.
  985. //
  986. if (clkSpeed > 50) {
  987. *pChipClkSpeed = clkSpeed;
  988. *pChipClkSpeed *= (1000*1000);
  989. }
  990. VideoDebugPrint((3, "Perm3: ROM clk speed value 0x%x\n", (ULONG) VideoPortReadRegisterUchar(&(p[0xA]))));
  991. } else {
  992. VideoDebugPrint((0, "Perm3: Bad BIOS ROM header 0x%x\n", (ULONG) VideoPortReadRegisterUshort ((USHORT *) p)));
  993. }
  994. VideoPortWriteRegisterUlong(APERTURE_TWO, Default);
  995. }