1416 lines
36 KiB
C
1416 lines
36 KiB
C
/*++
|
|
|
|
Copyright (c) 1995,1996 Microsoft Corporation
|
|
:ts=4
|
|
|
|
Module Name:
|
|
|
|
dscrptor.c
|
|
|
|
Abstract:
|
|
|
|
The module manages descriptor allocation.
|
|
|
|
Descriptors are structures in physical memory used by the
|
|
host controller to manage transfers, the HC requires two
|
|
types of TDs: Queue head TDs and Transfer TDs.
|
|
|
|
A memory descriptor describes a buffer that can be accessed by the
|
|
Host Controller (ie allocated with HalAllocateCommonBuffer).
|
|
|
|
The descriptor code maintains three types of memory descriptor
|
|
lists UHCD_LARGE_COMMON_BUFFERS, UHCD_MEDIUM_COMMON_BUFFERS and
|
|
UHCD_SMALL_COMMON_BUFFERS
|
|
|
|
UHCD_LARGE_COMMON_BUFFERS are blocks of memory we use for a queue
|
|
head and its associated transfer descriptors for iso and large bulk
|
|
endpoints.
|
|
|
|
UHCD_MEDIUM_COMMON_BUFFERS are blocks of memory we use for a queue
|
|
head and its associated transfer descriptors.
|
|
|
|
UHCD_SMALL_COMMON_BUFFERS are blocks of memory we use to double
|
|
buffer non-isochronous packets if needed.
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
11-01-95 : created
|
|
|
|
--*/
|
|
#include "wdm.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
|
|
|
|
#include "usbdi.h"
|
|
#include "hcdi.h"
|
|
#include "uhcd.h"
|
|
|
|
#ifdef PAGE_CODE
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, UHCD_InitializeCommonBufferPool)
|
|
#endif
|
|
#endif
|
|
|
|
LONG UHCD_CommonBufferBytes = 0;
|
|
#if DBG
|
|
|
|
#define UHCD_ASSERT_BUFFER_POOL(bp) \
|
|
(((PUHCD_BUFFER_POOL) (bp))->Sig == UHCD_BP_SIG)
|
|
#else
|
|
#define UHCD_ASSERT_BUFFER_POOL(bp)
|
|
#endif
|
|
|
|
|
|
|
|
#define UHCD_BP_SIG 0x444a444a
|
|
|
|
|
|
|
|
PUHCD_BUFFER_POOL
|
|
UHCD_SelectBufferPool(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG CommonBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
select the appropriate buffer pool based on the
|
|
size of the CommonBufferBlock requested.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PUHCD_BUFFER_POOL bufferPool;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
UHCD_ASSERT(CommonBufferLength <= UHCD_LARGE_COMMON_BUFFER_SIZE);
|
|
|
|
if (CommonBufferLength <= UHCD_SMALL_COMMON_BUFFER_SIZE) {
|
|
bufferPool = &deviceExtension->SmallBufferPool;
|
|
} else if (CommonBufferLength <= UHCD_MEDIUM_COMMON_BUFFER_SIZE) {
|
|
bufferPool = &deviceExtension->MediumBufferPool;
|
|
} else if (CommonBufferLength <= UHCD_LARGE_COMMON_BUFFER_SIZE) {
|
|
bufferPool = &deviceExtension->LargeBufferPool;
|
|
} else {
|
|
bufferPool = NULL;
|
|
}
|
|
|
|
LOGENTRY(LOG_MISC, 'sbPL', bufferPool, CommonBufferLength, 0);
|
|
|
|
#if DBG
|
|
if (bufferPool) {
|
|
UHCD_ASSERT_BUFFER_POOL(bufferPool);
|
|
}
|
|
#endif
|
|
|
|
return bufferPool;
|
|
}
|
|
|
|
|
|
ULONG
|
|
UHCD_FreePoolSize(
|
|
IN PUHCD_BUFFER_POOL BufferPool,
|
|
IN OUT PULONG ByteCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
returns the number of entries in the free pool
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG count = 0;
|
|
PSINGLE_LIST_ENTRY current;
|
|
PSINGLE_LIST_ENTRY listEntry;
|
|
PUHCD_MEMORY_DESCRIPTOR memoryDescriptor;
|
|
KIRQL oldIrql;
|
|
|
|
*ByteCount = 0;
|
|
|
|
KeAcquireSpinLock(&BufferPool->MemoryDescriptorFreePoolSpin, &oldIrql);
|
|
listEntry = &BufferPool->MemoryDescriptorFreePool;
|
|
|
|
// walk the list
|
|
|
|
current = listEntry->Next;
|
|
LOGENTRY(LOG_MISC, 'fpsz', listEntry, 0, current);
|
|
while (current != NULL) {
|
|
memoryDescriptor = CONTAINING_RECORD(current,
|
|
UHCD_MEMORY_DESCRIPTOR,
|
|
SingleListEntry);
|
|
UHCD_ASSERT(memoryDescriptor->Sig == SIG_MD);
|
|
count++;
|
|
*ByteCount+=BufferPool->CommonBufferLength;
|
|
current = current->Next;
|
|
LOGENTRY(LOG_MISC, 'fpsN', count, 0, current);
|
|
}
|
|
|
|
KeReleaseSpinLock(&BufferPool->MemoryDescriptorFreePoolSpin, oldIrql);
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_InitializeHardwareQueueHeadDescriptor(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PHW_QUEUE_HEAD QueueHead,
|
|
IN HW_DESCRIPTOR_PHYSICAL_ADDRESS LogicalAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
set up a newly created queue head
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - device object for this controller.
|
|
|
|
QueueHead - ptr to queue head to initialize.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
RtlZeroMemory(QueueHead, sizeof(HW_QUEUE_HEAD));
|
|
|
|
UHCD_ASSERT((LogicalAddress & 0xf) == 0);
|
|
|
|
QueueHead->PhysicalAddress = SET_Q_BIT(LogicalAddress);
|
|
QueueHead->Sig = SIG_QH;
|
|
QueueHead->Flags = 0;
|
|
|
|
QueueHead->HW_HLink = QueueHead->PhysicalAddress;
|
|
SET_T_BIT(QueueHead->HW_HLink);
|
|
QueueHead->HW_VLink = LIST_END; // T-bit set, no descriptors
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_InitializeHardwareTransferDescriptor(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PHW_TRANSFER_DESCRIPTOR TransferDescriptor,
|
|
IN HW_DESCRIPTOR_PHYSICAL_ADDRESS LogicalAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
set up a newly created transfer descriptor.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - device object for this controller.
|
|
|
|
Transfer - ptr to queue head to initialize
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
RtlZeroMemory(TransferDescriptor, sizeof(HW_TRANSFER_DESCRIPTOR));
|
|
|
|
UHCD_ASSERT((LogicalAddress & 0xf) == 0);
|
|
|
|
TransferDescriptor->PhysicalAddress = LogicalAddress;
|
|
TransferDescriptor->Sig = SIG_TD;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
UHCD_AllocateHardwareDescriptors(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_HARDWARE_DESCRIPTOR_LIST *HardwareDescriptorList,
|
|
IN ULONG NumberOfTransferDescriptors
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates a descriptor list of a specified size,
|
|
the descriptor list includes a queue head and array of
|
|
'NumberOfTransferDescriptors' transfer descriptors.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - device object for this controller.
|
|
|
|
HardwareDescriptorList - pointer to descriptor list structure,
|
|
filled in with information about descriptors allocated.
|
|
|
|
NumberOfTransferDescriptors - number of transfer descriptors to allocate.
|
|
|
|
Return Value:
|
|
|
|
returns TRUE if successful.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
BOOLEAN status = FALSE;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUHCD_HARDWARE_DESCRIPTOR_LIST hardwareDescriptorList;
|
|
PUHCD_MEMORY_DESCRIPTOR memoryDescriptor;
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_AllocateHardwareDescriptors\n"));
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
*HardwareDescriptorList = NULL;
|
|
|
|
UHCD_ASSERT(sizeof(HW_QUEUE_HEAD) == UHCD_HW_DESCRIPTOR_SIZE);
|
|
UHCD_ASSERT(sizeof(HW_TRANSFER_DESCRIPTOR) == UHCD_HW_DESCRIPTOR_SIZE);
|
|
|
|
|
|
UHCD_ASSERT(NumberOfTransferDescriptors == MAX_TDS_PER_ENDPOINT ||
|
|
NumberOfTransferDescriptors == MIN_TDS_PER_ENDPOINT);
|
|
|
|
// first allocate the descriptor list structure
|
|
hardwareDescriptorList = GETHEAP(NonPagedPool,
|
|
sizeof(*hardwareDescriptorList));
|
|
|
|
LOGENTRY(LOG_MISC, 'alDL', hardwareDescriptorList, 0, 0);
|
|
|
|
if (hardwareDescriptorList) {
|
|
ULONG need;
|
|
|
|
// Allocate some shared adapter memory for this
|
|
// descriptor list.
|
|
//
|
|
// Note: we need one extra descriptor for the Queue Head
|
|
// and one extra for a scratch buffer
|
|
need = TD_LIST_SIZE(NumberOfTransferDescriptors);
|
|
|
|
|
|
hardwareDescriptorList->MemoryDescriptor =
|
|
UHCD_AllocateCommonBuffer(DeviceObject, need);
|
|
hardwareDescriptorList->NumberOfHWDescriptors =
|
|
NumberOfTransferDescriptors+1;
|
|
|
|
if (hardwareDescriptorList->MemoryDescriptor) {
|
|
memoryDescriptor = hardwareDescriptorList->MemoryDescriptor;
|
|
|
|
LOGENTRY(LOG_MISC, 'iHDL', hardwareDescriptorList,
|
|
NumberOfTransferDescriptors, 0);
|
|
|
|
UHCD_InitializeHardwareQueueHeadDescriptor(
|
|
DeviceObject,
|
|
(PHW_QUEUE_HEAD) memoryDescriptor->VirtualAddress,
|
|
memoryDescriptor->LogicalAddress);
|
|
for (i = 0; i < NumberOfTransferDescriptors; i++) {
|
|
LOGENTRY(LOG_MISC, 'iHTD', hardwareDescriptorList,
|
|
NumberOfTransferDescriptors, 0);
|
|
|
|
UHCD_InitializeHardwareTransferDescriptor(DeviceObject,
|
|
(PHW_TRANSFER_DESCRIPTOR)
|
|
(memoryDescriptor->VirtualAddress +
|
|
i * sizeof(HW_TRANSFER_DESCRIPTOR) +
|
|
sizeof(HW_QUEUE_HEAD)),
|
|
memoryDescriptor->LogicalAddress +
|
|
i * sizeof(HW_TRANSFER_DESCRIPTOR) +
|
|
sizeof(HW_QUEUE_HEAD));
|
|
}
|
|
|
|
hardwareDescriptorList->ScratchBufferVirtualAddress =
|
|
memoryDescriptor->VirtualAddress + i *
|
|
sizeof(HW_TRANSFER_DESCRIPTOR) +
|
|
sizeof(HW_QUEUE_HEAD);
|
|
UHCD_ASSERT((ULONG)((PUCHAR)hardwareDescriptorList->
|
|
ScratchBufferVirtualAddress -
|
|
(PUCHAR)memoryDescriptor->VirtualAddress) < need);
|
|
|
|
hardwareDescriptorList->ScratchBufferLogicalAddress =
|
|
memoryDescriptor->LogicalAddress + i *
|
|
sizeof(HW_TRANSFER_DESCRIPTOR) +
|
|
sizeof(HW_QUEUE_HEAD);
|
|
|
|
*HardwareDescriptorList = hardwareDescriptorList;
|
|
status = TRUE;
|
|
} else {
|
|
RETHEAP(hardwareDescriptorList);
|
|
}
|
|
}
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_AllocateHardwareDescriptors descriptors 0x%x\n",
|
|
status));
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_FreeHardwareDescriptors(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_HARDWARE_DESCRIPTOR_LIST HardwareDescriptorList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns descriptors to the system.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - device object for this controller.
|
|
|
|
HardwareDescriptorList - pointer to descriptor list structure,
|
|
filled in with information about descriptors allocated.
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_FreeHardwareDesriptors\n"));
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Put this one back on the free list
|
|
//
|
|
|
|
LOGENTRY(LOG_MISC, 'frDL', HardwareDescriptorList,
|
|
HardwareDescriptorList->MemoryDescriptor, 0);
|
|
|
|
//
|
|
// free the shared memory
|
|
//
|
|
UHCD_FreeCommonBuffer(DeviceObject,
|
|
HardwareDescriptorList->MemoryDescriptor);
|
|
|
|
// free the list header structure
|
|
RETHEAP(HardwareDescriptorList);
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_FreeHardwareDescriptors\n"));
|
|
}
|
|
|
|
|
|
PUHCD_MEMORY_DESCRIPTOR
|
|
UHCD_DoAllocateCommonBuffer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG CommonBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a new block of memory that both the HCD and
|
|
the HC harware can access, this memory can be used for HW descriptors
|
|
or packet buffers.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
CommonBufferLength - minimum number of bytes this shared memory block
|
|
must contain.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUHCD_MEMORY_DESCRIPTOR memoryDescriptor = NULL;
|
|
PSINGLE_LIST_ENTRY singleListEntry;
|
|
PSINGLE_LIST_ENTRY memoryDescriptorFreePool;
|
|
PKSPIN_LOCK memoryDescriptorFreePoolSpin;
|
|
PUHCD_BUFFER_POOL bufferPool;
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_DoAllocateCommonBuffer\n"));
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// select the list to allocate from
|
|
//
|
|
|
|
bufferPool = UHCD_SelectBufferPool(DeviceObject, CommonBufferLength);
|
|
|
|
memoryDescriptorFreePool = &bufferPool->MemoryDescriptorFreePool;
|
|
memoryDescriptorFreePoolSpin =
|
|
&bufferPool->MemoryDescriptorFreePoolSpin;
|
|
|
|
singleListEntry = ExInterlockedPopEntryList(memoryDescriptorFreePool,
|
|
memoryDescriptorFreePoolSpin);
|
|
|
|
if (singleListEntry) {
|
|
memoryDescriptor = CONTAINING_RECORD(singleListEntry,
|
|
UHCD_MEMORY_DESCRIPTOR,
|
|
SingleListEntry);
|
|
|
|
LOGENTRY(LOG_MISC, 'alMD', memoryDescriptor,
|
|
memoryDescriptor->VirtualAddress, 0);
|
|
ASSERT_MD(memoryDescriptor);
|
|
memoryDescriptor->InUse++;
|
|
}
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_DoAllocateCommonBuffer 0x%x\n",
|
|
memoryDescriptor));
|
|
|
|
return memoryDescriptor;
|
|
}
|
|
|
|
|
|
PUHCD_MEMORY_DESCRIPTOR
|
|
UHCD_AllocateCommonBuffer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG CommonBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a new block of memory that both the HCD and
|
|
the HC harware can access, this memory can be used for HW descriptors
|
|
or packet buffers.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
CommonBufferLength - minimum number of bytes this shared memory block
|
|
must contain.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PUHCD_MEMORY_DESCRIPTOR memoryDescriptor = NULL;
|
|
|
|
// first attempt to satisfy the request whit what is available
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_AllocateCommonBuffer\n"));
|
|
LOGENTRY(LOG_MISC, 'acbr', 0, CommonBufferLength, 0);
|
|
|
|
// try to grow the pool
|
|
UHCD_MoreCommonBuffers(DeviceObject);
|
|
|
|
memoryDescriptor =
|
|
UHCD_DoAllocateCommonBuffer(DeviceObject,
|
|
CommonBufferLength);
|
|
|
|
if (memoryDescriptor == NULL) {
|
|
// non available, attempt to grow the pool
|
|
UHCD_AllocateCommonBufferBlock(DeviceObject,
|
|
CommonBufferLength,
|
|
1);
|
|
memoryDescriptor =
|
|
UHCD_DoAllocateCommonBuffer(DeviceObject,
|
|
CommonBufferLength);
|
|
|
|
#if DBG
|
|
if (memoryDescriptor == NULL) {
|
|
UHCD_KdTrap(("UHCD failed to allocate common buffer\n"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// if we are at passive level then grow the pool now
|
|
//
|
|
|
|
if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
|
|
UHCD_MoreCommonBuffers(DeviceObject);
|
|
}
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_AllocateCommonBuffer 0x%x\n", memoryDescriptor));
|
|
|
|
return memoryDescriptor;
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_FreeCommonBuffer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_MEMORY_DESCRIPTOR MemoryDescriptor
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
MemoryDescriptor - memory descriptor to free
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PSINGLE_LIST_ENTRY memoryDescriptorFreePool;
|
|
PKSPIN_LOCK memoryDescriptorFreePoolSpin;
|
|
PUHCD_BUFFER_POOL bufferPool;
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_FreeCommonBuffer\n"));
|
|
|
|
LOGENTRY(LOG_MISC, 'frMD', MemoryDescriptor,
|
|
MemoryDescriptor->VirtualAddress, MemoryDescriptor->Length);
|
|
|
|
ASSERT_MD(MemoryDescriptor);
|
|
|
|
bufferPool = MemoryDescriptor->BufferPool;
|
|
|
|
#if DBG
|
|
// RtlZeroMemory(MemoryDescriptor->VirtualAddress, MemoryDescriptor->Length);
|
|
RtlFillMemory(MemoryDescriptor->VirtualAddress,
|
|
MemoryDescriptor->Length,
|
|
-1);
|
|
#endif
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
memoryDescriptorFreePool = &bufferPool->MemoryDescriptorFreePool;
|
|
memoryDescriptorFreePoolSpin =
|
|
&bufferPool->MemoryDescriptorFreePoolSpin;
|
|
|
|
ExInterlockedPushEntryList(memoryDescriptorFreePool,
|
|
&MemoryDescriptor->SingleListEntry,
|
|
memoryDescriptorFreePoolSpin);
|
|
|
|
MemoryDescriptor->InUse--;
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_FreeCommonBuffer\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_AllocateCommonBufferBlock(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG CommonBufferLength,
|
|
IN ULONG NumberOfPages
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function tries to increase the pool of common memory
|
|
blocks used for descriptors and packet buffers.
|
|
|
|
|
|
Each Memory Descriptor looks like this:
|
|
|
|
offset
|
|
memoryDescriptor =
|
|
00 [Header] 32 bytes, (UHCD_HW_DESCRIPTOR_SIZE)
|
|
memoryDescriptor->VirtualAddress =
|
|
32 [memory] CommonBufferLength
|
|
......
|
|
all memoryDescriptors are aligned on a 32 byte
|
|
boundry.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
CommonBufferLength - Number of contiguous bytes needed
|
|
in the in each common buffer.
|
|
|
|
NumberOfPages - number of pages to allocate for common buffers.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PUCHAR virtualAddress, baseVirtualAddress, endVirtualAddress;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUHCD_MEMORY_DESCRIPTOR memoryDescriptor = NULL;
|
|
PSINGLE_LIST_ENTRY memoryDescriptorFreePool;
|
|
HW_DESCRIPTOR_PHYSICAL_ADDRESS hwLogicalAddress;
|
|
PHYSICAL_ADDRESS logicalAddress;
|
|
ULONG blockSize, remain;
|
|
PUHCD_BUFFER_POOL bufferPool;
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// first figure our what size buffer we are dealing with
|
|
//
|
|
|
|
bufferPool = UHCD_SelectBufferPool(DeviceObject, CommonBufferLength);
|
|
LOGENTRY(LOG_MISC, 'ACbb', bufferPool, NumberOfPages, CommonBufferLength);
|
|
|
|
if (bufferPool == NULL) {
|
|
//
|
|
// Generally this means that CommonBufferLength is an illegal size
|
|
// so we punt without growing the pools
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// select the descriptor list based on the size of the request
|
|
//
|
|
memoryDescriptorFreePool = &bufferPool->MemoryDescriptorFreePool;
|
|
//
|
|
// set CommonBufferLength based on the descriptor list we selected
|
|
//
|
|
CommonBufferLength = bufferPool->CommonBufferLength;
|
|
|
|
#if DBG
|
|
{
|
|
//
|
|
// Dump out the size of the free pool for this buffer type
|
|
//
|
|
ULONG freeBytes, freeCommonBuffers;
|
|
|
|
freeCommonBuffers = UHCD_FreePoolSize(bufferPool, &freeBytes);
|
|
LOGENTRY(LOG_MISC, 'frBB', freeCommonBuffers, freeBytes, bufferPool);
|
|
UHCD_KdPrint(
|
|
(2, "'before alloc pool size = %d # buffs = %d total = %d bytes\n",
|
|
bufferPool->CommonBufferLength, freeCommonBuffers, freeBytes));
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Grow the pool..
|
|
// BUGBUG
|
|
// we always grow by one page
|
|
//
|
|
|
|
LOGENTRY(LOG_MISC, 'grow', NumberOfPages, bufferPool, CommonBufferLength);
|
|
|
|
//
|
|
// calc the number of bytes
|
|
//
|
|
|
|
blockSize = NumberOfPages*PAGE_SIZE;
|
|
|
|
//
|
|
// allocate some shared memory
|
|
//
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
#ifdef MAX_DEBUG
|
|
if (KeGetCurrentIrql() > APC_LEVEL) {
|
|
UHCD_KdPrint((2, "UHCD calling HalAllocateCommonBuffer at DPC level\n"));
|
|
TEST_TRAP();
|
|
}
|
|
#endif
|
|
|
|
virtualAddress =
|
|
baseVirtualAddress =
|
|
HalAllocateCommonBuffer(deviceExtension->AdapterObject,
|
|
blockSize,
|
|
&logicalAddress,
|
|
TRUE);
|
|
|
|
#if DBG
|
|
UHCD_CommonBufferBytes += blockSize;
|
|
#endif
|
|
|
|
// remember the base Virtual Address so we can free it later
|
|
// we need to keep track of the common buffers we allocate
|
|
|
|
if (baseVirtualAddress) {
|
|
|
|
PUHCD_PAGE_LIST_ENTRY pageListEntry;
|
|
|
|
UHCD_KdPrint((2, "'page list size = %d\n", sizeof(UHCD_PAGE_LIST_ENTRY)));
|
|
|
|
//
|
|
// CIMEXCIMEX
|
|
//
|
|
|
|
UHCD_ASSERT((sizeof(UHCD_PAGE_LIST_ENTRY) % 32) == 0);
|
|
|
|
pageListEntry =
|
|
(PUHCD_PAGE_LIST_ENTRY) baseVirtualAddress;
|
|
|
|
pageListEntry->Length = blockSize;
|
|
pageListEntry->LogicalAddress = logicalAddress;
|
|
pageListEntry->Flags = 0;
|
|
|
|
baseVirtualAddress += sizeof(UHCD_PAGE_LIST_ENTRY);
|
|
virtualAddress = baseVirtualAddress;
|
|
blockSize -= sizeof(UHCD_PAGE_LIST_ENTRY);
|
|
logicalAddress.LowPart += sizeof(UHCD_PAGE_LIST_ENTRY);
|
|
|
|
// link it in
|
|
InsertTailList(&deviceExtension->PageList,
|
|
&pageListEntry->ListEntry);
|
|
}
|
|
|
|
|
|
//
|
|
// break the new block up in to memory descriptors
|
|
// and put them on the free list.
|
|
//
|
|
|
|
if (baseVirtualAddress) {
|
|
ULONG length;
|
|
|
|
remain = blockSize;
|
|
|
|
//
|
|
// first grow the current pool by as many buffers
|
|
// as possible
|
|
//
|
|
|
|
|
|
hwLogicalAddress = logicalAddress.LowPart;
|
|
endVirtualAddress = baseVirtualAddress + (blockSize - 1);
|
|
|
|
length = UHCD_GrowBufferPool(DeviceObject, bufferPool,
|
|
CommonBufferLength, virtualAddress,
|
|
endVirtualAddress, hwLogicalAddress);
|
|
|
|
virtualAddress+=length;
|
|
hwLogicalAddress+=length;
|
|
|
|
//
|
|
// use what is left over for smaller buffers
|
|
//
|
|
remain -= length;
|
|
|
|
|
|
if (remain > (UHCD_MEDIUM_COMMON_BUFFER_SIZE + UHCD_HW_DESCRIPTOR_SIZE)) {
|
|
|
|
UHCD_ASSERT(virtualAddress < endVirtualAddress);
|
|
|
|
length = UHCD_GrowBufferPool(DeviceObject,
|
|
&deviceExtension->SmallBufferPool,
|
|
UHCD_MEDIUM_COMMON_BUFFER_SIZE,
|
|
virtualAddress, endVirtualAddress,
|
|
hwLogicalAddress);
|
|
|
|
virtualAddress+=length;
|
|
hwLogicalAddress+=length;
|
|
remain -= length;
|
|
}
|
|
|
|
if (remain >
|
|
(UHCD_SMALL_COMMON_BUFFER_SIZE + UHCD_HW_DESCRIPTOR_SIZE)) {
|
|
|
|
UHCD_ASSERT(virtualAddress < endVirtualAddress);
|
|
|
|
length = UHCD_GrowBufferPool(DeviceObject,
|
|
&deviceExtension->SmallBufferPool,
|
|
UHCD_SMALL_COMMON_BUFFER_SIZE,
|
|
virtualAddress, endVirtualAddress,
|
|
hwLogicalAddress);
|
|
remain -= length;
|
|
}
|
|
|
|
LOGENTRY(LOG_MISC, 'WSTE', remain, 0, 0);
|
|
|
|
} /* Grow the Pool */
|
|
|
|
#if DBG
|
|
{
|
|
//
|
|
// Dump out the size of the free pool for this buffer type
|
|
//
|
|
ULONG freeBytes, freeCommonBuffers;
|
|
|
|
freeCommonBuffers = UHCD_FreePoolSize(bufferPool, &freeBytes);
|
|
LOGENTRY(LOG_MISC, 'frB2', freeCommonBuffers, freeBytes, bufferPool);
|
|
UHCD_KdPrint(
|
|
(2, "'after alloc pool size = %d # buffs = %d total = %d bytes\n",
|
|
bufferPool->CommonBufferLength, freeCommonBuffers, freeBytes));
|
|
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_FreeCommonBufferBlocks(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempt to release unused shared memory to the system.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
// not implemented
|
|
UHCD_KdTrap(("FreeCommonBufferBlocks not supported yet\n"));
|
|
}
|
|
|
|
|
|
ULONG
|
|
UHCD_CheckCommonBufferPool(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_BUFFER_POOL BufferPool,
|
|
IN BOOLEAN Allocate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempt to grow of ree common buffers relative to the maximum
|
|
free pool size.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
Return Value:
|
|
|
|
Returns number of pages needed or grown
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ULONG freeBytes, freeCommonBuffers;
|
|
ULONG pagesNeeded = 0;
|
|
|
|
//
|
|
// make sure our reserve of common buffers is
|
|
// kept up
|
|
//
|
|
|
|
//
|
|
// Dump out the size of the free pool for this buffer type
|
|
//
|
|
|
|
UHCD_ASSERT_BUFFER_POOL(BufferPool);
|
|
|
|
freeCommonBuffers = UHCD_FreePoolSize(BufferPool, &freeBytes);
|
|
UHCD_KdPrint((2, "'pool size = %d # buffs = %d total = %d bytes\n",
|
|
BufferPool->CommonBufferLength, freeCommonBuffers, freeBytes));
|
|
|
|
if (freeCommonBuffers < BufferPool->MaximumFreeBuffers) {
|
|
// we are below the maximum buffers we like to
|
|
// keep available, grow the pool to this size
|
|
|
|
//
|
|
// allocate more common buffers, request the
|
|
// number of pages needed to satisfy the request
|
|
//
|
|
|
|
pagesNeeded = ((BufferPool->MaximumFreeBuffers - freeCommonBuffers)*
|
|
BufferPool->CommonBufferLength) / PAGE_SIZE;
|
|
pagesNeeded++;
|
|
|
|
if (Allocate) {
|
|
UHCD_AllocateCommonBufferBlock(DeviceObject,
|
|
BufferPool->CommonBufferLength,
|
|
pagesNeeded);
|
|
}
|
|
|
|
}
|
|
|
|
return pagesNeeded;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_MoreCommonBuffers(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempt to release unused shared memory to the system.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUHCD_WORKITEM workItem;
|
|
KIRQL irql;
|
|
ULONG need;
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
LOGENTRY(LOG_MISC, 'mCMB', 0, KeGetCurrentIrql(), 0);
|
|
|
|
if (KeGetCurrentIrql() > APC_LEVEL) {
|
|
LOGENTRY(LOG_MISC, 'mCPS', 0, 0, 0);
|
|
|
|
need = UHCD_CheckCommonBufferPool(DeviceObject,
|
|
&deviceExtension->LargeBufferPool,
|
|
FALSE)+
|
|
UHCD_CheckCommonBufferPool(DeviceObject,
|
|
&deviceExtension->MediumBufferPool,
|
|
FALSE)+
|
|
UHCD_CheckCommonBufferPool(DeviceObject,
|
|
&deviceExtension->SmallBufferPool,
|
|
FALSE);
|
|
|
|
KeAcquireSpinLock(&deviceExtension->HcFlagSpin, &irql);
|
|
|
|
if (deviceExtension->HcFlags & HCFLAG_WORK_ITEM_QUEUED || need == 0) {
|
|
KeReleaseSpinLock(&deviceExtension->HcFlagSpin, irql);
|
|
return;
|
|
} else {
|
|
|
|
deviceExtension->HcFlags |= HCFLAG_WORK_ITEM_QUEUED;
|
|
KeReleaseSpinLock(&deviceExtension->HcFlagSpin, irql);
|
|
|
|
workItem = GETHEAP(NonPagedPool, sizeof(UHCD_WORKITEM));
|
|
|
|
if (workItem) {
|
|
|
|
workItem->DeviceObject = DeviceObject;
|
|
|
|
|
|
|
|
ExInitializeWorkItem(&workItem->WorkQueueItem,
|
|
UHCD_GrowPoolWorker,
|
|
workItem);
|
|
|
|
ExQueueWorkItem(&workItem->WorkQueueItem,
|
|
DelayedWorkQueue);
|
|
} else {
|
|
KeAcquireSpinLock(&deviceExtension->HcFlagSpin, &irql);
|
|
deviceExtension->HcFlags &= ~HCFLAG_WORK_ITEM_QUEUED;
|
|
KeReleaseSpinLock(&deviceExtension->HcFlagSpin, irql);
|
|
}
|
|
}
|
|
} else {
|
|
|
|
LOGENTRY(LOG_MISC, 'mCnS', 0, 0, 0);
|
|
//
|
|
// make sure our reserve of common buffers is
|
|
// kept up
|
|
//
|
|
|
|
UHCD_CheckCommonBufferPool(DeviceObject,
|
|
&deviceExtension->LargeBufferPool,
|
|
TRUE);
|
|
|
|
UHCD_CheckCommonBufferPool(DeviceObject,
|
|
&deviceExtension->MediumBufferPool,
|
|
TRUE);
|
|
|
|
UHCD_CheckCommonBufferPool(DeviceObject,
|
|
&deviceExtension->SmallBufferPool,
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_InitializeCommonBufferPool(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PUHCD_BUFFER_POOL BufferPool,
|
|
IN ULONG CommonBufferLength,
|
|
IN ULONG MaximumFreeBuffers
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
PAGED_CODE();
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
// BUGBUG Note:
|
|
// for now we only support one size pool
|
|
//
|
|
|
|
KeInitializeSpinLock(&BufferPool->MemoryDescriptorFreePoolSpin);
|
|
|
|
BufferPool->MemoryDescriptorFreePool.Next = NULL;
|
|
BufferPool->CommonBufferLength = CommonBufferLength;
|
|
BufferPool->MaximumFreeBuffers = MaximumFreeBuffers;
|
|
BufferPool->Sig = UHCD_BP_SIG;
|
|
//
|
|
// This is where we intially grow the pool to
|
|
// some default size.
|
|
//
|
|
}
|
|
|
|
|
|
#if 0
|
|
VOID
|
|
UHCD_BufferPoolCheck(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by open_endpoint start_io.
|
|
This routine sanity checks our buffer pools.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PUHCD_BUFFER_POOL smallBufferPool;
|
|
PUHCD_BUFFER_POOL mediumBufferPool;
|
|
PUHCD_BUFFER_POOL LargeBufferPool;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
|
|
// UHCD_ASSERT(smallBufferPool->ReservedBuffers == 0);
|
|
// UHCD_ASSERT(largeBufferPool->ReservedBuffers == 0);
|
|
}
|
|
#endif
|
|
|
|
ULONG
|
|
UHCD_GrowBufferPool(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_BUFFER_POOL BufferPool,
|
|
IN ULONG Length,
|
|
IN PUCHAR VirtualAddress,
|
|
IN PUCHAR EndVirtualAddress,
|
|
IN HW_DESCRIPTOR_PHYSICAL_ADDRESS HwLogicalAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to grow a specific buffer pool
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
BufferPool - buffer pool to add these descriptors to.
|
|
|
|
Length - length of buffers to allocate
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PUHCD_MEMORY_DESCRIPTOR memoryDescriptor = NULL;
|
|
ULONG consumed = 0;
|
|
|
|
PAGED_CODE();
|
|
//
|
|
// buffers must be 32 byte aligned for the hardware
|
|
//
|
|
|
|
UHCD_ASSERT((Length/32)*32 == Length);
|
|
|
|
// we have a buffer, break it up in to memory descriptors
|
|
// and add them to the free list
|
|
|
|
do {
|
|
//
|
|
// CIMEXCIMEX
|
|
//
|
|
|
|
UHCD_ASSERT(sizeof(*memoryDescriptor) == UHCD_HW_DESCRIPTOR_SIZE);
|
|
|
|
memoryDescriptor = (PUHCD_MEMORY_DESCRIPTOR) VirtualAddress;
|
|
memoryDescriptor->VirtualAddress =
|
|
VirtualAddress+UHCD_HW_DESCRIPTOR_SIZE;
|
|
memoryDescriptor->LogicalAddress =
|
|
HwLogicalAddress+UHCD_HW_DESCRIPTOR_SIZE;
|
|
memoryDescriptor->Sig = SIG_MD;
|
|
memoryDescriptor->InUse++;
|
|
LOGENTRY(LOG_MISC, 'grad', VirtualAddress , memoryDescriptor, Length);
|
|
|
|
memoryDescriptor->Length = Length;
|
|
consumed+=memoryDescriptor->Length+UHCD_HW_DESCRIPTOR_SIZE;
|
|
HwLogicalAddress += memoryDescriptor->Length+UHCD_HW_DESCRIPTOR_SIZE;
|
|
VirtualAddress += memoryDescriptor->Length+UHCD_HW_DESCRIPTOR_SIZE;
|
|
|
|
// put it on the free list by
|
|
// calling the free routine
|
|
memoryDescriptor->BufferPool = BufferPool;
|
|
|
|
UHCD_FreeCommonBuffer(DeviceObject, memoryDescriptor);
|
|
LOGENTRY(LOG_MISC, 'grbf', VirtualAddress , Length, EndVirtualAddress);
|
|
} while (VirtualAddress + Length +
|
|
UHCD_HW_DESCRIPTOR_SIZE <= EndVirtualAddress);
|
|
|
|
LOGENTRY(LOG_MISC, 'grpl', consumed , BufferPool, 0);
|
|
|
|
return consumed;
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_GrowPoolWorker(
|
|
IN PVOID Context
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* NTSTATUS
|
|
*
|
|
* -- */
|
|
{
|
|
PUHCD_WORKITEM workItem = Context;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
KIRQL irql;
|
|
|
|
LOGENTRY(LOG_MISC, 'gpwk', Context , 0, 0);
|
|
|
|
deviceExtension = workItem->DeviceObject->DeviceExtension;
|
|
|
|
UHCD_MoreCommonBuffers(workItem->DeviceObject);
|
|
|
|
KeAcquireSpinLock(&deviceExtension->HcFlagSpin, &irql);
|
|
deviceExtension->HcFlags &= ~HCFLAG_WORK_ITEM_QUEUED;
|
|
KeReleaseSpinLock(&deviceExtension->HcFlagSpin, irql);
|
|
|
|
RETHEAP(workItem);
|
|
}
|
|
|
|
#define UHCD_NO_DMA_BUFFER_USED 0x00000001
|
|
#define UHCD_NO_DMA_BUFFER_FREE 0x00000002
|
|
|
|
VOID
|
|
UHCD_Free_NoDMA_Buffer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUCHAR NoDMABuffer
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* This function adds a No DMA buffer to our page list
|
|
* so that i will be freed when the HCD driver unloads
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* NTSTATUS
|
|
*
|
|
* -- */
|
|
{
|
|
PUHCD_PAGE_LIST_ENTRY pageListEntry;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
NoDMABuffer -= sizeof(UHCD_PAGE_LIST_ENTRY);
|
|
|
|
pageListEntry =
|
|
(PUHCD_PAGE_LIST_ENTRY) NoDMABuffer;
|
|
|
|
// just mark it free
|
|
pageListEntry->Flags = UHCD_NO_DMA_BUFFER_FREE;
|
|
|
|
}
|
|
|
|
|
|
PUCHAR
|
|
UHCD_Alloc_NoDMA_Buffer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_ENDPOINT Endpoint,
|
|
IN ULONG Length
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* This function adds a No DMA buffer to our page list
|
|
* so that i will be freed when the HCD driver unloads
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* NTSTATUS
|
|
*
|
|
* -- */
|
|
{
|
|
PUHCD_PAGE_LIST_ENTRY pageListEntry;
|
|
PUCHAR noDMABuffer;
|
|
PHYSICAL_ADDRESS logicalAddress;
|
|
PUCHAR baseVirtualAddress = NULL;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PLIST_ENTRY listEntry;
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
UHCD_KdPrint((2, "'page list size = %d\n", sizeof(UHCD_PAGE_LIST_ENTRY)));
|
|
UHCD_ASSERT(sizeof(UHCD_PAGE_LIST_ENTRY) == 32);
|
|
|
|
noDMABuffer = NULL;
|
|
Length+=sizeof(UHCD_PAGE_LIST_ENTRY);
|
|
|
|
// first see if we have a buffer we can use
|
|
|
|
// walk the list, see if there is a free double_buffer entry
|
|
|
|
listEntry = &deviceExtension->PageList;
|
|
if (!IsListEmpty(listEntry)) {
|
|
listEntry = deviceExtension->PageList.Flink;
|
|
}
|
|
|
|
while (listEntry != &deviceExtension->PageList) {
|
|
|
|
pageListEntry = (PUHCD_PAGE_LIST_ENTRY) CONTAINING_RECORD(
|
|
listEntry,
|
|
struct _UHCD_PAGE_LIST_ENTRY,
|
|
ListEntry);
|
|
|
|
LOGENTRY(LOG_MISC, 'ple>', 0 , pageListEntry->Length, pageListEntry);
|
|
|
|
if (pageListEntry->Flags == UHCD_NO_DMA_BUFFER_FREE &&
|
|
pageListEntry->Length >= Length) {
|
|
|
|
UHCD_KdPrint((2, "'re-use page list\n"));
|
|
baseVirtualAddress = (PUCHAR) pageListEntry;
|
|
break;
|
|
}
|
|
|
|
listEntry = pageListEntry->ListEntry.Flink;
|
|
}
|
|
|
|
if (baseVirtualAddress) {
|
|
|
|
// mark it used
|
|
pageListEntry->Flags = UHCD_NO_DMA_BUFFER_USED;
|
|
logicalAddress = pageListEntry->LogicalAddress;
|
|
Length = pageListEntry->Length;
|
|
|
|
LOGENTRY(LOG_MISC, 'rUse', baseVirtualAddress , 0, pageListEntry);
|
|
|
|
UHCD_ASSERT(baseVirtualAddress == (PUCHAR) pageListEntry);
|
|
|
|
}
|
|
|
|
|
|
if (baseVirtualAddress == NULL) {
|
|
|
|
// no buffer -- allocate one
|
|
|
|
baseVirtualAddress =
|
|
HalAllocateCommonBuffer(deviceExtension->AdapterObject,
|
|
Length,
|
|
&logicalAddress,
|
|
TRUE);
|
|
|
|
|
|
if (baseVirtualAddress != NULL) {
|
|
|
|
pageListEntry =
|
|
(PUHCD_PAGE_LIST_ENTRY) baseVirtualAddress;
|
|
|
|
pageListEntry->Length = Length;
|
|
pageListEntry->LogicalAddress = logicalAddress;
|
|
pageListEntry->Flags = UHCD_NO_DMA_BUFFER_USED;
|
|
|
|
|
|
// link it in
|
|
InsertTailList(&deviceExtension->PageList,
|
|
&pageListEntry->ListEntry);
|
|
|
|
LOGENTRY(LOG_MISC, 'Nple', 0 , 0, pageListEntry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (baseVirtualAddress) {
|
|
|
|
pageListEntry->Flags = UHCD_NO_DMA_BUFFER_USED;
|
|
noDMABuffer = baseVirtualAddress + sizeof(UHCD_PAGE_LIST_ENTRY);
|
|
Length -= sizeof(UHCD_PAGE_LIST_ENTRY);
|
|
logicalAddress.LowPart += sizeof(UHCD_PAGE_LIST_ENTRY);
|
|
|
|
Endpoint->NoDMABufferLength = Length;
|
|
// Endpoint->NoDMALogicalAddress = logicalAddress;
|
|
Endpoint->NoDMAPhysicalAddress = logicalAddress.LowPart;
|
|
}
|
|
|
|
return noDMABuffer;
|
|
}
|
|
|
|
|
|
|
|
|