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.

332 lines
9.0 KiB

  1. //***************************************************************************
  2. //
  3. // Module Name:
  4. //
  5. // interupt.c
  6. //
  7. // Abstract:
  8. //
  9. // This module contains code to control interrupts for Permedia2. The
  10. // interrupt handler performs operations required by the display driver.
  11. // To communicate between the two we set up a piece of non-paged shared
  12. // memory to contain synchronization information and a queue for DMA
  13. // buffers.
  14. //
  15. // Environment:
  16. //
  17. // Kernel mode
  18. //
  19. //
  20. // Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
  21. // Copyright (c) 1995-1999 Microsoft Corporation. All Rights Reserved.
  22. //
  23. //***************************************************************************
  24. #include "permedia.h"
  25. #pragma alloc_text(PAGE,Permedia2InitializeInterruptBlock)
  26. #pragma optimize("x",on)
  27. //
  28. // *** THIS ROUTINE CANNOT BE PAGED ***
  29. //
  30. BOOLEAN
  31. Permedia2VidInterrupt(
  32. PVOID HwDeviceExtension
  33. )
  34. /*++
  35. Routine Description:
  36. Interrupts are enabled by the DD as and when they are needed. The miniport
  37. simply indicates via the Capabilities flags whether interrupts are
  38. available.
  39. Arguments:
  40. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  41. Return Value:
  42. --*/
  43. {
  44. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  45. PINTERRUPT_CONTROL_BLOCK pBlock;
  46. ULONG intrFlags;
  47. ULONG enableFlags;
  48. P2_DECL;
  49. if(hwDeviceExtension->PreviousPowerState != VideoPowerOn)
  50. {
  51. //
  52. // We reach here because we are sharing IRQ with other devices
  53. // and another device on the chain is in D0 and functioning
  54. //
  55. return FALSE;
  56. }
  57. intrFlags = VideoPortReadRegisterUlong(INT_FLAGS);
  58. enableFlags = VideoPortReadRegisterUlong(INT_ENABLE);
  59. //
  60. // if this a SVGA interrupt, some one must have enabled SVGA interrupt
  61. // by accident. We should first disable interrupt from SVGA unit and
  62. // then dismiss then current interupt
  63. //
  64. if(intrFlags & INTR_SVGA_SET) {
  65. USHORT usData;
  66. UCHAR OldIndex;
  67. //
  68. // Disable interrupt from SVGA unit
  69. //
  70. OldIndex = VideoPortReadRegisterUchar(PERMEDIA_MMVGA_INDEX_REG);
  71. VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_INDEX_REG,
  72. PERMEDIA_VGA_CTRL_INDEX);
  73. usData = (USHORT)VideoPortReadRegisterUchar(PERMEDIA_MMVGA_DATA_REG);
  74. usData &= ~PERMEDIA_VGA_INTERRUPT_ENABLE;
  75. usData = (usData << 8) | PERMEDIA_VGA_CTRL_INDEX;
  76. VideoPortWriteRegisterUshort(PERMEDIA_MMVGA_INDEX_REG, usData);
  77. VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_INDEX_REG,
  78. OldIndex);
  79. //
  80. // Dismiss current SVGA interrupt
  81. //
  82. OldIndex = VideoPortReadRegisterUchar(PERMEDIA_MMVGA_CRTC_INDEX_REG);
  83. VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_CRTC_INDEX_REG,
  84. PERMEDIA_VGA_CR11_INDEX);
  85. usData = (USHORT)VideoPortReadRegisterUchar(PERMEDIA_MMVGA_CRTC_DATA_REG);
  86. usData &= ~PERMEDIA_VGA_SYNC_INTERRUPT;
  87. usData = (usData << 8) | PERMEDIA_VGA_CR11_INDEX;
  88. VideoPortWriteRegisterUshort(PERMEDIA_MMVGA_CRTC_INDEX_REG, usData);
  89. VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_CRTC_INDEX_REG,
  90. OldIndex);
  91. return TRUE;
  92. }
  93. //
  94. // find out what caused the interrupt. We AND with the enabled interrupts
  95. // since the flags are set if the event occurred even though no interrupt
  96. // was enabled.
  97. //
  98. intrFlags &= enableFlags;
  99. if (intrFlags == 0)
  100. return FALSE;
  101. //
  102. // select the interrupt control block for this board
  103. //
  104. pBlock = hwDeviceExtension->InterruptControl.ControlBlock;
  105. VideoPortWriteRegisterUlong(INT_FLAGS, intrFlags);
  106. if (pBlock == NULL) return TRUE;
  107. #if DBG
  108. //
  109. // if this error handler bugchecks, we have a synchronization problem
  110. // with the display driver
  111. //
  112. if (intrFlags & INTR_ERROR_SET)
  113. {
  114. ULONG ulError = VideoPortReadRegisterUlong (ERROR_FLAGS);
  115. if (ulError & (0xf|0x700))
  116. {
  117. pBlock->ulLastErrorFlags=ulError;
  118. pBlock->ulErrorCounter++;
  119. DEBUG_PRINT((0, "***Error Interrupt!!!(%lxh)\n", ulError));
  120. }
  121. VideoPortWriteRegisterUlong ( ERROR_FLAGS, ulError);
  122. }
  123. pBlock->ulIRQCounter++;
  124. if (intrFlags & INTR_VBLANK_SET)
  125. {
  126. pBlock->ulControl |= VBLANK_INTERRUPT_AVAILABLE;
  127. pBlock->ulVSIRQCounter++;
  128. }
  129. #endif
  130. if (intrFlags & INTR_DMA_SET)
  131. {
  132. pBlock->ulControl |= DMA_INTERRUPT_AVAILABLE;
  133. //
  134. // lock access to shared memory section first
  135. //
  136. if (VideoPortInterlockedExchange((LONG*)&pBlock->ulICBLock,TRUE))
  137. {
  138. return TRUE;
  139. }
  140. if (VideoPortReadRegisterUlong(DMA_COUNT) == 0)
  141. {
  142. if (pBlock->pDMAWritePos>pBlock->pDMANextStart)
  143. {
  144. VideoPortWriteRegisterUlong(DMA_ADDRESS,
  145. (ULONG)(pBlock->liDMAPhysAddress.LowPart +
  146. (pBlock->pDMANextStart-
  147. pBlock->pDMABufferStart)
  148. *sizeof(ULONG)));
  149. VideoPortWriteRegisterUlong(DMA_COUNT,
  150. (ULONG)(pBlock->pDMAWritePos-pBlock->pDMANextStart));
  151. pBlock->pDMAWriteEnd = pBlock->pDMABufferEnd;
  152. pBlock->pDMAPrevStart = pBlock->pDMANextStart;
  153. pBlock->pDMANextStart = pBlock->pDMAWritePos;
  154. } else if (pBlock->pDMAWritePos<pBlock->pDMANextStart)
  155. {
  156. VideoPortWriteRegisterUlong(DMA_ADDRESS,
  157. (ULONG)(pBlock->liDMAPhysAddress.LowPart +
  158. (pBlock->pDMANextStart-
  159. pBlock->pDMABufferStart)
  160. *sizeof(ULONG)));
  161. VideoPortWriteRegisterUlong(DMA_COUNT,
  162. (ULONG)(pBlock->pDMAActualBufferEnd-pBlock->pDMANextStart));
  163. pBlock->pDMAActualBufferEnd=pBlock->pDMABufferEnd;
  164. pBlock->pDMAPrevStart=pBlock->pDMANextStart;
  165. pBlock->pDMAWriteEnd =pBlock->pDMANextStart-1;
  166. pBlock->pDMANextStart=pBlock->pDMABufferStart;
  167. } else //if (pBlock->pDMAWritePos==pBlock->pDMANextStart)
  168. {
  169. //
  170. // turn off IRQ service if we are idle...
  171. //
  172. VideoPortWriteRegisterUlong(INT_ENABLE, enableFlags & ~INTR_DMA_SET);
  173. }
  174. }
  175. //
  176. // release lock, we are done
  177. //
  178. VideoPortInterlockedExchange((LONG*)&pBlock->ulICBLock,FALSE);
  179. }
  180. return TRUE;
  181. }
  182. #pragma optimize("",on)
  183. BOOLEAN
  184. Permedia2InitializeInterruptBlock(
  185. PHW_DEVICE_EXTENSION hwDeviceExtension
  186. )
  187. /*++
  188. Routine Description:
  189. Do any initialization needed for interrupts, such as allocating the shared
  190. memory control block.
  191. Arguments:
  192. HwDeviceExtension - Supplies a pointer to the miniport's device extension.
  193. Return Value:
  194. --*/
  195. {
  196. PINTERRUPT_CONTROL_BLOCK pBlock;
  197. PVOID virtAddr;
  198. ULONG size;
  199. PHYSICAL_ADDRESS phyadd;
  200. ULONG ActualSize;
  201. //
  202. // allocate a page of non-paged memory. This will be used as the shared
  203. // memory between the display driver and the interrupt handler. Since
  204. // it's only a page in size the physical addresses are contiguous. So
  205. // we can use this as a small DMA buffer.
  206. //
  207. size = PAGE_SIZE;
  208. virtAddr = VideoPortGetCommonBuffer( hwDeviceExtension,
  209. size,
  210. PAGE_SIZE,
  211. &phyadd,
  212. &ActualSize,
  213. TRUE );
  214. hwDeviceExtension->InterruptControl.ControlBlock = virtAddr;
  215. hwDeviceExtension->InterruptControl.Size = ActualSize;
  216. if ( (virtAddr == NULL) || (ActualSize < size) )
  217. {
  218. DEBUG_PRINT((1, "ExAllocatePool failed for interrupt control block\n"));
  219. return(FALSE);
  220. }
  221. VideoPortZeroMemory( virtAddr, size);
  222. //
  223. // We can't flush the cache from the interrupt handler because we must be
  224. // running at <= DISPATCH_LEVEL to call KeFlushIoBuffers. So we need a DPC
  225. // to do the cache flush.
  226. //
  227. DEBUG_PRINT((2, "Initialized custom DPC routine for cache flushing\n"));
  228. P2_ASSERT((sizeof(INTERRUPT_CONTROL_BLOCK) <= size),
  229. "InterruptControlBlock is too big. Fix the driver!!\n");
  230. //
  231. // set up the control block
  232. //
  233. pBlock = virtAddr;
  234. pBlock->ulMagicNo = P2_ICB_MAGICNUMBER;
  235. //
  236. // we rely on the pBlock data being set to zero after allocation!
  237. //
  238. return(TRUE);
  239. }
  240.