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.

299 lines
8.6 KiB

  1. /******************************Module*Header**********************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: dma.c
  8. *
  9. * Content: Handling of DMA buffers.
  10. *
  11. * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
  12. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
  13. \*****************************************************************************/
  14. #include "precomp.h"
  15. #include "glint.h"
  16. //
  17. // Normally, we should not use global variables but the DMA buffers provided
  18. // by the miniport are global across all PDEVs and need be initialized only
  19. // once.
  20. //
  21. typedef struct _DMA_INFORMATION {
  22. ULONG NumDMABuffers;
  23. QUERY_DMA_BUFFERS DMABuffer[1];
  24. } DMAInformation, *LPDMAInformation;
  25. LPDMAInformation gpDMABufferInfo = (LPDMAInformation)0;
  26. /******************************Public*Routine******************************\
  27. * VOID bGlintInitializeDMA
  28. *
  29. * Interrogate the miniport to see if DMA is supported. If it is, map in the
  30. * DMA buffers ready for use by the 3D extension.
  31. *
  32. \**************************************************************************/
  33. VOID vGlintInitializeDMA(PPDEV ppdev)
  34. {
  35. DMA_NUM_BUFFERS queryDMA;
  36. ULONG enableFlags;
  37. LONG Length;
  38. LONG ExtraLength;
  39. ULONG i;
  40. GLINT_DECL;
  41. glintInfo->pxrxDMA = &glintInfo->pxrxDMAnonInterrupt;
  42. return; //azntst for multimon
  43. // check the miniport has initialised DMA
  44. //
  45. glintInfo->MaxDMASubBuffers = 0;
  46. if (!(ppdev->flCaps & CAPS_DMA_AVAILABLE))
  47. {
  48. return;
  49. }
  50. // in the multi-board case we only want one set of DMA buffers which
  51. // are global across all boards. But we have an interrupt per board.
  52. // So if the DMA buffers are sorted out try setting up the interrupt.
  53. //
  54. if (gpDMABufferInfo != NULL)
  55. {
  56. goto TryInterrupts;
  57. }
  58. // query the number of DMA buffers. If this fails we have no DMA
  59. //
  60. if (EngDeviceIoControl(ppdev->hDriver,
  61. IOCTL_VIDEO_QUERY_NUM_DMA_BUFFERS,
  62. NULL,
  63. 0,
  64. &queryDMA,
  65. sizeof(DMA_NUM_BUFFERS),
  66. &Length))
  67. {
  68. DISPDBG((ERRLVL, "QUERY_NUM_DMA_BUFFERS failed: "
  69. "No GLINT DMA available"));
  70. return;
  71. }
  72. Length = queryDMA.NumBuffers * queryDMA.BufferInformationLength;
  73. ExtraLength = sizeof(DMAInformation) - sizeof(QUERY_DMA_BUFFERS);
  74. DISPDBG((ERRLVL, "%d DMA buffers available. Total info size = 0x%x",
  75. queryDMA.NumBuffers, Length));
  76. // allocate space for the DMA information
  77. //
  78. gpDMABufferInfo = (LPDMAInformation)ENGALLOCMEM(
  79. FL_ZERO_MEMORY,
  80. ExtraLength + Length,
  81. ALLOC_TAG_GDI(1));
  82. if (gpDMABufferInfo == NULL)
  83. {
  84. DISPDBG((ERRLVL, "vGlintInitializeDMA: Out of memory"));
  85. return;
  86. }
  87. gpDMABufferInfo->NumDMABuffers = queryDMA.NumBuffers;
  88. if (EngDeviceIoControl(ppdev->hDriver,
  89. IOCTL_VIDEO_QUERY_DMA_BUFFERS,
  90. NULL,
  91. 0,
  92. (PVOID)(&gpDMABufferInfo->DMABuffer[0]),
  93. Length,
  94. &Length))
  95. {
  96. ENGFREEMEM(gpDMABufferInfo);
  97. gpDMABufferInfo = NULL;
  98. DISPDBG((ERRLVL, "QUERY_DMA_BUFFERS failed: No GLINT DMA available"));
  99. return;
  100. }
  101. DISPDBG((ERRLVL, "IOCTL returned length %d", Length));
  102. // zero the flags for each record
  103. //
  104. for (i = 0; i < queryDMA.NumBuffers; ++i)
  105. {
  106. gpDMABufferInfo->DMABuffer[i].flags = 0;
  107. }
  108. #if DBG
  109. {
  110. ULONG j;
  111. PUCHAR pAddr;
  112. for (i = 0; i < queryDMA.NumBuffers; ++i)
  113. {
  114. DISPDBG((ERRLVL,"DMA buffer %d: phys 0x%x, virt 0x%x"
  115. ", size 0x%x, flags 0x%x", i,
  116. gpDMABufferInfo->DMABuffer[i].physAddr.LowPart,
  117. gpDMABufferInfo->DMABuffer[i].virtAddr,
  118. gpDMABufferInfo->DMABuffer[i].size,
  119. gpDMABufferInfo->DMABuffer[i].flags));
  120. pAddr = gpDMABufferInfo->DMABuffer[i].virtAddr;
  121. for (j = 0; j < gpDMABufferInfo->DMABuffer[i].size; ++j)
  122. *pAddr++ = (UCHAR)(j & 0xff);
  123. }
  124. }
  125. #endif
  126. TryInterrupts:
  127. if (!INTERRUPTS_ENABLED)
  128. {
  129. return;
  130. }
  131. // map in the interrupt command control block. This is a piece of memory
  132. // shared with the intrerrupt controller which allows us to send control
  133. // what happens on VBLANK and DMA interrupts.
  134. //
  135. Length = sizeof(PVOID);
  136. DISPDBG((WRNLVL, "calling IOCTL_VIDEO_MAP_INTERRUPT_CMD_BUF"));
  137. if (EngDeviceIoControl(ppdev->hDriver,
  138. IOCTL_VIDEO_MAP_INTERRUPT_CMD_BUF,
  139. NULL,
  140. 0,
  141. (PVOID)&(glintInfo->pInterruptCommandBlock),
  142. Length,
  143. &Length))
  144. {
  145. DISPDBG((ERRLVL, "IOCTL_VIDEO_MAP_INTERRUPT_CMD_BUF failed."));
  146. return;
  147. }
  148. #if DBG
  149. else
  150. {
  151. DISPDBG((WRNLVL, "got command buffer at 0x%x",
  152. glintInfo->pInterruptCommandBlock));
  153. DISPDBG((WRNLVL, "front, back, end indexes = %d, %d, %d",
  154. glintInfo->pInterruptCommandBlock->frontIndex,
  155. glintInfo->pInterruptCommandBlock->backIndex,
  156. glintInfo->pInterruptCommandBlock->endIndex));
  157. }
  158. #endif
  159. // if we get here we have both DMA and interrupts so set for interrupt
  160. // driven DMA. Don't turn on interrupts yet. That has to be done on a
  161. // per context basis.
  162. //
  163. DISPDBG((WRNLVL, "Using interrupt driven DMA"));
  164. glintInfo->flags |= GLICAP_INTERRUPT_DMA;
  165. glintInfo->MaxDMASubBuffers = glintInfo->pInterruptCommandBlock->maximumIndex;
  166. glintInfo->pxrxDMA = &glintInfo->pInterruptCommandBlock->pxrxDMA;
  167. return;
  168. }
  169. /******************************Public*Routine******************************\
  170. * ULONG anyFreeDMABuffers
  171. *
  172. * Return number of unused DMA buffers available
  173. *
  174. \**************************************************************************/
  175. ULONG anyFreeDMABuffers(void)
  176. {
  177. PQUERY_DMA_BUFFERS pDma;
  178. ULONG i;
  179. ULONG numAvailable = 0;
  180. if (!gpDMABufferInfo)
  181. {
  182. return 0;
  183. }
  184. pDma = &gpDMABufferInfo->DMABuffer[0];
  185. for (i = 0; i < gpDMABufferInfo->NumDMABuffers; ++i)
  186. {
  187. if (!(pDma->flags & DMA_BUFFER_INUSE))
  188. {
  189. numAvailable++;
  190. }
  191. ++pDma;
  192. }
  193. return numAvailable;
  194. }
  195. /******************************Public*Routine******************************\
  196. * ULONG GetFreeDMABuffer
  197. *
  198. * Return info about a DMA buffer and mark it as in use.
  199. * -1 is returned if no buffer is available.
  200. *
  201. \**************************************************************************/
  202. LONG GetFreeDMABuffer(PQUERY_DMA_BUFFERS dmaBuf)
  203. {
  204. PQUERY_DMA_BUFFERS pDma;
  205. ULONG i;
  206. if (!gpDMABufferInfo)
  207. {
  208. return(-1);
  209. }
  210. pDma = &gpDMABufferInfo->DMABuffer[0];
  211. for (i = 0; i < gpDMABufferInfo->NumDMABuffers; ++i)
  212. {
  213. if (!(pDma->flags & DMA_BUFFER_INUSE))
  214. {
  215. pDma->flags |= DMA_BUFFER_INUSE;
  216. *dmaBuf = *pDma;
  217. DISPDBG((WRNLVL, "Allocated DMA buffer %d", i));
  218. return(i);
  219. }
  220. ++pDma;
  221. }
  222. // all are in use
  223. DISPDBG((ERRLVL, "No more DMA buffers available"));
  224. return(-1);
  225. }
  226. /******************************Public*Routine******************************\
  227. * VOID FreeDMABuffer
  228. *
  229. * Mark the given DMA buffer as free. The caller passes in the physical
  230. * address of the buffer.
  231. *
  232. \**************************************************************************/
  233. VOID FreeDMABuffer(PVOID physAddr)
  234. {
  235. PQUERY_DMA_BUFFERS pDma;
  236. ULONG i;
  237. if (!gpDMABufferInfo)
  238. {
  239. return;
  240. }
  241. pDma = &gpDMABufferInfo->DMABuffer[0];
  242. for (i = 0; i < gpDMABufferInfo->NumDMABuffers; ++i)
  243. {
  244. if (pDma->physAddr.LowPart == (UINT_PTR)physAddr)
  245. {
  246. pDma->flags &= ~DMA_BUFFER_INUSE;
  247. break;
  248. }
  249. ++pDma;
  250. }
  251. return;
  252. }