summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/ndis40/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/ndis40/common.c')
-rw-r--r--private/ntos/ndis/ndis40/common.c3452
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);
+}
+
+
+