mirror of https://github.com/lianthony/NT4.0
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.
234 lines
4.8 KiB
234 lines
4.8 KiB
/*++
|
|
|
|
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);
|
|
}
|
|
}
|