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.

561 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation.
  3. Module Name:
  4. rcastrm.c
  5. Abstract:
  6. RCA Streaming routines.
  7. Author:
  8. Richard Machin (RMachin)
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. RMachin 2-25-97 stolen/adapted from msfsread and mswaveio
  13. DChen 3-12-98 Bug fixing and cleanup
  14. JameelH 4-18-98 Cleanup
  15. SPATHER 5-20-99 Cleanup. Re-orged to separate KS / NDIS parts.
  16. Notes:
  17. --*/
  18. #include <precomp.h>
  19. #define MODULE_NUMBER MODULE_STRM
  20. #define _FILENUMBER 'MRTS'
  21. VOID
  22. RCAReceiveCallback(
  23. IN PVOID RcaVcContext,
  24. IN PVOID ClientReceiveContext,
  25. IN PNDIS_PACKET pPacket
  26. )
  27. {
  28. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  29. PPIN_INSTANCE_DEVIO pDevioPin;
  30. PPIN_INSTANCE_BRIDGE pBridgePin;
  31. PRCA_STREAM_HEADER StreamHdr;
  32. PMDL pMdl;
  33. ULONG ulBufferLength;
  34. PWORK_ITEM pWorkItem;
  35. RCADEBUGP(RCA_INFO, ("RCAReceiveCallback: Enter\n"));
  36. do {
  37. //
  38. // Check that all our pins exist.
  39. //
  40. pBridgePin = (PPIN_INSTANCE_BRIDGE) ClientReceiveContext;
  41. if (pBridgePin == NULL) {
  42. RCADEBUGP(RCA_WARNING, ("RCAReceiveCallback: Bridge pin was null, dumping\n"));
  43. Status = NDIS_STATUS_FAILURE;
  44. break;
  45. }
  46. pDevioPin = pBridgePin->FilterInstance->DevIoPin;
  47. if (pDevioPin == NULL) {
  48. RCADEBUGP(RCA_WARNING, ("RCAReceiveCallback: Devio pin was null, dumping\n"));
  49. Status = NDIS_STATUS_FAILURE;
  50. break;
  51. }
  52. //
  53. // Check that the device is in the running state.
  54. //
  55. if (pDevioPin->DeviceState != KSSTATE_RUN) {
  56. RCADEBUGP(RCA_WARNING, ("RCAReceiveCallback: Device is not running, dumping\n"));
  57. Status = NDIS_STATUS_FAILURE;
  58. break;
  59. }
  60. //
  61. // If we're connected as an IRP source, check that there is someone to send IRPs to.
  62. //
  63. if (!(pDevioPin->ConnectedAsSink)) {
  64. if (pDevioPin->FilterInstance->NextFileObject == NULL) {
  65. RCADEBUGP(RCA_ERROR, ("RCAReceiveCallback: No device to stream to, dumping\n"));
  66. Status = NDIS_STATUS_FAILURE;
  67. break;
  68. }
  69. }
  70. //
  71. // Get a stream header and fill it out.
  72. //
  73. StreamHdr = RCASHPoolGet();
  74. if (StreamHdr == NULL) {
  75. RCADEBUGP(RCA_ERROR, ("RCAReceiveCallback: Could not get a stream header\n"));
  76. Status = NDIS_STATUS_FAILURE;
  77. break;
  78. }
  79. Status = RCACoNdisGetMdlFromPacket(pPacket, &pMdl);
  80. if (Status != NDIS_STATUS_SUCCESS) {
  81. RCADEBUGP(RCA_ERROR, ("RCAReceiveCallback: Could not get MDL from packet\n"));
  82. break;
  83. }
  84. ulBufferLength = MmGetMdlByteCount(pMdl);
  85. StreamHdr->Header.Size = sizeof (KSSTREAM_HEADER);
  86. StreamHdr->Header.TypeSpecificFlags = 0;
  87. StreamHdr->Header.PresentationTime.Time = 0; // FIXME: Fix this.
  88. StreamHdr->Header.PresentationTime.Numerator = 1;
  89. StreamHdr->Header.PresentationTime.Denominator = 1;
  90. StreamHdr->Header.DataUsed = ulBufferLength;
  91. StreamHdr->Header.FrameExtent = ulBufferLength;
  92. StreamHdr->Header.OptionsFlags = KSSTREAM_HEADER_OPTIONSF_TIMEVALID | KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
  93. StreamHdr->Header.Data = MmGetSystemAddressForMdl (pMdl); // data is in MDL address
  94. StreamHdr->Header.Duration = StreamHdr->Header.DataUsed; // just use all the data in the buffer
  95. StreamHdr->NdisPacket = pPacket;
  96. //
  97. // Make a worker thread stream the data.
  98. //
  99. pWorkItem = WORK_ITEM_FROM_PKT(pPacket);
  100. pWorkItem->StreamHeader = StreamHdr;
  101. RCA_ACQUIRE_BRIDGE_PIN_LOCK(pBridgePin);
  102. RcaGlobal.QueueSize++;
  103. InsertTailList(&pBridgePin->WorkQueue, &pWorkItem->ListEntry);
  104. if (!pBridgePin->bWorkItemQueued) {
  105. //
  106. // There is no work item pending, so we'll schedule one.
  107. //
  108. NdisInitializeWorkItem(&pBridgePin->WorkItem, RCAIoWorker, (PVOID)pBridgePin);
  109. NdisScheduleWorkItem(&pBridgePin->WorkItem);
  110. pBridgePin->bWorkItemQueued = TRUE;
  111. }
  112. RCA_RELEASE_BRIDGE_PIN_LOCK(pBridgePin);
  113. } while (FALSE);
  114. //
  115. // If something got botched, return the packet immediately.
  116. //
  117. if (Status != NDIS_STATUS_SUCCESS) {
  118. RCACoNdisReturnPacket(pPacket);
  119. }
  120. RCADEBUGP(RCA_INFO, ("RCAReceiveCallback: Exit\n"));
  121. }
  122. VOID
  123. RCASendCompleteCallback(
  124. IN PVOID RcaVcContext,
  125. IN PVOID ClientSendContext,
  126. IN PVOID PacketContext,
  127. IN PMDL pSentMdl,
  128. IN NDIS_STATUS Status
  129. )
  130. {
  131. PIRP pIrp = (PIRP) PacketContext;
  132. PIO_STACK_LOCATION pIrpSp;
  133. PPIN_INSTANCE_BRIDGE pBridgePin = (PPIN_INSTANCE_BRIDGE) ClientSendContext;
  134. RCADEBUGP(RCA_INFO, ("RCASendCompleteCallback: Enter\n"));
  135. //
  136. // Complete the IRP.
  137. //
  138. pIrp->IoStatus.Status = Status;
  139. if (!NT_SUCCESS(Status)) {
  140. RCADEBUGP(RCA_ERROR, ("RCASendCompleteCallback: "
  141. "Send failed with status 0x%x\n", Status));
  142. }
  143. pIrp->IoStatus.Information = 0;
  144. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  145. if (pBridgePin) {
  146. RCA_ACQUIRE_BRIDGE_PIN_LOCK(pBridgePin);
  147. pBridgePin->PendingSendsCount--;
  148. if ((pBridgePin->PendingSendsCount == 0) && pBridgePin->SignalWhenSendsComplete) {
  149. RCASignal(&pBridgePin->PendingSendsBlock, Status);
  150. }
  151. RCA_RELEASE_BRIDGE_PIN_LOCK(pBridgePin);
  152. }
  153. //
  154. // Free the MDL.
  155. //
  156. IoFreeMdl(pSentMdl);
  157. RCADEBUGP(RCA_INFO, ("RCASendCompleteCallback: Exit\n"));
  158. }
  159. VOID
  160. RCAVcCloseCallback(
  161. IN PVOID RcaVcContext,
  162. IN PVOID ClientReceiveContext,
  163. IN PVOID ClientSendContext
  164. )
  165. {
  166. PPIN_INSTANCE_BRIDGE pBridgePin;
  167. PVOID VcContextToRelease;
  168. if (ClientReceiveContext) {
  169. pBridgePin = (PPIN_INSTANCE_BRIDGE) ClientReceiveContext;
  170. RCA_ACQUIRE_BRIDGE_PIN_LOCK(pBridgePin);
  171. ASSERT(RcaVcContext == pBridgePin->VcContext);
  172. VcContextToRelease = pBridgePin->VcContext;
  173. pBridgePin->VcContext = NULL;
  174. if (pBridgePin->FilterInstance->DevIoPin)
  175. pBridgePin->FilterInstance->DevIoPin->VcContext = NULL;
  176. RCA_RELEASE_BRIDGE_PIN_LOCK(pBridgePin);
  177. RCACoNdisReleaseReceiveVcContext(VcContextToRelease);
  178. }
  179. if (ClientSendContext) {
  180. pBridgePin = (PPIN_INSTANCE_BRIDGE) ClientSendContext;
  181. RCA_ACQUIRE_BRIDGE_PIN_LOCK(pBridgePin);
  182. ASSERT(RcaVcContext == pBridgePin->VcContext);
  183. VcContextToRelease = pBridgePin->VcContext;
  184. pBridgePin->VcContext = NULL;
  185. if (pBridgePin->FilterInstance->DevIoPin)
  186. pBridgePin->FilterInstance->DevIoPin->VcContext = NULL;
  187. RCA_RELEASE_BRIDGE_PIN_LOCK(pBridgePin);
  188. RCACoNdisReleaseSendVcContext(VcContextToRelease);
  189. }
  190. }
  191. NTSTATUS
  192. ReadStream(
  193. IN PIRP Irp,
  194. IN PPIN_INSTANCE_DEVIO PinInstance
  195. )
  196. /*++
  197. Routine Description:
  198. Handles IOCTL_KS_READ_STREAM by reading data from the open VC.
  199. Arguments:
  200. Irp - Streaming Irp.
  201. Return Values:
  202. Returns STATUS_SUCCESS if the request was fulfilled.
  203. Else returns STATUS_PORT_DISCONNECTED if the VC has been closed (no FILE PIN in this
  204. context).
  205. some read error, or some parameter validation error.
  206. --*/
  207. {
  208. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  209. PFILTER_INSTANCE FilterInstance = PinInstance->FilterInstance;
  210. RCADEBUGP(RCA_LOUD, ("ReadStream: enter\n"));
  211. if (FilterInstance->FilterType == FilterTypeCapture)
  212. {
  213. if ((PinInstance->DeviceState == KSSTATE_RUN) ||
  214. (PinInstance->DeviceState == KSSTATE_PAUSE))
  215. {
  216. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); // Can be removed when the following debug print is removed
  217. RCADEBUGP(RCA_LOUD, ("ReadStream: Irp's output buffer length is: 0x%x\n",
  218. irpSp->Parameters.DeviceIoControl.OutputBufferLength));
  219. Status = KsProbeStreamIrp(Irp,
  220. KSPROBE_STREAMREAD | (KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK),
  221. sizeof(KSSTREAM_HEADER));
  222. if (NT_SUCCESS(Status))
  223. {
  224. #if AUDIO_SINK_FLAG
  225. KsAddIrpToCancelableQueue(&PinInstance->ActiveQueue,
  226. &PinInstance->QueueLock,
  227. Irp,
  228. KsListEntryTail,
  229. NULL);
  230. #endif
  231. Status = STATUS_PENDING;
  232. }
  233. else
  234. {
  235. RCADEBUGP(RCA_ERROR, ("ReadStream: "
  236. "KsProbeStreamIrp failed with Status == 0x%x\n",
  237. Status));
  238. }
  239. }
  240. }
  241. return(Status);
  242. }
  243. NTSTATUS
  244. WriteStream(
  245. IN PIRP Irp,
  246. IN PPIN_INSTANCE_DEVIO pDevIoPin
  247. )
  248. /*++
  249. Routine Description:
  250. Handles IOCTL_KS_WRITE_STREAM by writing data to the open VC.
  251. Arguments:
  252. Irp -
  253. Streaming Irp.
  254. Return Values:
  255. Returns STATUS_SUCCESS if the request was fulfilled (in which case the irp is pended
  256. until we complete it in our cosendcompletehandler.)
  257. Else returns an error, and the irp is completed back to the caller.
  258. --*/
  259. {
  260. NTSTATUS Status = 0;
  261. PVOID VcContext;
  262. PNDIS_PACKET pNdisPacket;
  263. ULONG BufferLength;
  264. PUCHAR SystemBuffer;
  265. PMDL pMdl;
  266. PVOID pMdlVirtualAddress;
  267. UINT bLength = 0;
  268. RCADEBUGP(RCA_LOUD, ("WriteStream: enter\n"));
  269. RCAAssert( KeGetCurrentIrql() == PASSIVE_LEVEL );
  270. RCA_ACQUIRE_BRIDGE_PIN_LOCK(pDevIoPin->FilterInstance->BridgePin);
  271. VcContext = pDevIoPin->VcContext;
  272. RCA_RELEASE_BRIDGE_PIN_LOCK(pDevIoPin->FilterInstance->BridgePin);
  273. //
  274. // FIXME: Now that we've released the lock, the VC could go away and
  275. // we'd be in trouble. Don't know how big this timing window
  276. // is.
  277. //
  278. do
  279. {
  280. ULONG BytesToCopy;
  281. if (VcContext == NULL)
  282. {
  283. RCADEBUGP(RCA_LOUD, ("WriteStream: no associated VC\n"));
  284. //
  285. // Bad sts will cause irp to be completed with sts in iostatus buffer
  286. //
  287. Status = STATUS_PORT_DISCONNECTED;
  288. break;
  289. }
  290. if (pDevIoPin->DeviceState != KSSTATE_RUN) {
  291. //
  292. // Device isn't "runnning".
  293. //
  294. Status = NDIS_STATUS_FAILURE;
  295. break;
  296. }
  297. //
  298. // Get the data in an MDL if it's not already. From the KsProbeStreamIrp code:
  299. //
  300. // Makes the specified modifications to the given IRP's input and output
  301. // buffers based on the specific streaming IOCTL in the current stack
  302. // location, and validates the stream header. The Irp end up in essentially
  303. // the METHOD_OUT_DIRECT or
  304. // METHOD_IN_DIRECT format, with the exception that the access to the data
  305. // buffer may be IoModifyAccess depending on the flags passed to this
  306. // function or in the stream header. If the stream buffers MDL's have been
  307. // allocated, they are available through the PIRP->MdlAddress. If extra data
  308. // has been requested, the copied list of headers with extra data area is
  309. // available in PIRP->Tail.Overlay.AuxiliaryBuffer.
  310. //
  311. Status = KsProbeStreamIrp(Irp,
  312. KSPROBE_STREAMWRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK,
  313. sizeof(KSSTREAM_HEADER));
  314. if (Status != STATUS_SUCCESS)
  315. {
  316. RCADEBUGP(RCA_WARNING,("WriteStream: KsProbeStreamIrp failed sts %x\n", Status));
  317. break;
  318. }
  319. if (!((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->DataUsed)
  320. {
  321. //
  322. // This IRP has no data, complete it immediately.
  323. //
  324. RCADEBUGP(RCA_WARNING, ("Irp %x has no data\n", Irp) );
  325. Status = STATUS_UNSUCCESSFUL;
  326. break;
  327. }
  328. //
  329. // Build a partial MDL containing only the dataused portion of this MDL
  330. //
  331. RCADEBUGP(RCA_INFO,("WriteStream: allocating MDL\n"));
  332. pMdlVirtualAddress = MmGetMdlVirtualAddress (Irp->MdlAddress);
  333. RCADEBUGP(RCA_INFO,("WriteStream: going to alloc an mdl of length %lu\n",
  334. ((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->DataUsed));
  335. pMdl = IoAllocateMdl(pMdlVirtualAddress,
  336. ((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->DataUsed,
  337. FALSE,
  338. FALSE,
  339. NULL);
  340. if (pMdl == NULL) {
  341. RCADEBUGP(RCA_WARNING,("WriteStream: STATUS_INSUFFICIENT_RESOURCES for MDL\n"));
  342. return(STATUS_INSUFFICIENT_RESOURCES);
  343. }
  344. RCADEBUGP(RCA_INFO,("WriteStream: building partial MDL\n"));
  345. BytesToCopy = ((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->DataUsed;
  346. //
  347. // For debugging only.
  348. //
  349. if (g_ulBufferSize > 0) {
  350. BytesToCopy = g_ulBufferSize;
  351. }
  352. IoBuildPartialMdl(Irp->MdlAddress,
  353. pMdl,
  354. pMdlVirtualAddress,
  355. BytesToCopy);
  356. //
  357. // TBS: wait for CSA soltion for passing header info across transform filters.
  358. // Now we're sure the header is in the system buffer. We also need to ship the header, since
  359. // we need the dataused number and (in future) CSA will specify timing and other info in there
  360. // that we need to get end-to-end. Allocate the MDL and put it on the end of the list
  361. //
  362. IoMarkIrpPending( Irp );
  363. RCA_ACQUIRE_BRIDGE_PIN_LOCK(pDevIoPin->FilterInstance->BridgePin);
  364. pDevIoPin->FilterInstance->BridgePin->PendingSendsCount++;
  365. RCA_RELEASE_BRIDGE_PIN_LOCK(pDevIoPin->FilterInstance->BridgePin);
  366. Status = RCACoNdisSendFrame(VcContext,
  367. pMdl,
  368. (PVOID)Irp);
  369. if (Status != NDIS_STATUS_PENDING) {
  370. RCADEBUGP(RCA_ERROR, ("WriteStream: RCACoNdisSendFrame returned status 0x%x, "
  371. "manually calling send complete handler\n", Status));
  372. RCASendCompleteCallback(VcContext,
  373. (PVOID) pDevIoPin->FilterInstance->BridgePin,
  374. (PVOID) Irp,
  375. pMdl,
  376. Status);
  377. }
  378. //
  379. // If status returned from RCACoNdisSendFrame was not STATUS_PENDING, then we
  380. // completed the IRP with that status. We need to set the status back to PENDING
  381. // here so that PinDispatchIoControl will not try to complete the IRP again.
  382. //
  383. Status = NDIS_STATUS_PENDING;
  384. } while (FALSE);
  385. return(Status);
  386. }
  387. NTSTATUS
  388. GetInterface(
  389. IN PIRP Irp,
  390. IN PKSPROPERTY Property,
  391. OUT PKSPIN_INTERFACE Interface
  392. )
  393. /*++
  394. Routine Description:
  395. Handles the KSPROPERTY_STREAM_INTERFACE property Get in the Stream property set.
  396. Returns the interface on the Dev I/O Pin so that positional translations can be
  397. performed.
  398. Arguments:
  399. Irp -
  400. Device control Irp.
  401. Property -
  402. Specific property request.
  403. Interface -
  404. The place in which to put the Interface.
  405. Return Values:
  406. Returns STATUS_SUCCESS.
  407. --*/
  408. {
  409. RCADEBUGP(RCA_INFO, ("GetInterface: Enter\n"));
  410. Interface->Set = KSINTERFACESETID_Standard;
  411. // Interface->Id = KSINTERFACE_STANDARD_POSITION;
  412. Irp->IoStatus.Information = sizeof(KSPIN_INTERFACE);
  413. RCADEBUGP(RCA_INFO, ("GetInterface: Exit - Returning STATUS_NOT_IMPLEMENTED\n"));
  414. DbgBreakPoint();
  415. return(STATUS_NOT_IMPLEMENTED);
  416. }
  417.