miniport.cpp
来自「winddk src目录下的WDM源码压缩!」· C++ 代码 · 共 1,744 行 · 第 1/4 页
CPP
1,744 行
}
if (!m_TimerQueued)
{
(void) ConsumeEvents();
}
}
else // capture
{
_DbgPrintF(DEBUGLVL_BLAB, ("PutMessage to capture stream"));
ASSERT(NULL == pDMKEvt);
SourceEvtsToPort();
}
return ntStatus;
}
#pragma code_seg()
/*****************************************************************************
* CMiniportDMusUARTStream::ConsumeEvents()
*****************************************************************************
* Attempts to empty the render message queue.
* Called either from DPC timer or upon IRP submittal.
// TODO: support packages right
// process the package (actually, should do this above.
// treat the package as a list fragment that shouldn't be sorted.
// better yet, go through each event in the package, and when
// an event is exhausted, delete it and decrement m_offset.
*/
NTSTATUS CMiniportDMusUARTStream::ConsumeEvents(void)
{
PDMUS_KERNEL_EVENT aDMKEvt;
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG bytesRemaining = 0,bytesWritten = 0;
LARGE_INTEGER aMillisecIn100ns;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
KeAcquireSpinLockAtDpcLevel(&m_DpcSpinLock);
m_TimerQueued = FALSE;
while (m_DMKEvtQueue) // do we have anything to play at all?
{
aDMKEvt = m_DMKEvtQueue; // event we try to play
if (aDMKEvt->cbEvent)
{
bytesRemaining = aDMKEvt->cbEvent - m_DMKEvtOffset; // number of bytes left in this evt
ASSERT(bytesRemaining > 0);
if (bytesRemaining <= 0)
{
bytesRemaining = aDMKEvt->cbEvent;
}
if (aDMKEvt->cbEvent <= sizeof(PBYTE)) // short message
{
_DbgPrintF(DEBUGLVL_BLAB, ("ConsumeEvents(%02x%02x%02x%02x)",aDMKEvt->uData.abData[0],aDMKEvt->uData.abData[1],aDMKEvt->uData.abData[2],aDMKEvt->uData.abData[3]));
ntStatus = Write(aDMKEvt->uData.abData + m_DMKEvtOffset,bytesRemaining,&bytesWritten);
}
else if (PACKAGE_EVT(aDMKEvt))
{
ASSERT(m_DMKEvtOffset == 0);
m_DMKEvtOffset = 0;
_DbgPrintF(DEBUGLVL_BLAB, ("ConsumeEvents(Package)"));
ntStatus = PutMessageLocked(aDMKEvt->uData.pPackageEvt); // we already own the spinlock
// null this because we are about to throw it in the allocator
aDMKEvt->uData.pPackageEvt = NULL;
aDMKEvt->cbEvent = 0;
bytesWritten = bytesRemaining;
}
else // SysEx message
{
_DbgPrintF(DEBUGLVL_BLAB, ("ConsumeEvents(%02x%02x%02x%02x)",aDMKEvt->uData.pbData[0],aDMKEvt->uData.pbData[1],aDMKEvt->uData.pbData[2],aDMKEvt->uData.pbData[3]));
ntStatus = Write(aDMKEvt->uData.pbData + m_DMKEvtOffset,bytesRemaining,&bytesWritten);
}
} // if (aDMKEvt->cbEvent)
if (STATUS_SUCCESS != ntStatus)
{
_DbgPrintF(DEBUGLVL_TERSE, ("ConsumeEvents: Write returned 0x%08x",ntStatus));
bytesWritten = bytesRemaining; // just bail on this event and try next time
}
ASSERT(bytesWritten <= bytesRemaining);
if (bytesWritten == bytesRemaining)
{
m_DMKEvtQueue = m_DMKEvtQueue->pNextEvt;
aDMKEvt->pNextEvt = NULL;
m_AllocatorMXF->PutMessage(aDMKEvt); // throw back in free pool
m_DMKEvtOffset = 0; // start fresh on next evt
m_NumberOfRetries = 0;
} // but wait ... there's more!
else // our FIFO is full for now.
{
// update our offset by that amount we did write
m_DMKEvtOffset += bytesWritten;
ASSERT(m_DMKEvtOffset < aDMKEvt->cbEvent);
_DbgPrintF(DEBUGLVL_BLAB,("ConsumeEvents tried %d, wrote %d, at offset %d",bytesRemaining,bytesWritten,m_DMKEvtOffset));
aMillisecIn100ns.QuadPart = -(kOneMillisec); // set timer, come back later
m_TimerQueued = TRUE;
m_NumberOfRetries++;
KeSetTimer( &m_TimerEvent, aMillisecIn100ns, &m_Dpc );
break;
} // we didn't write it all
} // go back, Jack, do it again (while m_DMKEvtQueue)
KeReleaseSpinLockFromDpcLevel(&m_DpcSpinLock);
return ntStatus;
}
#pragma code_seg()
/*****************************************************************************
* CMiniportDMusUARTStream::HandlePortParams()
*****************************************************************************
* Writes an outgoing MIDI message.
*/
NTSTATUS
CMiniportDMusUARTStream::
HandlePortParams
(
IN PPCPROPERTY_REQUEST pRequest
)
{
PAGED_CODE();
NTSTATUS ntStatus;
if (pRequest->Verb & KSPROPERTY_TYPE_SET)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTH_PORTPARAMS), TRUE);
if (NT_SUCCESS(ntStatus))
{
RtlCopyMemory(pRequest->Value, pRequest->Instance, sizeof(SYNTH_PORTPARAMS));
PSYNTH_PORTPARAMS Params = (PSYNTH_PORTPARAMS)pRequest->Value;
if (Params->ValidParams & ~SYNTH_PORTPARAMS_CHANNELGROUPS)
{
Params->ValidParams &= SYNTH_PORTPARAMS_CHANNELGROUPS;
}
if (!(Params->ValidParams & SYNTH_PORTPARAMS_CHANNELGROUPS))
{
Params->ChannelGroups = 1;
}
else if (Params->ChannelGroups != 1)
{
Params->ChannelGroups = 1;
}
pRequest->ValueSize = sizeof(SYNTH_PORTPARAMS);
}
return ntStatus;
}
#pragma code_seg()
/*****************************************************************************
* DMusTimerDPC()
*****************************************************************************
* The timer DPC callback. Thunks to a C++ member function.
* This is called by the OS in response to the DirectMusic pin
* wanting to wakeup later to process more DirectMusic stuff.
*/
VOID
NTAPI
DMusUARTTimerDPC
(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
{
ASSERT(DeferredContext);
CMiniportDMusUARTStream *aStream;
aStream = (CMiniportDMusUARTStream *) DeferredContext;
if (aStream)
{
_DbgPrintF(DEBUGLVL_BLAB,("DMusUARTTimerDPC"));
if (false == aStream->m_fCapture)
{
(void) aStream->ConsumeEvents();
}
// ignores return value!
}
}
/*****************************************************************************
* DirectMusic properties
****************************************************************************/
#pragma code_seg("PAGE")
/*
* Properties concerning synthesizer functions.
*/
const WCHAR wszDescOut[] = L"DMusic MPU-401 Out ";
const WCHAR wszDescIn[] = L"DMusic MPU-401 In ";
NTSTATUS PropertyHandler_Synth
(
IN PPCPROPERTY_REQUEST pRequest
)
{
NTSTATUS ntStatus;
PAGED_CODE();
if (pRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
{
ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE);
if (NT_SUCCESS(ntStatus))
{
// if return buffer can hold a ULONG, return the access flags
PULONG AccessFlags = PULONG(pRequest->Value);
*AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT;
switch (pRequest->PropertyItem->Id)
{
case KSPROPERTY_SYNTH_CAPS:
case KSPROPERTY_SYNTH_CHANNELGROUPS:
*AccessFlags |= KSPROPERTY_TYPE_GET;
}
switch (pRequest->PropertyItem->Id)
{
case KSPROPERTY_SYNTH_CHANNELGROUPS:
*AccessFlags |= KSPROPERTY_TYPE_SET;
}
ntStatus = STATUS_SUCCESS;
pRequest->ValueSize = sizeof(ULONG);
switch (pRequest->PropertyItem->Id)
{
case KSPROPERTY_SYNTH_PORTPARAMETERS:
if (pRequest->MinorTarget)
{
*AccessFlags |= KSPROPERTY_TYPE_GET;
}
else
{
pRequest->ValueSize = 0;
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
}
}
}
}
else
{
ntStatus = STATUS_SUCCESS;
switch(pRequest->PropertyItem->Id)
{
case KSPROPERTY_SYNTH_CAPS:
_DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_Synth:KSPROPERTY_SYNTH_CAPS"));
if (pRequest->Verb & KSPROPERTY_TYPE_SET)
{
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
}
if (NT_SUCCESS(ntStatus))
{
ntStatus = ValidatePropertyRequest(pRequest, sizeof(SYNTHCAPS), TRUE);
if (NT_SUCCESS(ntStatus))
{
SYNTHCAPS *caps = (SYNTHCAPS*)pRequest->Value;
int increment;
RtlZeroMemory(caps, sizeof(SYNTHCAPS));
// XXX Different guids for different instances!
//
if (pRequest->Node == eSynthNode)
{
increment = sizeof(wszDescOut) - 2;
RtlCopyMemory( caps->Description,wszDescOut,increment);
caps->Guid = CLSID_MiniportDriverDMusUART;
}
else
{
increment = sizeof(wszDescIn) - 2;
RtlCopyMemory( caps->Description,wszDescIn,increment);
caps->Guid = CLSID_MiniportDriverDMusUARTCapture;
}
caps->Flags = SYNTH_PC_EXTERNAL;
caps->MemorySize = 0;
caps->MaxChannelGroups = 1;
caps->MaxVoices = 0xFFFFFFFF;
caps->MaxAudioChannels = 0xFFFFFFFF;
caps->EffectFlags = 0;
CMiniportDMusUART *aMiniport;
ASSERT(pRequest->MajorTarget);
aMiniport = (CMiniportDMusUART *)(PMINIPORTDMUS)(pRequest->MajorTarget);
WCHAR wszDesc2[16];
size_t cLen;
StringCbPrintfW (wszDesc2, sizeof(wszDesc2), L"[%03X]\0", PtrToUlong(aMiniport->m_pPortBase));
StringCbLengthW (wszDesc2, sizeof(wszDesc2), &cLen);
RtlCopyMemory((WCHAR *)((DWORD_PTR)(caps->Description) + increment),
wszDesc2,
cLen);
pRequest->ValueSize = sizeof(SYNTHCAPS);
}
}
break;
case KSPROPERTY_SYNTH_PORTPARAMETERS:
_DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_Synth:KSPROPERTY_SYNTH_PORTPARAMETERS"));
{
CMiniportDMusUARTStream *aStream;
aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget);
if (aStream)
{
ntStatus = aStream->HandlePortParams(pRequest);
}
else
{
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
}
}
break;
case KSPROPERTY_SYNTH_CHANNELGROUPS:
_DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_Synth:KSPROPERTY_SYNTH_CHANNELGROUPS"));
ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONG), TRUE);
if (NT_SUCCESS(ntStatus))
{
*(PULONG)(pRequest->Value) = 1;
pRequest->ValueSize = sizeof(ULONG);
}
break;
case KSPROPERTY_SYNTH_LATENCYCLOCK:
_DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_Synth:KSPROPERTY_SYNTH_LATENCYCLOCK"));
if(pRequest->Verb & KSPROPERTY_TYPE_SET)
{
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
}
else
{
ntStatus = ValidatePropertyRequest(pRequest, sizeof(ULONGLONG), TRUE);
if(NT_SUCCESS(ntStatus))
{
REFERENCE_TIME rtLatency;
CMiniportDMusUARTStream *aStream;
aStream = (CMiniportDMusUARTStream*)(pRequest->MinorTarget);
if(aStream == NULL)
{
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
}
else
{
aStream->m_pMiniport->m_MasterClock->GetTime(&rtLatency);
*((PULONGLONG)pRequest->Value) = rtLatency;
pRequest->ValueSize = sizeof(ULONGLONG);
}
}
}
break;
default:
_DbgPrintF(DEBUGLVL_TERSE,("Unhandled property in PropertyHandler_Synth"));
break;
}
}
return ntStatus;
}
/*****************************************************************************
* ValidatePropertyRequest()
*****************************************************************************
* Validates pRequest.
* Checks if the ValueSize is valid
* Checks if the Value is valid
*
* This does not update pRequest->ValueSize if it returns NT_SUCCESS.
* Caller must set pRequest->ValueSize in case of NT_SUCCESS.
*/
NTSTATUS ValidatePropertyRequest
(
IN PPCPROPERTY_REQUEST pRequest,
IN ULONG ulValueSize,
IN BOOLEAN fValueRequired
)
{
NTSTATUS ntStatus;
if (pRequest->ValueSize >= ulValueSize)
{
if (fValueRequired && NULL == pRequest->Value)
{
ntStatus = STATUS_INVALID_PARAMETER;
}
else
{
ntStatus = STATUS_SUCCESS;
}
}
else if (0 == pRequest->ValueSize)
{
ntStatus = STATUS_BUFFER_OVERFLOW;
}
else
{
ntStatus = STATUS_BUFFER_TOO_SMALL;
}
if (STATUS_BUFFER_OVERFLOW == ntStatus)
{
pRequest->ValueSize = ulValueSize;
}
else
{
pRequest->ValueSize = 0;
}
return ntStatus;
} // ValidatePropertyRequest
#pragma code_seg()
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?