mirror of https://github.com/tongzx/nt5src
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.
562 lines
14 KiB
562 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation.
|
|
|
|
Module Name:
|
|
|
|
rcastrm.c
|
|
|
|
Abstract:
|
|
|
|
RCA Streaming routines.
|
|
|
|
Author:
|
|
|
|
Richard Machin (RMachin)
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
RMachin 2-25-97 stolen/adapted from msfsread and mswaveio
|
|
DChen 3-12-98 Bug fixing and cleanup
|
|
JameelH 4-18-98 Cleanup
|
|
SPATHER 5-20-99 Cleanup. Re-orged to separate KS / NDIS parts.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
|
|
#define MODULE_NUMBER MODULE_STRM
|
|
#define _FILENUMBER 'MRTS'
|
|
|
|
|
|
|
|
VOID
|
|
RCAReceiveCallback(
|
|
IN PVOID RcaVcContext,
|
|
IN PVOID ClientReceiveContext,
|
|
IN PNDIS_PACKET pPacket
|
|
)
|
|
{
|
|
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PPIN_INSTANCE_DEVIO pDevioPin;
|
|
PPIN_INSTANCE_BRIDGE pBridgePin;
|
|
PRCA_STREAM_HEADER StreamHdr;
|
|
PMDL pMdl;
|
|
ULONG ulBufferLength;
|
|
PWORK_ITEM pWorkItem;
|
|
|
|
RCADEBUGP(RCA_INFO, ("RCAReceiveCallback: Enter\n"));
|
|
|
|
do {
|
|
//
|
|
// Check that all our pins exist.
|
|
//
|
|
pBridgePin = (PPIN_INSTANCE_BRIDGE) ClientReceiveContext;
|
|
|
|
if (pBridgePin == NULL) {
|
|
RCADEBUGP(RCA_WARNING, ("RCAReceiveCallback: Bridge pin was null, dumping\n"));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
pDevioPin = pBridgePin->FilterInstance->DevIoPin;
|
|
|
|
if (pDevioPin == NULL) {
|
|
RCADEBUGP(RCA_WARNING, ("RCAReceiveCallback: Devio pin was null, dumping\n"));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check that the device is in the running state.
|
|
//
|
|
|
|
if (pDevioPin->DeviceState != KSSTATE_RUN) {
|
|
RCADEBUGP(RCA_WARNING, ("RCAReceiveCallback: Device is not running, dumping\n"));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we're connected as an IRP source, check that there is someone to send IRPs to.
|
|
//
|
|
|
|
if (!(pDevioPin->ConnectedAsSink)) {
|
|
if (pDevioPin->FilterInstance->NextFileObject == NULL) {
|
|
RCADEBUGP(RCA_ERROR, ("RCAReceiveCallback: No device to stream to, dumping\n"));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get a stream header and fill it out.
|
|
//
|
|
|
|
StreamHdr = RCASHPoolGet();
|
|
|
|
if (StreamHdr == NULL) {
|
|
RCADEBUGP(RCA_ERROR, ("RCAReceiveCallback: Could not get a stream header\n"));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
Status = RCACoNdisGetMdlFromPacket(pPacket, &pMdl);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
RCADEBUGP(RCA_ERROR, ("RCAReceiveCallback: Could not get MDL from packet\n"));
|
|
break;
|
|
}
|
|
|
|
ulBufferLength = MmGetMdlByteCount(pMdl);
|
|
|
|
StreamHdr->Header.Size = sizeof (KSSTREAM_HEADER);
|
|
StreamHdr->Header.TypeSpecificFlags = 0;
|
|
StreamHdr->Header.PresentationTime.Time = 0; // FIXME: Fix this.
|
|
StreamHdr->Header.PresentationTime.Numerator = 1;
|
|
StreamHdr->Header.PresentationTime.Denominator = 1;
|
|
StreamHdr->Header.DataUsed = ulBufferLength;
|
|
StreamHdr->Header.FrameExtent = ulBufferLength;
|
|
StreamHdr->Header.OptionsFlags = KSSTREAM_HEADER_OPTIONSF_TIMEVALID | KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
|
|
|
|
StreamHdr->Header.Data = MmGetSystemAddressForMdl (pMdl); // data is in MDL address
|
|
StreamHdr->Header.Duration = StreamHdr->Header.DataUsed; // just use all the data in the buffer
|
|
|
|
StreamHdr->NdisPacket = pPacket;
|
|
|
|
//
|
|
// Make a worker thread stream the data.
|
|
//
|
|
pWorkItem = WORK_ITEM_FROM_PKT(pPacket);
|
|
pWorkItem->StreamHeader = StreamHdr;
|
|
|
|
RCA_ACQUIRE_BRIDGE_PIN_LOCK(pBridgePin);
|
|
|
|
RcaGlobal.QueueSize++;
|
|
|
|
InsertTailList(&pBridgePin->WorkQueue, &pWorkItem->ListEntry);
|
|
|
|
if (!pBridgePin->bWorkItemQueued) {
|
|
//
|
|
// There is no work item pending, so we'll schedule one.
|
|
//
|
|
NdisInitializeWorkItem(&pBridgePin->WorkItem, RCAIoWorker, (PVOID)pBridgePin);
|
|
NdisScheduleWorkItem(&pBridgePin->WorkItem);
|
|
pBridgePin->bWorkItemQueued = TRUE;
|
|
}
|
|
|
|
RCA_RELEASE_BRIDGE_PIN_LOCK(pBridgePin);
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// If something got botched, return the packet immediately.
|
|
//
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
RCACoNdisReturnPacket(pPacket);
|
|
}
|
|
|
|
RCADEBUGP(RCA_INFO, ("RCAReceiveCallback: Exit\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
RCASendCompleteCallback(
|
|
IN PVOID RcaVcContext,
|
|
IN PVOID ClientSendContext,
|
|
IN PVOID PacketContext,
|
|
IN PMDL pSentMdl,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
{
|
|
PIRP pIrp = (PIRP) PacketContext;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
PPIN_INSTANCE_BRIDGE pBridgePin = (PPIN_INSTANCE_BRIDGE) ClientSendContext;
|
|
|
|
RCADEBUGP(RCA_INFO, ("RCASendCompleteCallback: Enter\n"));
|
|
|
|
//
|
|
// Complete the IRP.
|
|
//
|
|
pIrp->IoStatus.Status = Status;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RCADEBUGP(RCA_ERROR, ("RCASendCompleteCallback: "
|
|
"Send failed with status 0x%x\n", Status));
|
|
}
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
|
|
if (pBridgePin) {
|
|
RCA_ACQUIRE_BRIDGE_PIN_LOCK(pBridgePin);
|
|
|
|
pBridgePin->PendingSendsCount--;
|
|
|
|
if ((pBridgePin->PendingSendsCount == 0) && pBridgePin->SignalWhenSendsComplete) {
|
|
RCASignal(&pBridgePin->PendingSendsBlock, Status);
|
|
}
|
|
|
|
RCA_RELEASE_BRIDGE_PIN_LOCK(pBridgePin);
|
|
}
|
|
|
|
//
|
|
// Free the MDL.
|
|
//
|
|
|
|
IoFreeMdl(pSentMdl);
|
|
|
|
RCADEBUGP(RCA_INFO, ("RCASendCompleteCallback: Exit\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
RCAVcCloseCallback(
|
|
IN PVOID RcaVcContext,
|
|
IN PVOID ClientReceiveContext,
|
|
IN PVOID ClientSendContext
|
|
)
|
|
{
|
|
PPIN_INSTANCE_BRIDGE pBridgePin;
|
|
PVOID VcContextToRelease;
|
|
|
|
if (ClientReceiveContext) {
|
|
pBridgePin = (PPIN_INSTANCE_BRIDGE) ClientReceiveContext;
|
|
|
|
RCA_ACQUIRE_BRIDGE_PIN_LOCK(pBridgePin);
|
|
|
|
ASSERT(RcaVcContext == pBridgePin->VcContext);
|
|
|
|
VcContextToRelease = pBridgePin->VcContext;
|
|
|
|
pBridgePin->VcContext = NULL;
|
|
if (pBridgePin->FilterInstance->DevIoPin)
|
|
pBridgePin->FilterInstance->DevIoPin->VcContext = NULL;
|
|
|
|
RCA_RELEASE_BRIDGE_PIN_LOCK(pBridgePin);
|
|
|
|
RCACoNdisReleaseReceiveVcContext(VcContextToRelease);
|
|
}
|
|
|
|
if (ClientSendContext) {
|
|
pBridgePin = (PPIN_INSTANCE_BRIDGE) ClientSendContext;
|
|
|
|
RCA_ACQUIRE_BRIDGE_PIN_LOCK(pBridgePin);
|
|
|
|
ASSERT(RcaVcContext == pBridgePin->VcContext);
|
|
|
|
VcContextToRelease = pBridgePin->VcContext;
|
|
|
|
pBridgePin->VcContext = NULL;
|
|
if (pBridgePin->FilterInstance->DevIoPin)
|
|
pBridgePin->FilterInstance->DevIoPin->VcContext = NULL;
|
|
|
|
RCA_RELEASE_BRIDGE_PIN_LOCK(pBridgePin);
|
|
|
|
RCACoNdisReleaseSendVcContext(VcContextToRelease);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ReadStream(
|
|
IN PIRP Irp,
|
|
IN PPIN_INSTANCE_DEVIO PinInstance
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles IOCTL_KS_READ_STREAM by reading data from the open VC.
|
|
|
|
Arguments:
|
|
|
|
Irp - Streaming Irp.
|
|
|
|
Return Values:
|
|
|
|
Returns STATUS_SUCCESS if the request was fulfilled.
|
|
Else returns STATUS_PORT_DISCONNECTED if the VC has been closed (no FILE PIN in this
|
|
context).
|
|
some read error, or some parameter validation error.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
PFILTER_INSTANCE FilterInstance = PinInstance->FilterInstance;
|
|
|
|
RCADEBUGP(RCA_LOUD, ("ReadStream: enter\n"));
|
|
|
|
if (FilterInstance->FilterType == FilterTypeCapture)
|
|
{
|
|
if ((PinInstance->DeviceState == KSSTATE_RUN) ||
|
|
(PinInstance->DeviceState == KSSTATE_PAUSE))
|
|
{
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); // Can be removed when the following debug print is removed
|
|
|
|
RCADEBUGP(RCA_LOUD, ("ReadStream: Irp's output buffer length is: 0x%x\n",
|
|
irpSp->Parameters.DeviceIoControl.OutputBufferLength));
|
|
|
|
Status = KsProbeStreamIrp(Irp,
|
|
KSPROBE_STREAMREAD | (KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK),
|
|
sizeof(KSSTREAM_HEADER));
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
#if AUDIO_SINK_FLAG
|
|
KsAddIrpToCancelableQueue(&PinInstance->ActiveQueue,
|
|
&PinInstance->QueueLock,
|
|
Irp,
|
|
KsListEntryTail,
|
|
NULL);
|
|
#endif
|
|
Status = STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
RCADEBUGP(RCA_ERROR, ("ReadStream: "
|
|
"KsProbeStreamIrp failed with Status == 0x%x\n",
|
|
Status));
|
|
}
|
|
}
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
WriteStream(
|
|
IN PIRP Irp,
|
|
IN PPIN_INSTANCE_DEVIO pDevIoPin
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles IOCTL_KS_WRITE_STREAM by writing data to the open VC.
|
|
|
|
Arguments:
|
|
|
|
Irp -
|
|
Streaming Irp.
|
|
|
|
Return Values:
|
|
|
|
Returns STATUS_SUCCESS if the request was fulfilled (in which case the irp is pended
|
|
until we complete it in our cosendcompletehandler.)
|
|
|
|
Else returns an error, and the irp is completed back to the caller.
|
|
--*/
|
|
{
|
|
NTSTATUS Status = 0;
|
|
PVOID VcContext;
|
|
PNDIS_PACKET pNdisPacket;
|
|
ULONG BufferLength;
|
|
PUCHAR SystemBuffer;
|
|
PMDL pMdl;
|
|
PVOID pMdlVirtualAddress;
|
|
UINT bLength = 0;
|
|
|
|
RCADEBUGP(RCA_LOUD, ("WriteStream: enter\n"));
|
|
|
|
RCAAssert( KeGetCurrentIrql() == PASSIVE_LEVEL );
|
|
|
|
RCA_ACQUIRE_BRIDGE_PIN_LOCK(pDevIoPin->FilterInstance->BridgePin);
|
|
|
|
VcContext = pDevIoPin->VcContext;
|
|
|
|
RCA_RELEASE_BRIDGE_PIN_LOCK(pDevIoPin->FilterInstance->BridgePin);
|
|
|
|
//
|
|
// FIXME: Now that we've released the lock, the VC could go away and
|
|
// we'd be in trouble. Don't know how big this timing window
|
|
// is.
|
|
//
|
|
|
|
do
|
|
{
|
|
ULONG BytesToCopy;
|
|
|
|
if (VcContext == NULL)
|
|
{
|
|
RCADEBUGP(RCA_LOUD, ("WriteStream: no associated VC\n"));
|
|
//
|
|
// Bad sts will cause irp to be completed with sts in iostatus buffer
|
|
//
|
|
Status = STATUS_PORT_DISCONNECTED;
|
|
break;
|
|
}
|
|
|
|
if (pDevIoPin->DeviceState != KSSTATE_RUN) {
|
|
//
|
|
// Device isn't "runnning".
|
|
//
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
//
|
|
// Get the data in an MDL if it's not already. From the KsProbeStreamIrp code:
|
|
//
|
|
// Makes the specified modifications to the given IRP's input and output
|
|
// buffers based on the specific streaming IOCTL in the current stack
|
|
// location, and validates the stream header. The Irp end up in essentially
|
|
// the METHOD_OUT_DIRECT or
|
|
// METHOD_IN_DIRECT format, with the exception that the access to the data
|
|
// buffer may be IoModifyAccess depending on the flags passed to this
|
|
// function or in the stream header. If the stream buffers MDL's have been
|
|
// allocated, they are available through the PIRP->MdlAddress. If extra data
|
|
// has been requested, the copied list of headers with extra data area is
|
|
// available in PIRP->Tail.Overlay.AuxiliaryBuffer.
|
|
//
|
|
Status = KsProbeStreamIrp(Irp,
|
|
KSPROBE_STREAMWRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK,
|
|
sizeof(KSSTREAM_HEADER));
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
RCADEBUGP(RCA_WARNING,("WriteStream: KsProbeStreamIrp failed sts %x\n", Status));
|
|
break;
|
|
}
|
|
|
|
if (!((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->DataUsed)
|
|
{
|
|
//
|
|
// This IRP has no data, complete it immediately.
|
|
//
|
|
RCADEBUGP(RCA_WARNING, ("Irp %x has no data\n", Irp) );
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Build a partial MDL containing only the dataused portion of this MDL
|
|
//
|
|
RCADEBUGP(RCA_INFO,("WriteStream: allocating MDL\n"));
|
|
|
|
pMdlVirtualAddress = MmGetMdlVirtualAddress (Irp->MdlAddress);
|
|
|
|
RCADEBUGP(RCA_INFO,("WriteStream: going to alloc an mdl of length %lu\n",
|
|
((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->DataUsed));
|
|
|
|
pMdl = IoAllocateMdl(pMdlVirtualAddress,
|
|
((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->DataUsed,
|
|
FALSE,
|
|
FALSE,
|
|
NULL);
|
|
if (pMdl == NULL) {
|
|
RCADEBUGP(RCA_WARNING,("WriteStream: STATUS_INSUFFICIENT_RESOURCES for MDL\n"));
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
RCADEBUGP(RCA_INFO,("WriteStream: building partial MDL\n"));
|
|
|
|
BytesToCopy = ((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->DataUsed;
|
|
|
|
//
|
|
// For debugging only.
|
|
//
|
|
if (g_ulBufferSize > 0) {
|
|
BytesToCopy = g_ulBufferSize;
|
|
}
|
|
|
|
IoBuildPartialMdl(Irp->MdlAddress,
|
|
pMdl,
|
|
pMdlVirtualAddress,
|
|
BytesToCopy);
|
|
|
|
//
|
|
// TBS: wait for CSA soltion for passing header info across transform filters.
|
|
// Now we're sure the header is in the system buffer. We also need to ship the header, since
|
|
// we need the dataused number and (in future) CSA will specify timing and other info in there
|
|
// that we need to get end-to-end. Allocate the MDL and put it on the end of the list
|
|
//
|
|
|
|
IoMarkIrpPending( Irp );
|
|
|
|
RCA_ACQUIRE_BRIDGE_PIN_LOCK(pDevIoPin->FilterInstance->BridgePin);
|
|
|
|
pDevIoPin->FilterInstance->BridgePin->PendingSendsCount++;
|
|
|
|
RCA_RELEASE_BRIDGE_PIN_LOCK(pDevIoPin->FilterInstance->BridgePin);
|
|
|
|
Status = RCACoNdisSendFrame(VcContext,
|
|
pMdl,
|
|
(PVOID)Irp);
|
|
|
|
if (Status != NDIS_STATUS_PENDING) {
|
|
RCADEBUGP(RCA_ERROR, ("WriteStream: RCACoNdisSendFrame returned status 0x%x, "
|
|
"manually calling send complete handler\n", Status));
|
|
|
|
RCASendCompleteCallback(VcContext,
|
|
(PVOID) pDevIoPin->FilterInstance->BridgePin,
|
|
(PVOID) Irp,
|
|
pMdl,
|
|
Status);
|
|
}
|
|
|
|
//
|
|
// If status returned from RCACoNdisSendFrame was not STATUS_PENDING, then we
|
|
// completed the IRP with that status. We need to set the status back to PENDING
|
|
// here so that PinDispatchIoControl will not try to complete the IRP again.
|
|
//
|
|
Status = NDIS_STATUS_PENDING;
|
|
} while (FALSE);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
GetInterface(
|
|
IN PIRP Irp,
|
|
IN PKSPROPERTY Property,
|
|
OUT PKSPIN_INTERFACE Interface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles the KSPROPERTY_STREAM_INTERFACE property Get in the Stream property set.
|
|
Returns the interface on the Dev I/O Pin so that positional translations can be
|
|
performed.
|
|
|
|
Arguments:
|
|
|
|
Irp -
|
|
Device control Irp.
|
|
|
|
Property -
|
|
Specific property request.
|
|
|
|
Interface -
|
|
The place in which to put the Interface.
|
|
|
|
Return Values:
|
|
|
|
Returns STATUS_SUCCESS.
|
|
|
|
--*/
|
|
{
|
|
RCADEBUGP(RCA_INFO, ("GetInterface: Enter\n"));
|
|
|
|
Interface->Set = KSINTERFACESETID_Standard;
|
|
// Interface->Id = KSINTERFACE_STANDARD_POSITION;
|
|
Irp->IoStatus.Information = sizeof(KSPIN_INTERFACE);
|
|
|
|
RCADEBUGP(RCA_INFO, ("GetInterface: Exit - Returning STATUS_NOT_IMPLEMENTED\n"));
|
|
|
|
DbgBreakPoint();
|
|
return(STATUS_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
|
|
|