235 lines
4.8 KiB
C
235 lines
4.8 KiB
C
/*++
|
||
|
||
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);
|
||
}
|
||
}
|