/*++ 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 #pragma hdrstop #include // // 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); }