diff options
Diffstat (limited to 'private/ntos/ndis/ndis40/common.c')
-rw-r--r-- | private/ntos/ndis/ndis40/common.c | 3452 |
1 files changed, 3452 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndis40/common.c b/private/ntos/ndis/ndis40/common.c new file mode 100644 index 000000000..d9ef88449 --- /dev/null +++ b/private/ntos/ndis/ndis40/common.c @@ -0,0 +1,3452 @@ +/*++ + +Copyright (c) 1990-1995 Microsoft Corporation + +Module Name: + + common.c + +Abstract: + + NDIS wrapper functions common to miniports and full mac drivers + +Author: + + Adam Barr (adamba) 11-Jul-1990 + +Environment: + + Kernel mode, FSD + +Revision History: + + 26-Feb-1991 JohnsonA Added Debugging Code + 10-Jul-1991 JohnsonA Implement revised Ndis Specs + 01-Jun-1995 JameelH Re-organization/optimization + 09-Apr-1996 KyleB Added resource remove and acquisition routines. + +--*/ + + +#include <precomp.h> +#pragma hdrstop + +#include <stdarg.h> + +// +// Define the module number for debug code. +// +#define MODULE_NUMBER MODULE_COMMON + +// +// Routines for dealing with making the PKG specific routines pagable +// + +VOID +ndisInitializePackage( + IN PPKG_REF pPkg, + IN PVOID RoutineName + ) +{ + // + // Allocate the spin lock + // + INITIALIZE_SPIN_LOCK(&pPkg->ReferenceLock); + + // + // Initialize the "in page" event. + // + INITIALIZE_EVENT(&pPkg->PagedInEvent); + + // Lock and unlock the section to obtain the handle. Subsequent locks will be faster + pPkg->ImageHandle = MmLockPagableCodeSection(RoutineName); + MmUnlockPagableImageSection(pPkg->ImageHandle); +} + + +VOID +ndisReferencePackage( + IN PPKG_REF pPkg +) +{ + KIRQL OldIrql; + + // + // Grab the spin lock + // + ACQUIRE_SPIN_LOCK(&pPkg->ReferenceLock, &OldIrql); + + // + // Increment the reference count + // + pPkg->ReferenceCount++; + + if (pPkg->ReferenceCount == 1) + { + // + // We are the first reference. Page everything in. + // + + // + // Clear the event + // + RESET_EVENT(&pPkg->PagedInEvent); + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql); + + // + // Page in all the functions + // + MmLockPagableSectionByHandle(pPkg->ImageHandle); + + // + // Signal to everyone to go + // + SET_EVENT(&pPkg->PagedInEvent); + } + else + { + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql); + + // + // Wait for everything to be paged in + // + WAIT_FOR_OBJECT(&pPkg->PagedInEvent, NULL); + } +} + + +VOID +ndisDereferencePackage( + IN PPKG_REF pPkg + ) +{ + KIRQL OldIrql; + + // + // Get the spin lock + // + ACQUIRE_SPIN_LOCK(&pPkg->ReferenceLock, &OldIrql); + + pPkg->ReferenceCount--; + + if (pPkg->ReferenceCount == 0) + { + // + // Let next one in + // + RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(pPkg->ImageHandle); + } + else + { + // + // Let next one in + // + RELEASE_SPIN_LOCK(&pPkg->ReferenceLock, OldIrql); + } +} + + + +NDIS_STATUS +NdisAllocateMemory( + OUT PVOID * VirtualAddress, + IN UINT Length, + IN UINT MemoryFlags, + IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress + ) +/*++ + +Routine Description: + + Allocate memory for use by a protocol or a MAC driver + +Arguments: + + VirtualAddress - Returns a pointer to the allocated memory. + Length - Size of requested allocation in bytes. + MaximumPhysicalAddress - Highest addressable address of the allocated + memory.. 0 means highest system memory possible. + MemoryFlags - Bit mask that allows the caller to specify attributes + of the allocated memory. 0 means standard memory. + + other options: + + NDIS_MEMORY_CONTIGUOUS + NDIS_MEMORY_NONCACHED + +Return Value: + + NDIS_STATUS_SUCCESS if successful. + NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL. + + +--*/ +{ + // + // Depending on the value of MemoryFlags, we allocate three different + // types of memory. + // + + if (MemoryFlags == 0) + { + *VirtualAddress = ALLOC_FROM_POOL(Length, NDIS_TAG_ALLOC_MEM); + } + else if (MemoryFlags & NDIS_MEMORY_NONCACHED) + { + *VirtualAddress = MmAllocateNonCachedMemory(Length); + } + else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) + { + *VirtualAddress = MmAllocateContiguousMemory(Length, HighestAcceptableAddress); + } + + return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS; +} + + +NDIS_STATUS +NdisAllocateMemoryWithTag( + OUT PVOID * VirtualAddress, + IN UINT Length, + IN ULONG Tag + ) +/*++ + +Routine Description: + + Allocate memory for use by a protocol or a MAC driver + +Arguments: + + VirtualAddress - Returns a pointer to the allocated memory. + Length - Size of requested allocation in bytes. + Tag - tag to associate with this memory. + +Return Value: + + NDIS_STATUS_SUCCESS if successful. + NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL. + + +--*/ +{ + + *VirtualAddress = ALLOC_FROM_POOL(Length, Tag); + return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS; +} + + +VOID +NdisFreeMemory( + IN PVOID VirtualAddress, + IN UINT Length, + IN UINT MemoryFlags + ) +/*++ + +Routine Description: + + Releases memory allocated using NdisAllocateMemory. + +Arguments: + + VirtualAddress - Pointer to the memory to be freed. + Length - Size of allocation in bytes. + MemoryFlags - Bit mask that allows the caller to specify attributes + of the allocated memory. 0 means standard memory. + + other options: + + NDIS_MEMORY_CONTIGUOUS + NDIS_MEMORY_NONCACHED + +Return Value: + + None. + +--*/ +{ + // + // Depending on the value of MemoryFlags, we allocate three free 3 + // types of memory. + // + + if (MemoryFlags == 0) + { + FREE_POOL(VirtualAddress); + } + else if (MemoryFlags & NDIS_MEMORY_NONCACHED) + { + MmFreeNonCachedMemory(VirtualAddress, Length); + } + else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) + { + MmFreeContiguousMemory(VirtualAddress); + } +} + +// +// Packet and Buffer requests +// + +VOID +NdisAllocatePacketPool( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE PoolHandle, + IN UINT NumberOfDescriptors, + IN UINT ProtocolReservedLength + ) + +/*++ + +Routine Description: + + Initializes a packet pool. All packets are the same + size for a given pool (as determined by ProtocolReservedLength), + so a simple linked list of free packets is set up initially. + +Arguments: + + Status - Returns the final status (always NDIS_STATUS_SUCCESS). + PoolHandle - Returns a pointer to the pool. + NumberOfDescriptors - Number of packet descriptors needed. + ProtocolReservedLength - How long the ProtocolReserved field + should be for packets in this pool. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PACKET_POOL TmpPool; + PUCHAR FreeEntry; + UINT PacketLength; + UINT i; + + // + // Set up the size of packets in this pool (rounded + // up to sizeof(ULONG) for alignment). + // + + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("==>NdisAllocatePacketPool\n")); + + PacketLength = FIELD_OFFSET(NDIS_PACKET, ProtocolReserved) + + sizeof(NDIS_PACKET_OOB_DATA) + + sizeof(NDIS_PACKET_PRIVATE_EXTENSION) + + ((ProtocolReservedLength + sizeof(ULONGLONG) - 1) & ~(sizeof(ULONGLONG) -1)); + + // + // Allocate space needed + // + TmpPool = (PNDIS_PACKET_POOL)ALLOC_FROM_POOL(sizeof(NDIS_PACKET_POOL) + + (PacketLength * NumberOfDescriptors), + NDIS_TAG_PKT_POOL); + if (TmpPool == NULL) + { + *Status = NDIS_STATUS_RESOURCES; + return; + } + + ZeroMemory(TmpPool, PacketLength * NumberOfDescriptors); + TmpPool->PacketLength = PacketLength; + + // + // First entry in free list is at beginning of pool space. + // + TmpPool->FreeList = (PNDIS_PACKET)TmpPool->Buffer; + FreeEntry = TmpPool->Buffer; + + for (i = 1; i < NumberOfDescriptors; i++) + { + // + // Each entry is linked to the "packet" PacketLength bytes + // ahead of it, using the Private.Head field. + // + ((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)(FreeEntry + PacketLength); + FreeEntry += PacketLength; + } + + // + // Final free list entry. + // + ((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)NULL; + + NdisAllocateSpinLock(&TmpPool->SpinLock); + + *Status = NDIS_STATUS_SUCCESS; + *PoolHandle = (NDIS_HANDLE)TmpPool; + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("<==NdisAllocatePacketPool\n")); +} + + +#undef NdisFreePacketPool + +VOID +NdisFreePacketPool( + IN NDIS_HANDLE PoolHandle + ) +{ + NdisFreeSpinLock(&((PNDIS_PACKET_POOL)PoolHandle)->SpinLock); + FREE_POOL(PoolHandle); +} + + +VOID +NdisAllocateBufferPool( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE PoolHandle, + IN UINT NumberOfDescriptors + ) +/*++ + +Routine Description: + + Initializes a block of storage so that buffer descriptors can be + allocated. + +Arguments: + + Status - status of the request. + PoolHandle - handle that is used to specify the pool + NumberOfDescriptors - Number of buffer descriptors in the pool. + +Return Value: + + None. + +--*/ +{ + // + // A nop for NT + // + UNREFERENCED_PARAMETER(NumberOfDescriptors); + + *PoolHandle = NULL; + *Status = NDIS_STATUS_SUCCESS; +} + + +VOID +NdisFreeBufferPool( + IN NDIS_HANDLE PoolHandle + ) +/*++ + +Routine Description: + + Terminates usage of a buffer descriptor pool. + +Arguments: + + PoolHandle - handle that is used to specify the pool + +Return Value: + + None. + +--*/ +{ + UNREFERENCED_PARAMETER(PoolHandle); +} + + +VOID +NdisAllocateBuffer( + OUT PNDIS_STATUS Status, + OUT PNDIS_BUFFER * Buffer, + IN NDIS_HANDLE PoolHandle, + IN PVOID VirtualAddress, + IN UINT Length + ) +/*++ + +Routine Description: + + Creates a buffer descriptor to describe a segment of virtual memory + allocated via NdisAllocateMemory (which always allocates nonpaged). + +Arguments: + + Status - Status of the request. + Buffer - Pointer to the allocated buffer descriptor. + PoolHandle - Handle that is used to specify the pool. + VirtualAddress - The virtual address of the buffer. + Length - The Length of the buffer. + +Return Value: + + None. + +--*/ +{ + UNREFERENCED_PARAMETER(PoolHandle); + + *Status = NDIS_STATUS_FAILURE; + if ((*Buffer = IoAllocateMdl(VirtualAddress, + Length, + FALSE, + FALSE, + NULL)) != NULL) + { + MmBuildMdlForNonPagedPool(*Buffer); + (*Buffer)->Next = NULL; + *Status = NDIS_STATUS_SUCCESS; + } +} + + +#undef NdisAdjustBufferLength +VOID +NdisAdjustBufferLength( + IN PNDIS_BUFFER Buffer, + IN UINT Length + ) +{ + Buffer->ByteCount = Length; +} + + +VOID +NdisCopyBuffer( + OUT PNDIS_STATUS Status, + OUT PNDIS_BUFFER * Buffer, + IN NDIS_HANDLE PoolHandle, + IN PVOID MemoryDescriptor, + IN UINT Offset, + IN UINT Length + ) +/*++ + +Routine Description: + + Used to create a buffer descriptor given a memory descriptor. + +Arguments: + + Status - Status of the request. + Buffer - Pointer to the allocated buffer descriptor. + PoolHandle - Handle that is used to specify the pool. + MemoryDescriptor - Pointer to the descriptor of the source memory. + Offset - The Offset in the sources memory from which the copy is to begin + Length - Number of Bytes to copy. + +Return Value: + + None. + +--*/ +{ + PNDIS_BUFFER SourceDescriptor = (PNDIS_BUFFER)MemoryDescriptor; + PVOID BaseVa = (((PUCHAR)MDL_VA(SourceDescriptor)) + Offset); + + UNREFERENCED_PARAMETER(PoolHandle); + + *Status = NDIS_STATUS_FAILURE; + if ((*Buffer = IoAllocateMdl(BaseVa, + Length, + FALSE, + FALSE, + NULL)) != NULL) + { + IoBuildPartialMdl(SourceDescriptor, + *Buffer, + BaseVa, + Length); + + (*Buffer)->Next = NULL; + *Status = NDIS_STATUS_SUCCESS; + } +} + + +#define ndisAllocatePacketFromPool(_Pool, _ppPacket) \ + { \ + \ + /* \ + * See if any packets are on pool free list. \ + */ \ + \ + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, \ + ("==>NdisAllocatePacket\n")); \ + \ + IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR) \ + { \ + if (DbgIsNull(PoolHandle)) \ + { \ + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, \ + ("AllocatePacket: NULL Pool address\n")); \ + DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); \ + } \ + if (!DbgIsNonPaged(PoolHandle)) \ + { \ + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, \ + ("AllocatePacket: Pool not in NonPaged Memory\n")); \ + DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); \ + } \ + } \ + \ + *(_ppPacket) = Pool->FreeList; \ + if (Pool->FreeList != (PNDIS_PACKET)NULL) \ + { \ + /* \ + * Take free packet off head of list and return it. \ + */ \ + \ + Pool->FreeList = (PNDIS_PACKET)(*(_ppPacket))->Private.Head; \ + } \ + } + +#define ndisInitializePacket(_Pool, _Packet) \ + { \ + PNDIS_PACKET_PRIVATE_EXTENSION PacketExt; \ + \ + ZeroMemory((_Packet), (_Pool)->PacketLength); \ + (_Packet)->Private.Pool = (PNDIS_PACKET_POOL)(_Pool); \ + (_Packet)->Private.ValidCounts = TRUE; \ + (_Packet)->Private.NdisPacketFlags = fPACKET_ALLOCATED_BY_NDIS; \ + \ + /* \ + * Set the offset to the out of band data. \ + */ \ + (_Packet)->Private.NdisPacketOobOffset = (USHORT)( \ + (_Pool)->PacketLength - \ + sizeof(NDIS_PACKET_OOB_DATA) - \ + sizeof(NDIS_PACKET_PRIVATE_EXTENSION));\ + \ + /* \ + * Set the pointer to the packet linkage information for ndis. \ + */ \ + PacketExt = (PNDIS_PACKET_PRIVATE_EXTENSION)((PUCHAR)(_Packet) + \ + (_Packet)->Private.NdisPacketOobOffset + \ + sizeof(NDIS_PACKET_OOB_DATA)); \ + PacketExt->Packet = (_Packet); \ + } + +VOID +NdisAllocatePacket( + OUT PNDIS_STATUS Status, + OUT PNDIS_PACKET * Packet, + IN NDIS_HANDLE PoolHandle + ) + +/*++ + +Routine Description: + + Allocates a packet out of a packet pool. + +Arguments: + + Status - Returns the final status. + Packet - Return a pointer to the packet. + PoolHandle - The packet pool to allocate from. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PACKET_POOL Pool = (PNDIS_PACKET_POOL)PoolHandle; + KIRQL OldIrql; + + NDIS_ACQUIRE_SPIN_LOCK(&Pool->SpinLock, &OldIrql); + + ndisAllocatePacketFromPool(PoolHandle, Packet); + + NDIS_RELEASE_SPIN_LOCK(&Pool->SpinLock, OldIrql); + + if (*Packet != (PNDIS_PACKET)NULL) + { + // + // Clear packet elements. + // + ndisInitializePacket(Pool, *Packet); + + *Status = NDIS_STATUS_SUCCESS; + } + else + { + // + // No, cannot satisfy request. + // + + *Status = NDIS_STATUS_RESOURCES; + } + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("<==NdisAllocatePacket\n")); +} + + +VOID +NdisDprAllocatePacket( + OUT PNDIS_STATUS Status, + OUT PNDIS_PACKET * Packet, + IN NDIS_HANDLE PoolHandle + ) + +/*++ + +Routine Description: + + Allocates a packet out of a packet pool. Similar to NdisAllocatePacket + but can only be called at raised irql. + +Arguments: + + Status - Returns the final status. + Packet - Return a pointer to the packet. + PoolHandle - The packet pool to allocate from. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PACKET_POOL Pool = (PNDIS_PACKET_POOL)PoolHandle; + + NDIS_ACQUIRE_SPIN_LOCK_DPC(&Pool->SpinLock); + + ndisAllocatePacketFromPool(PoolHandle, Packet); + + NDIS_RELEASE_SPIN_LOCK_DPC(&Pool->SpinLock); + + if (*Packet != (PNDIS_PACKET)NULL) + { + // + // Clear packet elements. + // + ndisInitializePacket(Pool, *Packet); + + *Status = NDIS_STATUS_SUCCESS; + } + else + { + // + // No, cannot satisfy request. + // + + *Status = NDIS_STATUS_RESOURCES; + } + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("<==NdisDprAllocatePacket\n")); +} + + +VOID +NdisDprAllocatePacketNonInterlocked( + OUT PNDIS_STATUS Status, + OUT PNDIS_PACKET * Packet, + IN NDIS_HANDLE PoolHandle + ) + +/*++ + +Routine Description: + + Allocates a packet out of a packet pool. Similar to NdisAllocatePacket + but is not interlocked. Caller guarantees synchronization. + +Arguments: + + Status - Returns the final status. + Packet - Return a pointer to the packet. + PoolHandle - The packet pool to allocate from. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PACKET_POOL Pool = (PNDIS_PACKET_POOL)PoolHandle; + + ndisAllocatePacketFromPool(PoolHandle, Packet); + + if (*Packet != (PNDIS_PACKET)NULL) + { + // + // Clear packet elements. + // + ndisInitializePacket(Pool, *Packet); + + *Status = NDIS_STATUS_SUCCESS; + } + else + { + // + // No, cannot satisfy request. + // + + *Status = NDIS_STATUS_RESOURCES; + } + + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("<==NdisDprAllocatePacketNonInterlocked\n")); +} + + +#undef NdisFreePacket + +VOID +NdisFreePacket( + IN PNDIS_PACKET Packet + ) +{ + Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList); + Packet->Private.Pool->FreeList = Packet; +} + +#undef NdisDprFreePacket + +VOID +NdisDprFreePacket( + IN PNDIS_PACKET Packet + ) +{ + NdisDprAcquireSpinLock(&Packet->Private.Pool->SpinLock); + + Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList); + Packet->Private.Pool->FreeList = Packet; + + NdisDprReleaseSpinLock(&Packet->Private.Pool->SpinLock); +} + +#undef NdisDprFreePacketNonInterlocked + +VOID +NdisDprFreePacketNonInterlocked( + IN PNDIS_PACKET Packet + ) +{ + Packet->Private.Head = (PNDIS_BUFFER)(Packet->Private.Pool->FreeList); + Packet->Private.Pool->FreeList = Packet; +} + + +VOID +NdisUnchainBufferAtFront( + IN OUT PNDIS_PACKET Packet, + OUT PNDIS_BUFFER * Buffer + ) + +/*++ + +Routine Description: + + Takes a buffer off the front of a packet. + +Arguments: + + Packet - The packet to be modified. + Buffer - Returns the packet on the front, or NULL. + +Return Value: + + None. + +--*/ + +{ + *Buffer = Packet->Private.Head; + + // + // If packet is not empty, remove head buffer. + // + + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("==>NdisUnchainBufferAtFront\n")); + + IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR) + { + BOOLEAN f = FALSE; + if (DbgIsNull(Packet)) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("UnchainBufferAtFront: Null Packet Pointer\n")); + f = TRUE; + } + if (!DbgIsNonPaged(Packet)) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("UnchainBufferAtFront: Packet not in NonPaged Memory\n")); + f = TRUE; + } + if (!DbgIsPacket(Packet)) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("UnchainBufferAtFront: Illegal Packet Size\n")); + f = TRUE; + } + if (f) + DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); + } + + if (*Buffer != (PNDIS_BUFFER)NULL) + { + Packet->Private.Head = (*Buffer)->Next; // may be NULL + (*Buffer)->Next = (PNDIS_BUFFER)NULL; + Packet->Private.ValidCounts = FALSE; + } + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("<==NdisUnchainBufferAtFront\n")); +} + + +VOID +NdisUnchainBufferAtBack( + IN OUT PNDIS_PACKET Packet, + OUT PNDIS_BUFFER * Buffer + ) + +/*++ + +Routine Description: + + Takes a buffer off the end of a packet. + +Arguments: + + Packet - The packet to be modified. + Buffer - Returns the packet on the end, or NULL. + +Return Value: + + None. + +--*/ + +{ + PNDIS_BUFFER BufP = Packet->Private.Head; + PNDIS_BUFFER Result; + + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("==>NdisUnchainBufferAtBack\n")); + + IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR) + { + BOOLEAN f = FALSE; + if (DbgIsNull(Packet)) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("UnchainBufferAtBack: Null Packet Pointer\n")); + f = TRUE; + } + if (!DbgIsNonPaged(Packet)) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("UnchainBufferAtBack: Packet not in NonPaged Memory\n")); + f = TRUE; + } + if (!DbgIsPacket(Packet)) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("UnchainBufferAtBack: Illegal Packet Size\n")); + f = TRUE; + } + if (f) + DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR); + } + if (BufP != (PNDIS_BUFFER)NULL) + { + // + // The packet is not empty, return the tail buffer. + // + + Result = Packet->Private.Tail; + if (BufP == Result) + { + // + // There was only one buffer on the queue. + // + + Packet->Private.Head = (PNDIS_BUFFER)NULL; + } + else + { + // + // Determine the new tail buffer. + // + + while (BufP->Next != Result) + { + BufP = BufP->Next; + } + Packet->Private.Tail = BufP; + BufP->Next = NULL; + } + + Result->Next = (PNDIS_BUFFER)NULL; + Packet->Private.ValidCounts = FALSE; + } + else + { + // + // Packet is empty. + // + + Result = (PNDIS_BUFFER)NULL; + } + + *Buffer = Result; + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("<==NdisUnchainBufferAtBack\n")); +} + + + +VOID +NdisCopyFromPacketToPacket( + IN PNDIS_PACKET Destination, + IN UINT DestinationOffset, + IN UINT BytesToCopy, + IN PNDIS_PACKET Source, + IN UINT SourceOffset, + OUT PUINT BytesCopied + ) + +/*++ + +Routine Description: + + Copy from an ndis packet to an ndis packet. + +Arguments: + + Destination - The packet should be copied in to. + + DestinationOffset - The offset from the beginning of the packet + into which the data should start being placed. + + BytesToCopy - The number of bytes to copy from the source packet. + + Source - The ndis packet from which to copy data. + + SourceOffset - The offset from the start of the packet from which + to start copying data. + + BytesCopied - The number of bytes actually copied from the source + packet. This can be less than BytesToCopy if the source or destination + packet is too short. + +Return Value: + + None + +--*/ + +{ + // + // Holds the count of the number of ndis buffers comprising the + // destination packet. + // + UINT DestinationBufferCount; + + // + // Holds the count of the number of ndis buffers comprising the + // source packet. + // + UINT SourceBufferCount; + + // + // Points to the buffer into which we are putting data. + // + PNDIS_BUFFER DestinationCurrentBuffer; + + // + // Points to the buffer from which we are extracting data. + // + PNDIS_BUFFER SourceCurrentBuffer; + + // + // Holds the virtual address of the current destination buffer. + // + PVOID DestinationVirtualAddress; + + // + // Holds the virtual address of the current source buffer. + // + PVOID SourceVirtualAddress; + + // + // Holds the length of the current destination buffer. + // + UINT DestinationCurrentLength; + + // + // Holds the length of the current source buffer. + // + UINT SourceCurrentLength; + + // + // Keep a local variable of BytesCopied so we aren't referencing + // through a pointer. + // + UINT LocalBytesCopied = 0; + + // + // Take care of boundary condition of zero length copy. + // + + *BytesCopied = 0; + if (!BytesToCopy) + return; + + // + // Get the first buffer of the destination. + // + + NdisQueryPacket(Destination, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL); + + // + // Could have a null packet. + // + + if (!DestinationBufferCount) + return; + + NdisQueryBuffer(DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength); + + // + // Get the first buffer of the source. + // + + NdisQueryPacket(Source, + NULL, + &SourceBufferCount, + &SourceCurrentBuffer, + NULL); + + // + // Could have a null packet. + // + + if (!SourceBufferCount) + return; + + NdisQueryBuffer(SourceCurrentBuffer, + &SourceVirtualAddress, + &SourceCurrentLength); + + while (LocalBytesCopied < BytesToCopy) + { + // + // Check to see whether we've exhausted the current destination + // buffer. If so, move onto the next one. + // + + if (!DestinationCurrentLength) + { + NdisGetNextBuffer(DestinationCurrentBuffer, &DestinationCurrentBuffer); + + if (!DestinationCurrentBuffer) + { + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer(DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength); + continue; + } + + + // + // Check to see whether we've exhausted the current source + // buffer. If so, move onto the next one. + // + + if (!SourceCurrentLength) + { + NdisGetNextBuffer(SourceCurrentBuffer, &SourceCurrentBuffer); + + if (!SourceCurrentBuffer) + { + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + } + + NdisQueryBuffer(SourceCurrentBuffer, + &SourceVirtualAddress, + &SourceCurrentLength); + continue; + } + + // + // Try to get us up to the point to start the copy. + // + + if (DestinationOffset) + { + if (DestinationOffset > DestinationCurrentLength) + { + // + // What we want isn't in this buffer. + // + + DestinationOffset -= DestinationCurrentLength; + DestinationCurrentLength = 0; + continue; + } + else + { + DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress + + DestinationOffset; + DestinationCurrentLength -= DestinationOffset; + DestinationOffset = 0; + } + } + + // + // Try to get us up to the point to start the copy. + // + + if (SourceOffset) + { + if (SourceOffset > SourceCurrentLength) + { + // + // What we want isn't in this buffer. + // + + SourceOffset -= SourceCurrentLength; + SourceCurrentLength = 0; + continue; + } + else + { + SourceVirtualAddress = (PCHAR)SourceVirtualAddress + + SourceOffset; + SourceCurrentLength -= SourceOffset; + SourceOffset = 0; + } + } + + // + // Copy the data. + // + + { + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + // + // Holds the amount desired remaining. + // + UINT Remaining = BytesToCopy - LocalBytesCopied; + + AmountToMove = + ((SourceCurrentLength <= DestinationCurrentLength)? + (SourceCurrentLength):(DestinationCurrentLength)); + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + CopyMemory(DestinationVirtualAddress, SourceVirtualAddress, AmountToMove); + + DestinationVirtualAddress = + (PCHAR)DestinationVirtualAddress + AmountToMove; + SourceVirtualAddress = + (PCHAR)SourceVirtualAddress + AmountToMove; + + LocalBytesCopied += AmountToMove; + SourceCurrentLength -= AmountToMove; + DestinationCurrentLength -= AmountToMove; + } + } + + *BytesCopied = LocalBytesCopied; +} + +VOID +NdisAllocateSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + OUT PVOID * VirtualAddress, + OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + Allocates memory to be shared between the driver and the adapter. + +Arguments: + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + Length - Length of the memory to allocate. + Cached - TRUE if memory is to be cached. + VirtualAddress - Returns the virtual address of the memory, + or NULL if the memory cannot be allocated. + PhysicalAddress - Returns the physical address of the memory. + +Return Value: + + None. + +--*/ + +{ + PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + PADAPTER_OBJECT SystemAdapterObject; + PNDIS_WRAPPER_CONTEXT WrapperContext; + PULONG Page; + ULONG Type; + + // + // Get interesting information from the adapter/miniport. + // + + if (AdaptP->DeviceObject != NULL) + { + SystemAdapterObject = AdaptP->SystemAdapterObject; + WrapperContext = AdaptP->WrapperContext; + } + else + { + SystemAdapterObject = Miniport->SystemAdapterObject; + WrapperContext = Miniport->WrapperContext; + } + + // + // Non-busmasters shouldn't call this routine. + // + + if (SystemAdapterObject == NULL) + { + *VirtualAddress = NULL; + KdPrint(("You are not a busmaster\n")); + return; + } + + // + // Compute allocation size by aligning to the proper boundary. + // + + ASSERT(Length != 0); + + Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 1); + + // + // Check to determine is there is enough room left in the current page + // to satisfy the allocation. + // + + Type = Cached ? 1 : 0; + ExAcquireResourceExclusive(&SharedMemoryResource, TRUE); + + do + { + if (WrapperContext->SharedMemoryLeft[Type] < Length) + { + if ((Length + sizeof(ULONG)) >= PAGE_SIZE) + { + // + // The allocation is greater than a page. + // + + *VirtualAddress = HalAllocateCommonBuffer(SystemAdapterObject, + Length, + PhysicalAddress, + Cached); + break; + } + + // + // Allocate a new page for shared alocation. + // + + WrapperContext->SharedMemoryPage[Type] = + HalAllocateCommonBuffer(SystemAdapterObject, + PAGE_SIZE, + &WrapperContext->SharedMemoryAddress[Type], + Cached); + + if (WrapperContext->SharedMemoryPage[Type] == NULL) + { + WrapperContext->SharedMemoryLeft[Type] = 0; + *VirtualAddress = NULL; + break; + } + + // + // Initialize the reference count in the last ULONG of the page. + // + + Page = (PULONG)WrapperContext->SharedMemoryPage[Type]; + Page[(PAGE_SIZE / sizeof(ULONG)) - 1] = 0; + WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(ULONG); + } + + // + // Increment the reference count, set the address of the allocation, + // compute the physical address, and reduce the space remaining. + // + + Page = (PULONG)WrapperContext->SharedMemoryPage[Type]; + Page[(PAGE_SIZE / sizeof(ULONG)) - 1] += 1; + *VirtualAddress = (PVOID)((PUCHAR)Page + + (PAGE_SIZE - sizeof(ULONG) - WrapperContext->SharedMemoryLeft[Type])); + + PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart + + ((ULONG)*VirtualAddress & (PAGE_SIZE - 1)); + + WrapperContext->SharedMemoryLeft[Type] -= Length; + } while (FALSE); + + ExReleaseResource(&SharedMemoryResource); +} + + +#undef NdisUpdateSharedMemory + +VOID +NdisUpdateSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + Ensures that the data to be read from a shared memory region is + fully up-to-date. + +Arguments: + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + Length - The length of the shared memory. + VirtualAddress - Virtual address returned by NdisAllocateSharedMemory. + PhysicalAddress - The physical address returned by NdisAllocateSharedMemory. + +Return Value: + + None. + +--*/ + +{ + // + // There is no underlying HAL routine for this anymore, + // it is not needed. + // + + NdisAdapterHandle; Length; VirtualAddress; PhysicalAddress; +} + + +VOID +NdisFreeSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + Frees shared memory allocated via NdisAllocateSharedMemory. + +Arguments: + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + Length - Length of the memory to allocate. + Cached - TRUE if memory was allocated cached. + VirtualAddress - Virtual address returned by NdisAllocateSharedMemory. + PhysicalAddress - The physical address returned by NdisAllocateSharedMemory. + +Return Value: + + None. + +--*/ + +{ + PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + PADAPTER_OBJECT SystemAdapterObject; + PNDIS_WRAPPER_CONTEXT WrapperContext; + PULONG Page; + ULONG Type; + + // + // Get interesting information from the adapter/miniport. + // + + if (AdaptP->DeviceObject != NULL) + { + SystemAdapterObject = AdaptP->SystemAdapterObject; + WrapperContext = AdaptP->WrapperContext; + } + else + { + SystemAdapterObject = Miniport->SystemAdapterObject; + WrapperContext = Miniport->WrapperContext; + } + + // + // Non-busmasters shouldn't call this routine. + // + + ASSERT(SystemAdapterObject != NULL); + + // + // Compute allocation size by aligning to the proper boundary. + // + + ASSERT(Length != 0); + + Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 1); + + // + // Free the specified memory. + // + + ExAcquireResourceExclusive(&SharedMemoryResource, TRUE); + if ((Length + sizeof(ULONG)) >= PAGE_SIZE) + { + // + // The allocation is greater than a page free the page directly. + // + + HalFreeCommonBuffer(SystemAdapterObject, + Length, + PhysicalAddress, + VirtualAddress, + Cached); + } + else + { + // + // Decrement the reference count and if the result is zero, then free + // the page. + // + + Page = (PULONG)((ULONG)VirtualAddress & ~(PAGE_SIZE - 1)); + Page[(PAGE_SIZE / sizeof(ULONG)) - 1] -= 1; + if (Page[(PAGE_SIZE / sizeof(ULONG)) - 1] == 0) + { + // + // Compute the physical address of the page and free it. + // + + PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1); + HalFreeCommonBuffer(SystemAdapterObject, + PAGE_SIZE, + PhysicalAddress, + Page, + Cached); + + Type = Cached ? 1 : 0; + if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type]) + { + WrapperContext->SharedMemoryLeft[Type] = 0; + WrapperContext->SharedMemoryPage[Type] = NULL; + } + } + } + + ExReleaseResource(&SharedMemoryResource); +} + + +BOOLEAN +ndisCheckPortUsage( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG PortNumber, + IN ULONG Length, + IN PDRIVER_OBJECT DriverObject +) +/*++ + +Routine Description: + + This routine checks if a port is currently in use somewhere in the + system via IoReportUsage -- which fails if there is a conflict. + +Arguments: + + InterfaceType - The bus type (ISA, EISA) + BusNumber - Bus number in the system + PortNumber - Address of the port to access. + Length - Number of ports from the base address to access. + +Return Value: + + FALSE if there is a conflict, else TRUE + +--*/ + +{ + NTSTATUS NtStatus; + BOOLEAN Conflict; + NTSTATUS FirstNtStatus; + BOOLEAN FirstConflict; + PCM_RESOURCE_LIST Resources; + + // + // Allocate space for resources + // + Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NDIS_TAG_DEFAULT); + + if (Resources == NULL) + { + // + // Error out + // + + return FALSE; + } + + Resources->Count = 1; + Resources->List[0].InterfaceType = InterfaceType; + Resources->List[0].BusNumber = BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 1; + + // + // Setup port + // + Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort; + Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags = + (InterfaceType == Internal)? + CM_RESOURCE_PORT_MEMORY : + CM_RESOURCE_PORT_IO; + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart = PortNumber; + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = Length; + + // + // Submit Resources + // + FirstNtStatus = IoReportResourceUsage(NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &FirstConflict); + + // + // Now clear it out + // + Resources->List[0].PartialResourceList.Count = 0; + + NtStatus = IoReportResourceUsage(NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &Conflict); + + FREE_POOL(Resources); + + // + // Check for conflict. + // + + if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) + { + return FALSE; + } + + return TRUE; +} + + +NTSTATUS +ndisStartMapping( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG InitialAddress, + IN ULONG Length, + OUT PVOID * InitialMapping, + OUT PBOOLEAN Mapped + ) + +/*++ + +Routine Description: + + This routine initialize the mapping of a address into virtual + space dependent on the bus number, etc. + +Arguments: + + InterfaceType - The bus type (ISA, EISA) + BusNumber - Bus number in the system + InitialAddress - Address to access. + Length - Number of bytes from the base address to access. + InitialMapping - The virtual address space to use when accessing the + address. + Mapped - Did an MmMapIoSpace() take place. + +Return Value: + + The function value is the status of the operation. + +--*/ +{ + PHYSICAL_ADDRESS Address; + PHYSICAL_ADDRESS InitialPhysAddress; + ULONG addressSpace; + + // + // Get the system physical address for this card. The card uses + // I/O space, except for "internal" Jazz devices which use + // memory space. + // + + *Mapped = FALSE; + + addressSpace = (InterfaceType == Internal) ? 0 : 1; + + InitialPhysAddress.LowPart = InitialAddress; + + InitialPhysAddress.HighPart = 0; + + if (!HalTranslateBusAddress(InterfaceType, // InterfaceType + BusNumber, // BusNumber + InitialPhysAddress, // Bus Address + &addressSpace, // AddressSpace + &Address)) // Translated address + { + // + // It would be nice to return a better status here, but we only get + // TRUE/FALSE back from HalTranslateBusAddress. + // + + return NDIS_STATUS_FAILURE; + } + + if (addressSpace == 0) + { + // + // memory space + // + + *InitialMapping = MmMapIoSpace(Address, Length, FALSE); + + if (*InitialMapping == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + *Mapped = TRUE; + } + else + { + // + // I/O space + // + + *InitialMapping = (PVOID)Address.LowPart; + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +ndisEndMapping( + IN PVOID InitialMapping, + IN ULONG Length, + IN BOOLEAN Mapped + ) + +/*++ + +Routine Description: + + This routine undoes the mapping of an address into virtual + space dependent on the bus number, etc. + +Arguments: + + InitialMapping - The virtual address space to use when accessing the + address. + Length - Number of bytes from the base address to access. + Mapped - Do we need to call MmUnmapIoSpace. + +Return Value: + + The function value is the status of the operation. + +--*/ +{ + + if (Mapped) + { + // + // memory space + // + + MmUnmapIoSpace(InitialMapping, Length); + } + + return STATUS_SUCCESS; +} + + +VOID +NdisImmediateReadPortUchar( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PUCHAR Data + ) +/*++ + +Routine Description: + + This routine reads from a port a UCHAR. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. If so map the space. + // + if ((ndisCheckPortUsage(BusType, + BusNumber, + Port, + sizeof(UCHAR), + DriverObject) == FALSE) || + !NT_SUCCESS(Status = ndisStartMapping(BusType, + BusNumber, + Port, + sizeof(UCHAR), + &PortMapping, + &Mapped))) + { + *Data = (UCHAR)0xFF; + return; + } + // + // Read from the port + // + + *Data = READ_PORT_UCHAR((PUCHAR)PortMapping); + + // + // End port mapping + // + + ndisEndMapping(PortMapping, sizeof(UCHAR), Mapped); +} + +VOID +NdisImmediateReadPortUshort( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PUSHORT Data + ) +/*++ + +Routine Description: + + This routine reads from a port a USHORT. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. If so map the space. + // + if ((ndisCheckPortUsage(BusType, + BusNumber, + Port, + sizeof(USHORT), + DriverObject) == FALSE) || + !NT_SUCCESS(Status = ndisStartMapping(BusType, + BusNumber, + Port, + sizeof(USHORT), + &PortMapping, + &Mapped))) + { + *Data = (USHORT)0xFFFF; + return; + } + + // + // Read from the port + // + + *Data = READ_PORT_USHORT((PUSHORT)PortMapping); + + // + // End port mapping + // + + ndisEndMapping(PortMapping, sizeof(USHORT), Mapped); +} + + +VOID +NdisImmediateReadPortUlong( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PULONG Data + ) +/*++ + +Routine Description: + + This routine reads from a port a ULONG. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. If so map the space. + // + if ((ndisCheckPortUsage(BusType, + BusNumber, + Port, + sizeof(ULONG), + DriverObject) == FALSE) || + !NT_SUCCESS(Status = ndisStartMapping(BusType, + BusNumber, + Port, + sizeof(ULONG), + &PortMapping, + &Mapped))) + { + *Data = (ULONG)0xFFFFFFFF; + return; + } + + // + // Read from the port + // + + *Data = READ_PORT_ULONG((PULONG)PortMapping); + + // + // End port mapping + // + + ndisEndMapping(PortMapping, sizeof(ULONG), Mapped); +} + +VOID +NdisImmediateWritePortUchar( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN UCHAR Data + ) +/*++ + +Routine Description: + + This routine writes to a port a UCHAR. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. If so map the space. + // + if ((ndisCheckPortUsage(BusType, + BusNumber, + Port, + sizeof(UCHAR), + DriverObject) == FALSE) || + !NT_SUCCESS(Status = ndisStartMapping(BusType, + BusNumber, + Port, + sizeof(UCHAR), + &PortMapping, + &Mapped))) + { + return; + } + + // + // Read from the port + // + + WRITE_PORT_UCHAR((PUCHAR)PortMapping, Data); + + // + // End port mapping + // + + ndisEndMapping(PortMapping, sizeof(UCHAR), Mapped); +} + +VOID +NdisImmediateWritePortUshort( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN USHORT Data + ) +/*++ + +Routine Description: + + This routine writes to a port a USHORT. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. If so map the space. + // + if ((ndisCheckPortUsage(BusType, + BusNumber, + Port, + sizeof(USHORT), + DriverObject) == FALSE) || + !NT_SUCCESS(Status = ndisStartMapping(BusType, + BusNumber, + Port, + sizeof(USHORT), + &PortMapping, + &Mapped))) + { + return; + } + + // + // Read from the port + // + + WRITE_PORT_USHORT((PUSHORT)PortMapping, Data); + + // + // End port mapping + // + + ndisEndMapping(PortMapping, sizeof(USHORT), Mapped); +} + +VOID +NdisImmediateWritePortUlong( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN ULONG Data + ) +/*++ + +Routine Description: + + This routine writes to a port a ULONG. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. If so map the space. + // + if ((ndisCheckPortUsage(BusType, + BusNumber, + Port, + sizeof(ULONG), + DriverObject) == FALSE) || + !NT_SUCCESS(Status = ndisStartMapping(BusType, + BusNumber, + Port, + sizeof(ULONG), + &PortMapping, + &Mapped))) + // + // Read from the port + // + + WRITE_PORT_ULONG((PULONG)PortMapping, Data); + + // + // End port mapping + // + + ndisEndMapping(PortMapping, sizeof(ULONG), Mapped); +} + + +BOOLEAN +ndisCheckMemoryUsage( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG Address, + IN ULONG Length, + IN PDRIVER_OBJECT DriverObject +) +/*++ +Routine Description: + + This routine checks if a range of memory is currently in use somewhere + in the system via IoReportUsage -- which fails if there is a conflict. + +Arguments: + + InterfaceType - The bus type (ISA, EISA) + BusNumber - Bus number in the system + Address - Starting Address of the memory to access. + Length - Length of memory from the base address to access. + +Return Value: + + FALSE if there is a conflict, else TRUE + +--*/ +{ + NTSTATUS NtStatus; + BOOLEAN Conflict; + NTSTATUS FirstNtStatus; + BOOLEAN FirstConflict; + PCM_RESOURCE_LIST Resources; + + // + // Allocate space for resources + // + + Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NDIS_TAG_DEFAULT); + + if (Resources == NULL) + { + // + // Error out + // + + return FALSE; + } + + Resources->Count = 1; + Resources->List[0].InterfaceType = InterfaceType; + Resources->List[0].BusNumber = BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 1; + + // + // Setup memory + // + + Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = + CmResourceTypeMemory; + Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = + CmResourceShareDriverExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags = + CM_RESOURCE_MEMORY_READ_WRITE; + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart = Address; + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Length = Length; + + + // + // Submit Resources + // + FirstNtStatus = IoReportResourceUsage(NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &FirstConflict); + + // + // Now clear it out + // + Resources->List[0].PartialResourceList.Count = 0; + + NtStatus = IoReportResourceUsage(NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &Conflict); + + FREE_POOL(Resources); + + // + // Check for conflict. + // + + return (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) ? FALSE : TRUE; +} + + +VOID +NdisImmediateReadSharedMemory( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SharedMemoryAddress, + OUT PUCHAR Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine read into a buffer from shared ram. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + SharedMemoryAddress - The physical address to read from. + + Buffer - The buffer to read into. + + Length - Length of the buffer in bytes. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID MemoryMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the memory is available. Map the space + // + + if ((ndisCheckMemoryUsage(BusType, + BusNumber, + SharedMemoryAddress, + Length, + DriverObject) == FALSE) || + !NT_SUCCESS(ndisStartMapping(BusType, + BusNumber, + SharedMemoryAddress, + Length, + &MemoryMapping, + &Mapped))) + { + return; + } + + // + // Read from memory + // + +#ifdef _M_IX86 + + memcpy(Buffer, MemoryMapping, Length); + +#else + + READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length); + +#endif + + // + // End mapping + // + + ndisEndMapping(MemoryMapping, + Length, + Mapped); +} + + +VOID +NdisImmediateWriteSharedMemory( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SharedMemoryAddress, + IN PUCHAR Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine writes a buffer to shared ram. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + SharedMemoryAddress - The physical address to write to. + + Buffer - The buffer to write. + + Length - Length of the buffer in bytes. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID MemoryMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the memory is available. Map the space + // + if ((ndisCheckMemoryUsage(BusType, + BusNumber, + SharedMemoryAddress, + Length, + DriverObject) == FALSE) || + !NT_SUCCESS(ndisStartMapping(BusType, + BusNumber, + SharedMemoryAddress, + Length, + &MemoryMapping, + &Mapped))) + { + return; + } + + // + // Write to memory + // + +#ifdef _M_IX86 + + memcpy(MemoryMapping, Buffer, Length); + +#else + + WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length); + +#endif + + // + // End mapping + // + + ndisEndMapping(MemoryMapping, Length, Mapped); +} + + +VOID +NdisOpenFile( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE FileHandle, + OUT PUINT FileLength, + IN PNDIS_STRING FileName, + IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress + ) + +/*++ + +Routine Description: + + This routine opens a file for future mapping and reads its contents + into allocated memory. + +Arguments: + + Status - The status of the operation + + FileHandle - A handle to be associated with this open + + FileLength - Returns the length of the file + + FileName - The name of the file + + HighestAcceptableAddress - The highest physical address at which + the memory for the file can be allocated. + +Return Value: + + None. + +--*/ +{ + NTSTATUS NtStatus; + IO_STATUS_BLOCK IoStatus; + HANDLE NtFileHandle; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG LengthOfFile; + WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\"; + NDIS_STRING FullFileName; + ULONG FullFileNameLength; + PNDIS_FILE_DESCRIPTOR FileDescriptor; + PVOID FileImage; + + // + // This structure represents the data from the + // NtQueryInformationFile API with an information + // class of FileStandardInformation. + // + + FILE_STANDARD_INFORMATION StandardInfo; + + + // + // Insert the correct path prefix. + // + + FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength; + FullFileName.Buffer = ALLOC_FROM_POOL(FullFileNameLength, NDIS_TAG_DEFAULT); + + do + { + if (FullFileName.Buffer == NULL) + { + *Status = NDIS_STATUS_RESOURCES; + break; + } + FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR); + FullFileName.MaximumLength = (USHORT)FullFileNameLength; + CopyMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix)); + + RtlAppendUnicodeStringToString (&FullFileName, FileName); + + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("Attempting to open %Z\n", &FullFileName)); + + InitializeObjectAttributes(&ObjectAttributes, + &FullFileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + NtStatus = ZwCreateFile(&NtFileHandle, + SYNCHRONIZE | FILE_READ_DATA, + &ObjectAttributes, + &IoStatus, + NULL, + 0, + FILE_SHARE_READ, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); + + FREE_POOL(FullFileName.Buffer); + + if (!NT_SUCCESS(NtStatus)) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("Error opening file %x\n", NtStatus)); + *Status = NDIS_STATUS_FILE_NOT_FOUND; + break; + } + + // + // Query the object to determine its length. + // + + NtStatus = ZwQueryInformationFile(NtFileHandle, + &IoStatus, + &StandardInfo, + sizeof(FILE_STANDARD_INFORMATION), + FileStandardInformation); + + if (!NT_SUCCESS(NtStatus)) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("Error querying info on file %x\n", NtStatus)); + ZwClose(NtFileHandle); + *Status = NDIS_STATUS_ERROR_READING_FILE; + break; + } + + LengthOfFile = StandardInfo.EndOfFile.LowPart; + + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO, + ("File length is %d\n", LengthOfFile)); + + // + // Might be corrupted. + // + + if (LengthOfFile < 1) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("Bad file length %d\n", LengthOfFile)); + ZwClose(NtFileHandle); + *Status = NDIS_STATUS_ERROR_READING_FILE; + break; + } + + // + // Allocate buffer for this file + // + + FileImage = ALLOC_FROM_POOL(LengthOfFile, NDIS_TAG_DEFAULT); + + if (FileImage == NULL) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("Could not allocate buffer\n")); + ZwClose(NtFileHandle); + *Status = NDIS_STATUS_ERROR_READING_FILE; + break; + } + + // + // Read the file into our buffer. + // + + NtStatus = ZwReadFile(NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + FileImage, + LengthOfFile, + NULL, + NULL); + + ZwClose(NtFileHandle); + + if ((!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile)) + { + DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, + ("error reading file %x\n", NtStatus)); + *Status = NDIS_STATUS_ERROR_READING_FILE; + FREE_POOL(FileImage); + break; + } + + // + // Allocate a structure to describe the file. + // + + FileDescriptor = ALLOC_FROM_POOL(sizeof(NDIS_FILE_DESCRIPTOR), NDIS_TAG_DEFAULT); + + if (FileDescriptor == NULL) + { + *Status = NDIS_STATUS_RESOURCES; + FREE_POOL(FileImage); + break; + } + + FileDescriptor->Data = FileImage; + INITIALIZE_SPIN_LOCK (&FileDescriptor->Lock); + FileDescriptor->Mapped = FALSE; + + *FileHandle = (NDIS_HANDLE)FileDescriptor; + *FileLength = LengthOfFile; + *Status = STATUS_SUCCESS; + } while (FALSE); +} + + +VOID +NdisCloseFile( + IN NDIS_HANDLE FileHandle + ) + +/*++ + +Routine Description: + + This routine closes a file previously opened with NdisOpenFile. + The file is unmapped if needed and the memory is freed. + +Arguments: + + FileHandle - The handle returned by NdisOpenFile + +Return Value: + + None. + +--*/ +{ + PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle; + + FREE_POOL(FileDescriptor->Data); + FREE_POOL(FileDescriptor); +} + + +VOID +NdisMapFile( + OUT PNDIS_STATUS Status, + OUT PVOID * MappedBuffer, + IN NDIS_HANDLE FileHandle + ) + +/*++ + +Routine Description: + + This routine maps an open file, so that the contents can be accessed. + Files can only have one active mapping at any time. + +Arguments: + + Status - The status of the operation + + MappedBuffer - Returns the virtual address of the mapping. + + FileHandle - The handle returned by NdisOpenFile. + +Return Value: + + None. + +--*/ +{ + KIRQL OldIrql; + + PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle; + + ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock, &OldIrql); + + if (FileDescriptor->Mapped == TRUE) + { + *Status = NDIS_STATUS_ALREADY_MAPPED; + RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql); + return; + } + + FileDescriptor->Mapped = TRUE; + RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql); + + *MappedBuffer = FileDescriptor->Data; + *Status = STATUS_SUCCESS; +} + + +VOID +NdisUnmapFile( + IN NDIS_HANDLE FileHandle + ) + +/*++ + +Routine Description: + + This routine unmaps a file previously mapped with NdisOpenFile. + The file is unmapped if needed and the memory is freed. + +Arguments: + + FileHandle - The handle returned by NdisOpenFile + +Return Value: + + None. + +--*/ + +{ + PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle; + KIRQL OldIrql; + + ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock, &OldIrql); + FileDescriptor->Mapped = FALSE; + RELEASE_SPIN_LOCK (&FileDescriptor->Lock, OldIrql); +} + + +CCHAR +NdisSystemProcessorCount( + VOID + ) +{ + return **((PCHAR *)&KeNumberProcessors); +} + + +VOID +NdisGetSystemUpTime( + OUT PULONG pSystemUpTime + ) +{ + LARGE_INTEGER TickCount; + + // + // Get tick count and convert to hundreds of nanoseconds. + // + KeQueryTickCount(&TickCount); + TickCount = RtlExtendedIntegerMultiply(TickCount, + KeQueryTimeIncrement()); + TickCount = RtlExtendedIntegerMultiply(TickCount, 10000); + + ASSERT(TickCount.HighPart == 0); + *pSystemUpTime = TickCount.LowPart; +} + +VOID +NdisGetCurrentProcessorCpuUsage( + IN PULONG pCpuUsage +) +{ + PKPRCB Prcb; + + Prcb = KeGetCurrentPrcb(); + *pCpuUsage = 100 - (ULONG)(UInt32x32To64(Prcb->IdleThread->KernelTime, 100) / + (ULONGLONG)(Prcb->KernelTime + Prcb->UserTime)); +} + + +VOID +NdisGetCurrentProcessorCounts( + OUT PULONG pIdleCount, + OUT PULONG pKernelAndUser, + OUT PULONG pIndex + ) +{ + PKPRCB Prcb; + + Prcb = KeGetCurrentPrcb(); + *pIdleCount = Prcb->IdleThread->KernelTime; + *pKernelAndUser = Prcb->KernelTime + Prcb->UserTime; + *pIndex = (ULONG)Prcb->Number; +} + +#undef NdisGetCurrentSystemTime +VOID +NdisGetCurrentSystemTime( + IN PLARGE_INTEGER pCurrentTime +) +{ + KeQuerySystemTime(pCurrentTime); +} + + + +NDIS_STATUS +NdisQueryMapRegisterCount( + IN NDIS_INTERFACE_TYPE BusType, + OUT PUINT MapRegisterCount +) +{ + NTSTATUS Status; + UINT Count, Tmp; + + Count = (UINT)BusType; + Status = HalQuerySystemInformation(HalMapRegisterInformation, + sizeof(UINT), + &Count, + &Tmp); + if (NT_SUCCESS(Status)) + { + *MapRegisterCount = Count; + return NDIS_STATUS_SUCCESS; + } + + return NDIS_STATUS_NOT_SUPPORTED; +} + + +// +// NDIS Event support +// + +VOID +NdisInitializeEvent( + IN PNDIS_EVENT Event + ) +{ + INITIALIZE_EVENT(&Event->Event); +} + +VOID +NdisSetEvent( + IN PNDIS_EVENT Event + ) +{ + SET_EVENT(&Event->Event); +} + +VOID +NdisResetEvent( + IN PNDIS_EVENT Event + ) +{ + RESET_EVENT(&Event->Event); +} + +BOOLEAN +NdisWaitEvent( + IN PNDIS_EVENT Event, + IN UINT MsToWait + ) +{ + NTSTATUS Status; + TIME Time, *pTime; + + pTime = NULL; + if (MsToWait != 0) + { + ASSERT(CURRENT_IRQL < DISPATCH_LEVEL); + Time.QuadPart = Int32x32To64(MsToWait, -10000); + pTime = &Time; + } + + Status = WAIT_FOR_OBJECT(&Event->Event, pTime); + + return(Status == NDIS_STATUS_SUCCESS); +} + +VOID +NdisInitializeString( + OUT PNDIS_STRING Destination, + IN PUCHAR Source + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + WCHAR *strptr; + + Destination->Length = strlen(Source) * sizeof(WCHAR); + Destination->MaximumLength = Destination->Length + sizeof(WCHAR); + Destination->Buffer = ALLOC_FROM_POOL(Destination->MaximumLength, NDIS_TAG_STRING); + + strptr = Destination->Buffer; + while (*Source != '\0') + { + *strptr = (WCHAR)*Source; + Source++; + strptr++; + } + *strptr = UNICODE_NULL; +} + + +NDIS_STATUS +ndisReportResources( + PCM_RESOURCE_LIST Resources, + PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT DeviceObject, + PNDIS_STRING AdapterName, + ULONG NewResourceType + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NDIS_STATUS Status; + BOOLEAN Conflict; + + // + // When we report the resources we need to subtract 1 from the + // count. this is because the sizeof(CM_RESOURCE_LIST) already includes + // one CM_PARTIAL_RESOURCE_DESCRIPTOR and if we multiply by the current + // Count the size passed to IoReportResourceUsage will be one descriptor + // too many. + // + Status = IoReportResourceUsage(NULL, + DriverObject, + NULL, + 0, + DeviceObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (Resources->List->PartialResourceList.Count - 1)), + TRUE, + &Conflict); + + // + // Check for conflict. + // + if (Conflict || (Status != STATUS_SUCCESS)) + { + if (Conflict) + { + // + // Log an error + // + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG i; + ULONG StringSize; + PUCHAR Place; + PWCH baseFileName; + USHORT logsize; + + baseFileName = AdapterName->Buffer; + + // + // Parse out the path name, leaving only the device name. + // + for (i = 0; i < AdapterName->Length / sizeof(WCHAR); i++) + { + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + if (AdapterName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR) + { + baseFileName = &(AdapterName->Buffer[++i]); + } + } + + StringSize = AdapterName->MaximumLength - + ((ULONG)baseFileName - (ULONG)AdapterName->Buffer); + logsize = sizeof(IO_ERROR_LOG_PACKET) + StringSize + 6; + if (logsize > 255) + { + logsize = 255; + } + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + DeviceObject, + (UCHAR)logsize); + if (errorLogEntry != NULL) + { + switch (NewResourceType) + { + case CmResourceTypePort: + + errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT; + + break; + + case CmResourceTypeDma: + + errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT; + + break; + + case CmResourceTypeMemory: + + errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT; + + break; + + case CmResourceTypeInterrupt: + + errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT; + + break; + } + + // + // store the time + // + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + if (StringSize != 0) + { + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + MoveMemory(((PUCHAR)errorLogEntry) + sizeof(IO_ERROR_LOG_PACKET), + baseFileName, + logsize - (sizeof(IO_ERROR_LOG_PACKET) + 6)); + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET) + + StringSize; + } + else + { + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET); + + errorLogEntry->NumberOfStrings = 0; + } + + // + // write it out + // + IoWriteErrorLogEntry(errorLogEntry); + } + + return(NDIS_STATUS_RESOURCE_CONFLICT); + } + + return(NDIS_STATUS_FAILURE); + } + + return(NDIS_STATUS_SUCCESS); +} + +NDIS_STATUS +ndisRemoveResource( + OUT PCM_RESOURCE_LIST *pResources, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR DeadResource, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject, + IN PNDIS_STRING AdapterName + ) +/*++ + +Routine Description: + + this routine will walk the current resource list looking for the + dead resource. it will construct a new resource list without the + dead resource and report this new list to the system. + +Arguments: + + pResource - On entry this is the current resource list. + On exit this is the newly constructed resource list. + DriverObject - Driver object to report the resources for. + DeviceObject - Device object to report the resources for. + DeadResource - This is the resource to remove. + +Return Value: + + NDIS_STATUS_SUCCESS if the routine succeeded. + +--*/ +{ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Dst; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial; + PCM_RESOURCE_LIST CurrentList = *pResources; + PCM_RESOURCE_LIST Resources; + UINT c; + UINT Remaining; + BOOLEAN Conflict; + NDIS_STATUS Status; + BOOLEAN fFoundResource; + + // + // Sanity check! + // + if ((NULL == pResources) || (NULL == *pResources)) + { + return(NDIS_STATUS_FAILURE); + } + + // + // Allocate a new resource map. + // + Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL( + sizeof(CM_RESOURCE_LIST) + + (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (CurrentList->List->PartialResourceList.Count - 1)), + NDIS_TAG_RSRC_LIST); + if (NULL == Resources) + { + // + // Leave it there... + // + return(NDIS_STATUS_RESOURCES); + } + + // + // Copy the head information. + // + MoveMemory(Resources, CurrentList, sizeof(CM_RESOURCE_LIST)); + + Resources->List->PartialResourceList.Count--; + + // + // Get our destination pointer. + // + Dst = Resources->List->PartialResourceList.PartialDescriptors; + + // + // Find the resource in our resource list. + // + Partial = CurrentList->List->PartialResourceList.PartialDescriptors; + for (c = 0, fFoundResource = FALSE; + (c < CurrentList->List->PartialResourceList.Count) && !fFoundResource; + c++, Partial++) + { + // + // Is this the resource we are supposed to remove? + // + if (RtlEqualMemory( + Partial, + DeadResource, + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))) + { + // + // copy the remaining portion of the list. + // + fFoundResource = TRUE; + + // + // Copy any remaining resources into the list. + // + Remaining = CurrentList->List->PartialResourceList.Count - (c+1); + if (Remaining > 0) + { + MoveMemory(Dst, Partial+1, Remaining * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + } + } + else + { + // + // Copy this resource to our new list! + // + MoveMemory(Dst, Partial, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + Dst++; + } + + } + + // + // Did we find the resource? + // + if (!fFoundResource) + { + FREE_POOL(Resources); + return(NDIS_STATUS_FAILURE); + } + + // + // Free the old resource list and save the new one. + // + FREE_POOL(*pResources); + + *pResources = Resources; + + // + // Report the resources to the system. + // + Status = ndisReportResources( + Resources, + DriverObject, + DeviceObject, + AdapterName, + DeadResource->Type); + + return(Status); +} + + +NDIS_STATUS +ndisAddResource( + OUT PCM_RESOURCE_LIST *pResources, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR NewResource, + IN NDIS_INTERFACE_TYPE AdapterType, + IN ULONG BusNumber, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject, + IN PNDIS_STRING AdapterName + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + PCM_RESOURCE_LIST Resources; + UINT NumberOfElements; + BOOLEAN Conflict; + NDIS_STATUS Status; + + if (*pResources != NULL) + { + NumberOfElements = (*pResources)->List->PartialResourceList.Count; + } + else + { + NumberOfElements = 0; + } + + // + // Allocate room for the new list. Note that we don't have to add one + // to the NumberOfElements since a CM_RESOURCE_LIST already contains a + // single CM_PARTIAL_RESOURCE_DESCRIPTOR. + // + Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL( + sizeof(CM_RESOURCE_LIST) + + (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * NumberOfElements), + NDIS_TAG_RSRC_LIST); + if (NULL == Resources) + { + return(NDIS_STATUS_RESOURCES); + } + + if (*pResources != NULL) + { + // + // We need to subtract the size of a CM_PARTIAL_RESOURCE_DESCRIPTOR + // from the size of the CM_RESOURCE_LIST. + // + MoveMemory(Resources, + *pResources, + (sizeof(CM_RESOURCE_LIST) - + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)) + + (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (*pResources)->List->PartialResourceList.Count)); + } + else + { + // + // Setup initial resource information. + // + Resources->Count = 1; + Resources->List->InterfaceType = AdapterType; + Resources->List->BusNumber = BusNumber; + Resources->List->PartialResourceList.Version = 0; + Resources->List->PartialResourceList.Revision = 0; + Resources->List->PartialResourceList.Count = 0; + } + + // + // Add the new resource. + // + Resources->List->PartialResourceList.PartialDescriptors[Resources->List->PartialResourceList.Count] = *NewResource; + Resources->List->PartialResourceList.Count++; + + if (*pResources != NULL) + { + FREE_POOL(*pResources); + } + + *pResources = Resources; + + // + // Report the resources to the system. + // + Status = ndisReportResources( + Resources, + DriverObject, + DeviceObject, + AdapterName, + NewResource->Type); + + return(Status); +} + + + |