2020-09-30 17:12:29 +02:00

235 lines
4.8 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
util.c
Abstract:
This module contains code for utility routines.
Author:
Nigel Thompson (nigelt) 8-may-1991
Environment:
Kernel mode
Revision History:
Robin Speed (RobinSp) 29-Jan-1992 - Rewrote
--*/
#include "sound.h"
VOID
sndGetNextBuffer(
PLOCAL_DEVICE_INFO pLDI
)
/*++
Routine Description:
Get the next user's buffer :
If there is another buffer :
Remove the first buffer from the head of the list
Discard it if it's cancelled and go to the next
Map the locked user pages so we can refer to them
Update the GDI fields :
pUserBuffer - our pointer to buffer
UserBufferPosition - 0
pIrp - The request packet for the current buffer
Arguments:
pLDI - pointer to our local device info
Return Value:
None
--*/
{
PIO_STACK_LOCATION pIrpStack;
PLIST_ENTRY pListNode;
KIRQL OldIrql;
PGLOBAL_DEVICE_INFO pGDI;
pGDI = pLDI->pGlobalInfo;
dprintf4("New Packet");
ASSERT(pGDI->pUserBuffer == NULL);
//
// May be no more buffers. If there are they may be cancelled
// IO requests.
//
while (!IsListEmpty(&pLDI->QueueHead)) {
//
// pull the next request packet from the front of the list
//
pListNode = RemoveHeadList(&pLDI->QueueHead);
pGDI->pIrp = CONTAINING_RECORD(pListNode, IRP, Tail.Overlay.ListEntry);
pIrpStack = IoGetCurrentIrpStackLocation(pGDI->pIrp);
//
// If the request packet is cancelled then just free it.
// Don't break out of loops here - it's too complicated !
//
IoAcquireCancelSpinLock(&OldIrql); // Required to inspect Cancel flag
if (pGDI->pIrp->Cancel
#ifdef WAVE_DD_DO_LOOPS
&& pLDI->LoopBegin == NULL
#endif // WAVE_DD_DO_LOOPS
)
{
IoReleaseCancelSpinLock(OldIrql);
pGDI->pIrp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(pGDI->pIrp, IO_SOUND_INCREMENT);
} else {
IoReleaseCancelSpinLock(OldIrql);
//
// Get the length of the wave bits
//
pGDI->UserBufferSize =
pGDI->Usage == SoundInterruptUsageWaveOut ?
pIrpStack->Parameters.Write.Length :
pIrpStack->Parameters.Read.Length;
//
// Map the buffer pages to kernel mode
// Keep the address of the start so we can unmap them later
// Note the system falls over mapping 0 length buffers !
//
if (pGDI->UserBufferSize != 0) {
pGDI->pUserBuffer =
(PUCHAR) MmGetSystemAddressForMdl(pGDI->pIrp->MdlAddress);
} else {
pGDI->pUserBuffer = (PUCHAR)pGDI; // Dummy
}
//
// We now have a buffer - set the position to 0 and break
//
pGDI->UserBufferPosition = 0;
break;
}
}
}
VOID
sndCompleteIoBuffer(
PGLOBAL_DEVICE_INFO pGDI
)
/*++
Routine Description:
Complete the processing of a buffer
This involves freeing our mapping,
Setting the length of data processed in the Irp and
Clearing the pUserBuffer field.
Arguments:
pGDI - pointer to our global data
Return Value:
None
--*/
{
//
// Free any page mapping
//
ASSERT(pGDI->pUserBuffer != NULL);
//
// Set the data length for the caller. This is somewhat
// unsatisfactory. The only sensible way for the caller
// to work is to assume that all but the last buffer
// is full, otherwise they would have to go round allocating
// IO_STATUS_BLOCKs for every buffer in the queue.
//
pGDI->pIrp->IoStatus.Information = pGDI->UserBufferPosition;
//
// Note that there is currently no mapped buffer to use
//
pGDI->pUserBuffer = NULL;
}
VOID
sndFreeQ(
PLOCAL_DEVICE_INFO pLDI,
PLIST_ENTRY ListHead,
NTSTATUS IoStatus
)
/*++
Routine Description:
Free a list of Irps - setting the specified status and completing
them. The list will be empty on exit.
Arguments:
pListNode - the list to free
IoStatus - the status to set in each Irp.
Return Value:
None.
--*/
{
//
// Remove all the queue entries, completing all
// the Irps represented by the entries
//
while (!IsListEmpty(ListHead)) {
PLIST_ENTRY pListNode;
PIRP pIrp;
pListNode = RemoveHeadList(ListHead);
pIrp = CONTAINING_RECORD(pListNode, IRP, Tail.Overlay.ListEntry);
pIrp->IoStatus.Status = IoStatus;
//
// Bump priority here because the application may still be trying
// to be real-time
//
IoCompleteRequest(pIrp, IO_SOUND_INCREMENT);
}
}