Source code of Windows XP (NT5)
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.

465 lines
10 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. rcautils.c
  5. Abstract:
  6. Utility routines called by entry point functions. Split out into
  7. a separate file to keep the "entry point" files clean.
  8. Revision History:
  9. Who When What
  10. -------- -------- ----------------------------------------------
  11. rmachin 2-18-97 Created (from pxutils)
  12. DChen 3-16-98 Bug fixing and cleanup
  13. JameelH 4-18-98 Cleanup
  14. Notes:
  15. --*/
  16. #include "precomp.h"
  17. #include "atm.h"
  18. #include "stdio.h"
  19. #define MODULE_NUMBER MODULE_UTIL
  20. #define _FILENUMBER 'LITU'
  21. NTSTATUS
  22. RCAIoComplete(
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN PIRP Irp,
  25. IN PVOID Context
  26. )
  27. /*++
  28. Routine Description:
  29. Callback function for KsStreamIo() - invoked when stream write is complete.
  30. Here we just free any packets we allocated, return any NDIS packets back to NDIS,
  31. and return the stream header to the global pool.
  32. Arguments:
  33. DeviceObject - Our Device Object
  34. Irp - The IRP that completed
  35. Context - A pointer to the stream header
  36. Return Value:
  37. STATUS_SUCCESS
  38. --*/
  39. {
  40. PRCA_STREAM_HEADER StreamHeader;
  41. PNDIS_BUFFER pNdisBuffer = 0;
  42. RCADEBUGP(RCA_INFO, ("RCAIoComplete(): enter, context == %x\n", Context));
  43. StreamHeader = (PRCA_STREAM_HEADER)Context;
  44. RCACoNdisReturnPacket(StreamHeader->NdisPacket);
  45. RCASHPoolReturn(StreamHeader);
  46. RCADEBUGP(RCA_INFO, ("RCAIoComplete(): exit"));
  47. return STATUS_SUCCESS;
  48. }
  49. VOID
  50. CopyStreamHeaderToIrp(
  51. IN PRCA_STREAM_HEADER NetRCAStreamHeader,
  52. IN PIRP Irp
  53. )
  54. {
  55. PIO_STACK_LOCATION IrpStack;
  56. ULONG NetBufferLength, BufferLength;
  57. PBYTE NetBuffer, Buffer;
  58. PKSSTREAM_HEADER NetStreamHdr, StreamHdr;
  59. PMDL NetMdl, Mdl;
  60. ULONG BytesLeft;
  61. ULONG BytesFree;
  62. ULONG BytesToCopy;
  63. ULONG BytesRead = 0;
  64. NetStreamHdr = &NetRCAStreamHeader->Header;
  65. NetBuffer = NetStreamHdr->Data;
  66. BytesLeft = NetStreamHdr->DataUsed;
  67. RCADEBUGP(RCA_INFO, ("CopyStreamHeaderToIrp(): Going to copy %lu bytes\n", BytesLeft));
  68. // read IRP
  69. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  70. BufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  71. StreamHdr = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
  72. StreamHdr->DataUsed = 0;
  73. //StreamHdr->PresentationTime.Time = StreamHdr->PresentationTime.Time;
  74. Mdl = Irp->MdlAddress;
  75. Buffer = MmGetSystemAddressForMdl(Mdl);
  76. Mdl = Mdl->Next;
  77. //
  78. // Enumerate the stream headers, filling in each one.
  79. // Assume the net IRP has one stream header
  80. //
  81. while (BytesLeft)
  82. {
  83. BytesFree = StreamHdr->FrameExtent - StreamHdr->DataUsed;
  84. if(BytesFree)
  85. {
  86. BytesToCopy = BytesFree < BytesLeft ? BytesFree : BytesLeft;
  87. BytesLeft -= BytesToCopy;
  88. RtlCopyMemory(Buffer+StreamHdr->DataUsed,
  89. NetBuffer,
  90. BytesToCopy);
  91. BytesRead += BytesToCopy;
  92. StreamHdr->DataUsed += BytesToCopy;
  93. BytesFree = StreamHdr->FrameExtent - StreamHdr->DataUsed;
  94. NetBuffer += BytesToCopy;
  95. }
  96. // read stream full?
  97. if (!BytesFree)
  98. {
  99. //StreamHdr->PresentationTime.Numerator = 1;
  100. //StreamHdr->PresentationTime.Denominator = 1;
  101. //StreamHdr->Duration = StreamHdr->DataUsed;
  102. //StreamHdr->OptionsFlags = KSSTREAM_HEADER_OPTIONSF_TIMEVALID | KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
  103. // get the next stream header
  104. BufferLength -= sizeof(KSSTREAM_HEADER);
  105. if (BufferLength)
  106. {
  107. StreamHdr++;
  108. StreamHdr->DataUsed = 0;
  109. //StreamHdr->PresentationTime.Time = StreamHdr->PresentationTime.Time + BytesRead;
  110. if(StreamHdr->FrameExtent)
  111. {
  112. if(Mdl)
  113. {
  114. Buffer = (PUCHAR) MmGetSystemAddressForMdl(Mdl);
  115. RCAAssert(Buffer);
  116. Mdl = Mdl->Next;
  117. }
  118. else
  119. {
  120. break;
  121. }
  122. }
  123. }
  124. else
  125. {
  126. break;
  127. }
  128. }
  129. }
  130. #if DBG
  131. if(BytesLeft)
  132. {
  133. RCADEBUGP(RCA_ERROR,("CopyIrpData: OOPS - There are bytes left over: BytesLeft = %d BytesRead = %d \n",
  134. BytesLeft, BytesRead));
  135. //RCAAssert(FALSE);
  136. }
  137. #endif
  138. // free the IRP's
  139. RCAIoComplete(NULL, NULL, (PVOID)NetRCAStreamHeader);
  140. Irp->IoStatus.Information = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  141. Irp->IoStatus.Status = STATUS_SUCCESS;
  142. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  143. }
  144. VOID
  145. RCAIoWorker(
  146. IN PNDIS_WORK_ITEM pNdisWorkItem,
  147. IN PVOID Context
  148. )
  149. /*++
  150. Routine Description:
  151. This is the work item for the capture filter bridge pins. It
  152. streams the data in the work queue associated with a pin
  153. instance to the next connected filter.
  154. Arguments:
  155. PVOID Context - pointer to bridge pin instance.
  156. Return:
  157. Nothing.
  158. Comments:
  159. Not pageable, uses SpinLocks.
  160. --*/
  161. {
  162. NTSTATUS Status;
  163. PLIST_ENTRY pList;
  164. PWORK_ITEM pWorkItem;
  165. PPIN_INSTANCE_BRIDGE PinInstance = (PPIN_INSTANCE_BRIDGE)Context;
  166. PRCA_STREAM_HEADER StreamHeader;
  167. #if AUDIO_SINK_FLAG
  168. PIRP Irp;
  169. PPIN_INSTANCE_DEVIO DevIoPin;
  170. #endif
  171. RCADEBUGP(RCA_INFO, ("RCAIoWorker(): enter\n"));
  172. RCA_ACQUIRE_BRIDGE_PIN_LOCK(PinInstance);
  173. while(!IsListEmpty(&PinInstance->WorkQueue))
  174. {
  175. RcaGlobal.QueueSize--;
  176. RCADEBUGP(RCA_LOUD,("RCAIoWorker: Queue-- is %d\n", RcaGlobal.QueueSize));
  177. pList = RemoveHeadList(&PinInstance->WorkQueue);
  178. pWorkItem = CONTAINING_RECORD(pList, WORK_ITEM, ListEntry);
  179. RCA_RELEASE_BRIDGE_PIN_LOCK(PinInstance);
  180. StreamHeader = pWorkItem->StreamHeader;
  181. #if AUDIO_SINK_FLAG
  182. DevIoPin = PinInstance->FilterInstance->DevIoPin;
  183. //
  184. // The DevIo pin could have gone away between when we queued this packet and now.
  185. //
  186. if (DevIoPin == NULL) {
  187. RCAIoComplete(NULL, NULL, (PVOID)StreamHeader);
  188. //
  189. // Have to continue instead of breaking because we have to IoComplete everything
  190. // in the queue.
  191. //
  192. RCA_ACQUIRE_BRIDGE_PIN_LOCK(PinInstance);
  193. continue;
  194. }
  195. if (DevIoPin->ConnectedAsSink) {
  196. if (IsListEmpty(&DevIoPin->ActiveQueue)) {
  197. //
  198. // No IRP waiting for data, so just dump it.
  199. //
  200. RCAIoComplete(NULL, NULL, (PVOID)StreamHeader);
  201. RCA_ACQUIRE_BRIDGE_PIN_LOCK(PinInstance);
  202. continue;
  203. }
  204. Irp = KsRemoveIrpFromCancelableQueue(&DevIoPin->ActiveQueue,
  205. &DevIoPin->QueueLock,
  206. KsListEntryHead,
  207. KsAcquireAndRemove);
  208. if (Irp == NULL) {
  209. //
  210. // No IRP waiting for data, so just dump it.
  211. //
  212. RCAIoComplete(NULL, NULL, (PVOID)StreamHeader);
  213. RCA_ACQUIRE_BRIDGE_PIN_LOCK(PinInstance);
  214. continue;
  215. }
  216. CopyStreamHeaderToIrp(StreamHeader, Irp);
  217. Status = NDIS_STATUS_SUCCESS;
  218. } else {
  219. #endif
  220. if (PinInstance->FilterInstance->NextFileObject == (PFILE_OBJECT)NULL) {
  221. RCADEBUGP(RCA_WARNING, ("RCAIoWorker(): NextFileObject is NULL\n"));
  222. // FIXME: Calling RCAIoComplete() with two null args is OK for now since we don't use
  223. // those args anyway. But this is bad coding because it will break if we ever
  224. // change RCAIoComplete() to use them. Fix by abstracting out the functionality
  225. // we want from RCAIoComplete into another function (which we can then call from
  226. // RCAIoComplete).
  227. RCAIoComplete(NULL, NULL, (PVOID)StreamHeader);
  228. //
  229. // FIXME: Leak: nothing ever completes the IRP here.
  230. //
  231. RCA_ACQUIRE_BRIDGE_PIN_LOCK(PinInstance);
  232. continue;
  233. }
  234. ASSERT(PinInstance->FilterInstance->NextFileObject);
  235. Status = KsStreamIo(PinInstance->FilterInstance->NextFileObject,
  236. NULL,
  237. NULL,
  238. RCAIoComplete,
  239. (PVOID)StreamHeader,
  240. KsInvokeOnSuccess | KsInvokeOnError | KsInvokeOnCancel,
  241. &RcaGlobal.SHPool.IoStatus,
  242. (PVOID)&StreamHeader->Header,
  243. StreamHeader->Header.Size,
  244. KSSTREAM_WRITE,
  245. KernelMode);
  246. if (!((Status == STATUS_SUCCESS) || (Status == STATUS_PENDING))) {
  247. RCADEBUGP(RCA_ERROR, ("KsStreamIo failed with Status == %x\n", Status));
  248. }
  249. #if AUDIO_SINK_FLAG
  250. }
  251. #endif
  252. RCA_ACQUIRE_BRIDGE_PIN_LOCK(PinInstance);
  253. }
  254. // Ok to schedule another work item now.
  255. PinInstance->bWorkItemQueued = FALSE;
  256. if (PinInstance->SignalMe) {
  257. RCADEBUGP(RCA_INFO, ("RCAIoWorker(): Unblocking PinDispatchClose()\n"));
  258. RCASignal(&PinInstance->Block, Status);
  259. }
  260. RCA_RELEASE_BRIDGE_PIN_LOCK(PinInstance);
  261. RCADEBUGP(RCA_INFO, ("RCAIoWorker(): exit\n"));
  262. }
  263. VOID
  264. RCASHPoolInit(
  265. VOID
  266. )
  267. /*++
  268. Routine Description:
  269. Initializes the global stream header pool from which all RCA filters will obtain stream
  270. headers.
  271. Arguments:
  272. (None)
  273. Return Value:
  274. (None)
  275. --*/
  276. {
  277. RCADEBUGP(RCA_INFO, ("RCASHPoolInit(): enter\n"));
  278. ExInitializeNPagedLookasideList(&RcaGlobal.SHPool.LookAsideList,
  279. NULL,
  280. NULL,
  281. 0,
  282. sizeof(RCA_STREAM_HEADER),
  283. RCA_TAG,
  284. (PAGE_SIZE / sizeof(RCA_STREAM_HEADER)));
  285. RcaGlobal.SHPool.FailCount = 0;
  286. RCADEBUGP(RCA_INFO, ("RCASHPoolInit(): exit\n"));
  287. }
  288. PRCA_STREAM_HEADER
  289. RCASHPoolGet(
  290. VOID
  291. )
  292. /*++
  293. Routine Description:
  294. Obtains an stream header from the global pool.
  295. Arguments:
  296. (None)
  297. Return Value:
  298. A pointer to the stream header, or NULL if no stream header could be obtained.
  299. --*/
  300. {
  301. PRCA_STREAM_HEADER StreamHeader;
  302. RCADEBUGP(RCA_INFO, ("RCASHPoolGet(): enter\n"));
  303. StreamHeader = (PRCA_STREAM_HEADER)(ExAllocateFromNPagedLookasideList(&RcaGlobal.SHPool.LookAsideList));
  304. if (StreamHeader == NULL) {
  305. InterlockedIncrement(&RcaGlobal.SHPool.FailCount);
  306. }
  307. RCADEBUGP(RCA_INFO, ("RCASHPoolGet(): exit\n"));
  308. return StreamHeader;
  309. }
  310. VOID
  311. RCASHPoolReturn(
  312. IN PRCA_STREAM_HEADER StreamHeader
  313. )
  314. /*++
  315. Routine Description:
  316. Returns a stream header to the global pool. The stream header will be recycled for use later.
  317. Arguments:
  318. StreamHeader - Pointer to the stream header being returned
  319. Return Value:
  320. (None)
  321. --*/
  322. {
  323. RCADEBUGP(RCA_INFO, ("RCASHPoolReturn(): enter\n"));
  324. ExFreeToNPagedLookasideList(&RcaGlobal.SHPool.LookAsideList,
  325. (PVOID)StreamHeader);
  326. RCADEBUGP(RCA_INFO, ("RCASHPoolReturn(): exit\n"));
  327. }
  328. VOID
  329. RCASHPoolFree(
  330. VOID
  331. )
  332. /*++
  333. Routine Description:
  334. Frees any stream headers in the global IRP pool.
  335. Arguments:
  336. (None)
  337. Return Value:
  338. (None)
  339. --*/
  340. {
  341. RCADEBUGP(RCA_INFO, ("RCASHPoolFree(): enter\n"));
  342. ExDeleteNPagedLookasideList(&RcaGlobal.SHPool.LookAsideList);
  343. RCADEBUGP(RCA_INFO, ("RCASHPoolFree(): exit\n"));
  344. }