/*++ Copyright (c) 1990-1995 Microsoft Corporation Module Name: configm.c Abstract: NDIS wrapper functions for miniport configuration/initialization Author: Sean Selitrennikoff (SeanSe) 05-Oct-93 Jameel Hyder (JameelH) 01-Jun-95 Environment: Kernel mode, FSD Revision History: --*/ #include #pragma hdrstop // // Define the module number for debug code. // #define MODULE_NUMBER MODULE_CONFIGM NDIS_STATUS NdisMRegisterMiniport( IN NDIS_HANDLE NdisWrapperHandle, IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics, IN UINT CharacteristicsLength ) /*++ Routine Description: Used to register a Miniport driver with the wrapper. Arguments: Status - Status of the operation. NdisWrapperHandle - Handle returned by NdisWInitializeWrapper. MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table. CharacteristicsLength - The length of MiniportCharacteristics. Return Value: None. --*/ { NDIS_STATUS Status; PNDIS_M_DRIVER_BLOCK MiniBlock; DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("==>NdisMRegisterMiniport: NdisWrapperHandle %p\n", NdisWrapperHandle)); Status = ndisRegisterMiniportDriver(NdisWrapperHandle, MiniportCharacteristics, CharacteristicsLength, &MiniBlock); DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("NdisMRegisterMiniport: MiniBlock %p\n", MiniBlock)); ASSERT (CURRENT_IRQL < DISPATCH_LEVEL); DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("<==NdisMRegisterMiniport: MiniBlock %p, Status %lx\n", MiniBlock, Status)); return Status; } NDIS_STATUS NdisIMRegisterLayeredMiniport( IN NDIS_HANDLE NdisWrapperHandle, IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics, IN UINT CharacteristicsLength, OUT PNDIS_HANDLE DriverHandle ) /*++ Routine Description: Used to register a layered Miniport driver with the wrapper. Arguments: Status - Status of the operation. NdisWrapperHandle - Handle returned by NdisInitializeWrapper. MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table. CharacteristicsLength - The length of MiniportCharacteristics. DriverHandle - Returns a handle which can be used to call NdisMInitializeDeviceInstance. Return Value: None. --*/ { NDIS_STATUS Status; DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("==>NdisIMRegisterLayeredMiniport: NdisWrapperHandle %p\n", NdisWrapperHandle)); Status = ndisRegisterMiniportDriver(NdisWrapperHandle, MiniportCharacteristics, CharacteristicsLength, DriverHandle); if (Status == NDIS_STATUS_SUCCESS) { PNDIS_M_DRIVER_BLOCK MiniBlock = (PNDIS_M_DRIVER_BLOCK)(*DriverHandle); MiniBlock->Flags |= fMINIBLOCK_INTERMEDIATE_DRIVER; INITIALIZE_MUTEX(&MiniBlock->IMStartRemoveMutex); } DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("<==NdisIMRegisterLayeredMiniport: MiniBlock %p, Status %lx\n", *DriverHandle, Status)); return Status; } VOID NdisIMDeregisterLayeredMiniport( IN NDIS_HANDLE DriverHandle ) { // // Do nothing for now // } VOID NdisIMAssociateMiniport( IN NDIS_HANDLE DriverHandle, IN NDIS_HANDLE ProtocolHandle ) { PNDIS_M_DRIVER_BLOCK MiniDriver = (PNDIS_M_DRIVER_BLOCK)DriverHandle; PNDIS_PROTOCOL_BLOCK Protocol = (PNDIS_PROTOCOL_BLOCK)ProtocolHandle; MiniDriver->AssociatedProtocol = Protocol; Protocol->AssociatedMiniDriver = MiniDriver; } NDIS_STATUS ndisRegisterMiniportDriver( IN NDIS_HANDLE NdisWrapperHandle, IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics, IN UINT CharacteristicsLength, OUT PNDIS_HANDLE DriverHandle ) /*++ Routine Description: Used to register a layered Miniport driver with the wrapper. Arguments: Status - Status of the operation. NdisWrapperHandle - Handle returned by NdisWInitializeWrapper. MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table. CharacteristicsLength - The length of MiniportCharacteristics. DriverHandle - Returns a handle which can be used to call NdisMInitializeDeviceInstance. Return Value: None. --*/ { PNDIS_M_DRIVER_BLOCK MiniBlock; PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle; UNICODE_STRING Us; PWSTR pWch; USHORT i, size; NDIS_STATUS Status; KIRQL OldIrql; DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("==>ndisRegisterMiniportDriver: NdisWrapperHandle %p\n", NdisWrapperHandle)); do { if (DriverInfo == NULL) { Status = NDIS_STATUS_FAILURE; break; } // // Check version numbers and CharacteristicsLength. // size = 0; // Used to indicate bad version below if (MiniportCharacteristics->MinorNdisVersion == 0) { if (MiniportCharacteristics->MajorNdisVersion == 3) { size = sizeof(NDIS30_MINIPORT_CHARACTERISTICS); } else if (MiniportCharacteristics->MajorNdisVersion == 4) { size = sizeof(NDIS40_MINIPORT_CHARACTERISTICS); } else if (MiniportCharacteristics->MajorNdisVersion == 5) { size = sizeof(NDIS50_MINIPORT_CHARACTERISTICS); } } else if (MiniportCharacteristics->MinorNdisVersion == 1) { if (MiniportCharacteristics->MajorNdisVersion == 5) { size = sizeof(NDIS51_MINIPORT_CHARACTERISTICS); } } // // Check that this is an NDIS 3.0/4.0/5.0 miniport. // if (size == 0) { Status = NDIS_STATUS_BAD_VERSION; break; } // // Check that CharacteristicsLength is enough. // if (CharacteristicsLength < size) { Status = NDIS_STATUS_BAD_CHARACTERISTICS; break; } // // Validate some stuff for NDIS 5.0 // if (MiniportCharacteristics->MajorNdisVersion == 5) { if (MiniportCharacteristics->CoSendPacketsHandler != NULL) { if (MiniportCharacteristics->CoRequestHandler == NULL) { Status = NDIS_STATUS_BAD_CHARACTERISTICS; break; } } if (MiniportCharacteristics->MinorNdisVersion >= 1) { // // for 5.1 miniports, having an AdapterShutdownHandler is mandatory // if (MiniportCharacteristics->AdapterShutdownHandler == NULL) { Status = NDIS_STATUS_BAD_CHARACTERISTICS; break; } } } // // Allocate memory for the NDIS MINIPORT block. // Status = IoAllocateDriverObjectExtension(DriverInfo->DriverObject, // DriverObject (PVOID)NDIS_PNP_MINIPORT_DRIVER_ID,// MiniDriver magic number sizeof(NDIS_M_DRIVER_BLOCK), (PVOID)&MiniBlock); if (!NT_SUCCESS(Status)) { Status = NDIS_STATUS_RESOURCES; break; } ZeroMemory(MiniBlock, sizeof(NDIS_M_DRIVER_BLOCK)); // // Copy over the characteristics table. // CopyMemory(&MiniBlock->MiniportCharacteristics, MiniportCharacteristics, size); // // Check if the Driver is verifying // if (MmIsDriverVerifying(DriverInfo->DriverObject)) { MiniBlock->Flags |= fMINIBLOCK_VERIFYING; if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION) { if (ndisDriverTrackAlloc == NULL) { ndisDriverTrackAlloc = MiniBlock; } else { // // tracking memory alocation is allowed // for one driver only. otherwise null out the // global ndisDriverTrackAlloc to avoid confusion // memory allocations will continue to get tracked // but the result will not be very useful // ndisDriverTrackAlloc = NULL; } } } // // No adapters yet registered for this Miniport. // MiniBlock->MiniportQueue = (PNDIS_MINIPORT_BLOCK)NULL; // // Set up the handlers for this driver. First setup Dummy handlers and then specific ones // for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverInfo->DriverObject->MajorFunction[i] = ndisDummyIrpHandler; } // // set up AddDevice handler for this miniport // DriverInfo->DriverObject->DriverExtension->AddDevice = ndisPnPAddDevice; // // Set up unload handler // DriverInfo->DriverObject->DriverUnload = ndisMUnload; DriverInfo->DriverObject->MajorFunction[IRP_MJ_CREATE] = ndisCreateIrpHandler; DriverInfo->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ndisDeviceControlIrpHandler; DriverInfo->DriverObject->MajorFunction[IRP_MJ_CLOSE] = ndisCloseIrpHandler; // // setup a handler for PnP messages // DriverInfo->DriverObject->MajorFunction[IRP_MJ_PNP] = ndisPnPDispatch; DriverInfo->DriverObject->MajorFunction[IRP_MJ_POWER] = ndisPowerDispatch; DriverInfo->DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ndisWMIDispatch; // // Use this event to tell us when all adapters are removed from the mac // during an unload // INITIALIZE_EVENT(&MiniBlock->MiniportsRemovedEvent); // let the initial state stay reset, because the ref count // going to zero is going to signal the event MiniBlock->NdisDriverInfo = DriverInfo; InitializeListHead(&MiniBlock->DeviceList); ndisInitializeRef(&MiniBlock->Ref); // // Put Driver on global list. // PnPReferencePackage(); ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql); MiniBlock->NextDriver = ndisMiniDriverList; ndisMiniDriverList = MiniBlock; REF_NDIS_DRIVER_OBJECT(); RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql); PnPDereferencePackage(); *DriverHandle = MiniBlock; Status = NDIS_STATUS_SUCCESS; } while (FALSE); DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("<==ndisRegisterMiniportDriver: MiniBlock %p\n", MiniBlock)); return Status; } NDIS_STATUS NdisMRegisterDevice( IN NDIS_HANDLE NdisWrapperHandle, IN PNDIS_STRING DeviceName, IN PNDIS_STRING SymbolicName, IN PDRIVER_DISPATCH * MajorFunctions, OUT PDEVICE_OBJECT * pDeviceObject, OUT NDIS_HANDLE * NdisDeviceHandle ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PDRIVER_OBJECT DriverObject; PDEVICE_OBJECT DeviceObject; PNDIS_M_DRIVER_BLOCK MiniBlock; PNDIS_MINIPORT_BLOCK Miniport; PNDIS_DEVICE_LIST DeviceList = NULL; KIRQL OldIrql; *pDeviceObject = NULL; *NdisDeviceHandle = NULL; // // Check if the passed parameter is a NdisWrapperHandle or NdisMiniportHandle // if (DriverInfo->DriverObject == NULL) { Miniport = (PNDIS_MINIPORT_BLOCK)NdisWrapperHandle; MiniBlock = Miniport->DriverHandle; } else { MiniBlock = (PNDIS_M_DRIVER_BLOCK)IoGetDriverObjectExtension(DriverInfo->DriverObject, (PVOID)NDIS_PNP_MINIPORT_DRIVER_ID); } if (MiniBlock != NULL) { DriverObject = MiniBlock->NdisDriverInfo->DriverObject; Status = IoCreateDevice(DriverObject, // DriverObject sizeof(NDIS_WRAPPER_CONTEXT) + sizeof(NDIS_DEVICE_LIST) + // DeviceExtension DeviceName->Length + sizeof(WCHAR) + SymbolicName->Length + sizeof(WCHAR), DeviceName, // DeviceName FILE_DEVICE_NETWORK, // DeviceType FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics FALSE, // Exclusive &DeviceObject); // DeviceObject if (NT_SUCCESS(Status)) { DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; Status = IoCreateSymbolicLink(SymbolicName, DeviceName); if (!NT_SUCCESS(Status)) { IoDeleteDevice(DeviceObject); } else { DeviceList = (PNDIS_DEVICE_LIST)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); RtlZeroMemory(DeviceList, sizeof(NDIS_DEVICE_LIST) + DeviceName->Length + sizeof(WCHAR) + SymbolicName->Length + sizeof(WCHAR)); DeviceList->Signature = (PVOID)CUSTOM_DEVICE_MAGIC_VALUE; InitializeListHead(&DeviceList->List); DeviceList->MiniBlock = MiniBlock; DeviceList->DeviceObject = DeviceObject; RtlCopyMemory(DeviceList->MajorFunctions, MajorFunctions, (IRP_MJ_MAXIMUM_FUNCTION+1)*sizeof(PDRIVER_DISPATCH)); DeviceList->DeviceName.Buffer = (PWCHAR)(DeviceList + 1); DeviceList->DeviceName.Length = DeviceName->Length; DeviceList->DeviceName.MaximumLength = DeviceName->Length + sizeof(WCHAR); RtlCopyMemory(DeviceList->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length); DeviceList->SymbolicLinkName.Buffer = (PWCHAR)((PUCHAR)DeviceList->DeviceName.Buffer + DeviceList->DeviceName.MaximumLength); DeviceList->SymbolicLinkName.Length = SymbolicName->Length; DeviceList->SymbolicLinkName.MaximumLength = SymbolicName->Length + sizeof(WCHAR); RtlCopyMemory(DeviceList->SymbolicLinkName.Buffer, SymbolicName->Buffer, SymbolicName->Length); PnPReferencePackage(); ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql); InsertHeadList(&MiniBlock->DeviceList, &DeviceList->List); RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql); PnPDereferencePackage(); *pDeviceObject = DeviceObject; *NdisDeviceHandle = DeviceList; } } } else { Status = NDIS_STATUS_NOT_SUPPORTED; } return Status; } NDIS_STATUS NdisMDeregisterDevice( IN NDIS_HANDLE NdisDeviceHandle ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_DEVICE_LIST DeviceList = (PNDIS_DEVICE_LIST)NdisDeviceHandle; PNDIS_M_DRIVER_BLOCK MiniBlock; KIRQL OldIrql; MiniBlock = DeviceList->MiniBlock; PnPReferencePackage(); ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql); RemoveEntryList(&DeviceList->List); RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql); PnPDereferencePackage(); IoDeleteSymbolicLink(&DeviceList->SymbolicLinkName); IoDeleteDevice(DeviceList->DeviceObject); return NDIS_STATUS_SUCCESS; } VOID NdisMRegisterUnloadHandler( IN NDIS_HANDLE NdisWrapperHandle, IN PDRIVER_UNLOAD UnloadHandler ) { PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle; PNDIS_M_DRIVER_BLOCK MiniBlock; if (DriverInfo->DriverObject == NULL) { MiniBlock = (PNDIS_M_DRIVER_BLOCK)NdisWrapperHandle; } else { MiniBlock = (PNDIS_M_DRIVER_BLOCK)IoGetDriverObjectExtension(DriverInfo->DriverObject, (PVOID)NDIS_PNP_MINIPORT_DRIVER_ID); } if (MiniBlock != NULL) { MiniBlock->UnloadHandler = UnloadHandler; } } NDIS_STATUS NdisIMDeInitializeDeviceInstance( IN NDIS_HANDLE NdisMiniportHandle ) /*++ Routine Description: Arguments: Return Value: --*/ { PNDIS_MINIPORT_BLOCK Miniport; PNDIS_M_DRIVER_BLOCK MiniBlock; NDIS_STATUS Status = NDIS_STATUS_FAILURE; DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("==>NdisIMDeInitializeDeviceInstance: Miniport %p\n", NdisMiniportHandle)); ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL); Miniport = (PNDIS_MINIPORT_BLOCK)NdisMiniportHandle; MiniBlock = Miniport->DriverHandle; if (MINIPORT_INCREMENT_REF(Miniport)) { ndisReferenceDriver(MiniBlock); // // for all practical purposes we want the same thing happens as in // stopping the device, i.e. device objects remain and some certain fields that // get initialized during AddDevice to be preserved. // Miniport->PnPDeviceState = NdisPnPDeviceStopped; ndisPnPRemoveDevice(Miniport->DeviceObject, NULL); Miniport->CurrentDevicePowerState = PowerDeviceUnspecified; MINIPORT_DECREMENT_REF(Miniport); ndisDereferenceDriver(MiniBlock, FALSE); Status = NDIS_STATUS_SUCCESS; } DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("<==NdisIMDeInitializeDeviceInstance: Miniport %p, Status %lx\n", NdisMiniportHandle, Status)); return Status; } VOID ndisMFinishQueuedPendingOpen( IN PNDIS_POST_OPEN_PROCESSING PostOpen ) /*++ Routine Description: Handles any pending NdisOpenAdapter() calls for miniports. Arguments: PostOpen: a tempoary structure to carry the open information around Return Value: Returns the status code of the open. --*/ { PNDIS_OPEN_BLOCK Open = PostOpen->Open; PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle; PNDIS_AF_NOTIFY AfNotify = NULL; NDIS_STATUS Status; UINT OpenRef; KIRQL OldIrql; DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO, ("==>ndisMFinishQueuedPendingOpen: PostOpen %p\n", PostOpen)); PnPReferencePackage(); NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); // // If this is a binding that involves registration/open of address families, notify // ASSERT (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO) && (Open->ProtocolHandle->ProtocolCharacteristics.CoAfRegisterNotifyHandler != NULL)); Status = ndisCreateNotifyQueue(Miniport, Open, NULL, &AfNotify); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); if (AfNotify != NULL) { // // Notify existing clients of this registration // ndisNotifyAfRegistration(AfNotify); } FREE_POOL(PostOpen); ndisDereferenceAfNotification(Open); NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); ndisMDereferenceOpen(Open); NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); PnPDereferencePackage(); DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO, ("<==ndisMFinishQueuedPendingOpen: Open %p\n", Open)); } NDIS_STATUS NdisMRegisterIoPortRange( OUT PVOID * PortOffset, IN NDIS_HANDLE MiniportAdapterHandle, IN UINT InitialPort, IN UINT NumberOfPorts ) /*++ Routine Description: Sets up an IO port for operations. Arguments: PortOffset - The mapped port address the Miniport uses for NdisRaw functions. MiniportAdapterHandle - Handle passed to Miniport Initialize. InitialPort - Physical address of the starting port number. NumberOfPorts - Number of ports to map. Return Value: None. --*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle); PHYSICAL_ADDRESS PortAddress; PHYSICAL_ADDRESS InitialPortAddress; ULONG addressSpace; NDIS_STATUS Status; PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDescriptor = NULL; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMRegisterIoPortRange: Miniport %p\n", Miniport)); // Miniport->InfoFlags |= NDIS_MINIPORT_USES_IO; do { if (MINIPORT_VERIFY_TEST_FLAG(Miniport, fMINIPORT_VERIFY_FAIL_REGISTER_IO)) { #if DBG DbgPrint("NdisMRegisterIoPortRange failed to verify miniport %p\n", Miniport); #endif Status = NDIS_STATUS_RESOURCES; break; } InitialPortAddress.QuadPart = InitialPort; #if !defined(_M_IX86) Status = ndisTranslateResources(Miniport, CmResourceTypePort, InitialPortAddress, &PortAddress, &pResourceDescriptor); if (Status != NDIS_STATUS_SUCCESS) { Status = NDIS_STATUS_FAILURE; break; } if (pResourceDescriptor->Type == CmResourceTypeMemory) addressSpace = 0; else addressSpace = -1; if (addressSpace == 0) { // // memory space // *(PortOffset) = (PULONG)MmMapIoSpace(PortAddress, NumberOfPorts, FALSE); if (*(PortOffset) == (PULONG)NULL) { Status = NDIS_STATUS_RESOURCES; break; } } else { // // I/O space // *(PortOffset) = ULongToPtr(PortAddress.LowPart); } #else // x86 platform // // make sure the port belongs to the device // Status = ndisTranslateResources(Miniport, CmResourceTypePort, InitialPortAddress, &PortAddress, &pResourceDescriptor); if (Status != NDIS_STATUS_SUCCESS) { Status = NDIS_STATUS_FAILURE; break; } if (pResourceDescriptor->Type == CmResourceTypeMemory) { // // memory space // *(PortOffset) = (PULONG)MmMapIoSpace(PortAddress, NumberOfPorts, FALSE); if (*(PortOffset) == (PULONG)NULL) { Status = NDIS_STATUS_RESOURCES; break; } } else { // // I/O space // *(PortOffset) = (PULONG)PortAddress.LowPart; } #endif Status = NDIS_STATUS_SUCCESS; } while (FALSE); DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMRegisterIoPortRange: Miniport %p, Status %lx\n", Miniport, Status)); return Status; } VOID NdisMDeregisterIoPortRange( IN NDIS_HANDLE MiniportAdapterHandle, IN UINT InitialPort, IN UINT NumberOfPorts, IN PVOID PortOffset ) /*++ Routine Description: Sets up an IO port for operations. Arguments: MiniportAdapterHandle - Handle passed to Miniport Initialize. InitialPort - Physical address of the starting port number. NumberOfPorts - Number of ports to map. PortOffset - The mapped port address the Miniport uses for NdisRaw functions. Return Value: None. --*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle); PHYSICAL_ADDRESS PortAddress; PHYSICAL_ADDRESS InitialPortAddress; ULONG addressSpace; CM_PARTIAL_RESOURCE_DESCRIPTOR Resource; NDIS_STATUS Status; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMDeregisterIoPortRange: Miniport %p\n", Miniport)); DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMDeregisterIoPortRange: Miniport %p\n", Miniport)); return; } NDIS_STATUS NdisMMapIoSpace( OUT PVOID * VirtualAddress, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, IN UINT Length ) { NDIS_STATUS Status; ULONG addressSpace = 0; PHYSICAL_ADDRESS PhysicalTemp; PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle); PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDescriptor = NULL; DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("==>NdisMMapIoSpace\n")); // Miniport->InfoFlags |= NDIS_MINIPORT_USES_MEMORY; if (MINIPORT_VERIFY_TEST_FLAG(Miniport, fMINIPORT_VERIFY_FAIL_MAP_IO_SPACE)) { #if DBG DbgPrint("NdisMMapIoSpace failed to verify miniport %p\n", Miniport); #endif *VirtualAddress = NULL; return NDIS_STATUS_RESOURCES; } do { #if !defined(_M_IX86) PhysicalTemp.HighPart = 0; Status = ndisTranslateResources(Miniport, CmResourceTypeMemory, PhysicalAddress, &PhysicalTemp, &pResourceDescriptor); if (Status != NDIS_STATUS_SUCCESS) { Status = NDIS_STATUS_FAILURE; break; } if (pResourceDescriptor->Type == CmResourceTypeMemory) addressSpace = 0; else addressSpace = -1; #else addressSpace = 0; // need to do MmMapIoSpace Status = ndisTranslateResources(Miniport, CmResourceTypeMemory, PhysicalAddress, &PhysicalTemp, &pResourceDescriptor); if (Status != NDIS_STATUS_SUCCESS) { Status = NDIS_STATUS_FAILURE; break; } #endif if (addressSpace == 0) { *VirtualAddress = MmMapIoSpace(PhysicalTemp, (Length), FALSE); } else { *VirtualAddress = ULongToPtr(PhysicalTemp.LowPart); } Status = NDIS_STATUS_SUCCESS; if (*VirtualAddress == NULL) { Status = NDIS_STATUS_RESOURCES; } } while (FALSE); DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMMapIoSpace: Miniport %p, Status %lx\n", MiniportAdapterHandle, Status)); return Status; } VOID NdisMUnmapIoSpace( IN NDIS_HANDLE MiniportAdapterHandle, IN PVOID VirtualAddress, IN UINT Length ) { DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMUnmapIoSpace: Miniport %p\n", MiniportAdapterHandle)); #ifndef _ALPHA_ MmUnmapIoSpace(VirtualAddress, Length); #endif DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMUnmapIoSpace: Miniport %p\n", MiniportAdapterHandle)); } VOID NdisMAllocateSharedMemory( IN NDIS_HANDLE MiniportAdapterHandle, IN ULONG Length, IN BOOLEAN Cached, OUT PVOID * VirtualAddress, OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; PDMA_ADAPTER SystemAdapterObject; PNDIS_WRAPPER_CONTEXT WrapperContext; PULONG Page; ULONG Type; PNDIS_SHARED_MEM_SIGNATURE pSharedMemSignature = NULL; // Miniport->InfoFlags |= NDIS_MINIPORT_USES_SHARED_MEMORY; SystemAdapterObject = Miniport->SystemAdapterObject; WrapperContext = Miniport->WrapperContext; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMAllocateSharedMemory: Miniport %p, Length %lx\n", Miniport, Length)); PhysicalAddress->HighPart = PhysicalAddress->LowPart = 0; if (MINIPORT_VERIFY_TEST_FLAG(Miniport, fMINIPORT_VERIFY_FAIL_SHARED_MEM_ALLOC)) { #if DBG DbgPrint("NdisMAllocateSharedMemory failed to verify miniport %p\n", Miniport); #endif *VirtualAddress = NULL; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMAllocateSharedMemory: Miniport %p, Length %lx\n", Miniport, Length)); return; } if (Miniport->SystemAdapterObject == NULL) { *VirtualAddress = NULL; return; } if (CURRENT_IRQL >= DISPATCH_LEVEL) { BAD_MINIPORT(Miniport, "Allocating Shared Memory at raised IRQL"); KeBugCheckEx(BUGCODE_ID_DRIVER, (ULONG_PTR)Miniport, Length, 0, 1); } // // 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; ExAcquireResourceExclusiveLite(&SharedMemoryResource, TRUE); do { PALLOCATE_COMMON_BUFFER allocateCommonBuffer; allocateCommonBuffer = *SystemAdapterObject->DmaOperations->AllocateCommonBuffer; if (WrapperContext->SharedMemoryLeft[Type] < Length) { if ((Length + sizeof(NDIS_SHARED_MEM_SIGNATURE)) >= PAGE_SIZE) { // // The allocation is greater than a page. // *VirtualAddress = allocateCommonBuffer(SystemAdapterObject, Length, PhysicalAddress, Cached); break; } // // Allocate a new page for shared alocation. // WrapperContext->SharedMemoryPage[Type] = allocateCommonBuffer(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. // Initialize the Tag in the second last ulong of the page // Page = (PULONG)WrapperContext->SharedMemoryPage[Type]; pSharedMemSignature = (PNDIS_SHARED_MEM_SIGNATURE) ((PUCHAR)Page+ (PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE))); pSharedMemSignature->Tag = NDIS_TAG_SHARED_MEMORY; pSharedMemSignature->PageRef = 0; WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE); } // // Increment the reference count, set the address of the allocation, // compute the physical address, and reduce the space remaining. // Page = (PULONG)WrapperContext->SharedMemoryPage[Type]; // // First check whether Page is pointing to shared memory. Bugcheck to catch the driver // pSharedMemSignature = (PNDIS_SHARED_MEM_SIGNATURE) ((PUCHAR)Page+ (PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE))); if (pSharedMemSignature->Tag != NDIS_TAG_SHARED_MEMORY) { ASSERT (pSharedMemSignature->Tag == NDIS_TAG_SHARED_MEMORY); BAD_MINIPORT(Miniport, "Overwrote past allocated shared memory"); KeBugCheckEx(BUGCODE_ID_DRIVER, (ULONG_PTR)Miniport, (ULONG_PTR)Page, (ULONG_PTR)WrapperContext, (ULONG_PTR)pSharedMemSignature); } pSharedMemSignature->PageRef += 1; *VirtualAddress = (PVOID)((PUCHAR)Page + (PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE) - WrapperContext->SharedMemoryLeft[Type])); PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart + ((ULONG_PTR)(*VirtualAddress) & (PAGE_SIZE - 1)); WrapperContext->SharedMemoryLeft[Type] -= Length; } while (FALSE); if (*VirtualAddress) { InterlockedIncrement(&Miniport->DmaAdapterRefCount); } ExReleaseResourceLite(&SharedMemoryResource); #if DBG if (*VirtualAddress == NULL) { DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_ERR, ("NdisMAllocateSharedMemory: Miniport %p, allocateCommonBuffer failed for %lx bytes\n", Miniport, Length)); } #endif if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_64BITS_DMA) && (PhysicalAddress->HighPart > 0)) { #if DBG DbgPrint("NdisMAllocateSharedMemory: Miniport %p, allocateCommonBuffer returned a physical address > 4G for a" " non-64bit DMA adapter. PhysAddress->HighPart = %p", Miniport, PhysicalAddress->HighPart); #endif ASSERT(PhysicalAddress->HighPart == 0); } DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMAllocateSharedMemory: Miniport %p, Length %lx, Virtual Address %p\n", Miniport, Length, *VirtualAddress)); } NDIS_STATUS NdisMAllocateSharedMemoryAsync( IN NDIS_HANDLE MiniportAdapterHandle, IN ULONG Length, IN BOOLEAN Cached, IN PVOID Context ) { // // Convert the handle to our internal structure. // PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle; PASYNC_WORKITEM pWorkItem = NULL; // Miniport->InfoFlags |= NDIS_MINIPORT_USES_SHARED_MEMORY; // Allocate a workitem if ((Miniport->SystemAdapterObject != NULL) && (Miniport->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler != NULL)) { pWorkItem = ALLOC_FROM_POOL(sizeof(ASYNC_WORKITEM), NDIS_TAG_ALLOC_SHARED_MEM_ASYNC); } if ((pWorkItem == NULL) || !MINIPORT_INCREMENT_REF(Miniport)) { if (pWorkItem != NULL) FREE_POOL(pWorkItem); return NDIS_STATUS_FAILURE; } InterlockedIncrement(&Miniport->DmaAdapterRefCount); // Initialize the workitem and queue it up to a worker thread pWorkItem->Miniport = Miniport; pWorkItem->Length = Length; pWorkItem->Cached = Cached; pWorkItem->Context = Context; INITIALIZE_WORK_ITEM(&pWorkItem->ExWorkItem, ndisMQueuedAllocateSharedHandler, pWorkItem); QUEUE_WORK_ITEM(&pWorkItem->ExWorkItem, CriticalWorkQueue); return NDIS_STATUS_PENDING; } VOID ndisMQueuedAllocateSharedHandler( IN PASYNC_WORKITEM pWorkItem ) { KIRQL OldIrql; // Allocate the memory NdisMAllocateSharedMemory(pWorkItem->Miniport, pWorkItem->Length, pWorkItem->Cached, &pWorkItem->VAddr, &pWorkItem->PhyAddr); // // we shouldn't need to reference package here // ASSERT(ndisPkgs[NDSM_PKG].ReferenceCount > 0); if (MINIPORT_TEST_FLAG(pWorkItem->Miniport, fMINIPORT_DESERIALIZE)) { KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); } else { NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(pWorkItem->Miniport, &OldIrql); } // Call the miniport back (*pWorkItem->Miniport->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler)( pWorkItem->Miniport->MiniportAdapterContext, pWorkItem->VAddr, &pWorkItem->PhyAddr, pWorkItem->Length, pWorkItem->Context); if (MINIPORT_TEST_FLAG(pWorkItem->Miniport, fMINIPORT_DESERIALIZE)) { KeLowerIrql(OldIrql); } else { NDIS_RELEASE_MINIPORT_SPIN_LOCK(pWorkItem->Miniport, OldIrql); } ndisDereferenceDmaAdapter(pWorkItem->Miniport); // Dereference the miniport MINIPORT_DECREMENT_REF(pWorkItem->Miniport); // And finally free the work-item FREE_POOL(pWorkItem); } VOID ndisFreeSharedMemory( IN NDIS_HANDLE MiniportAdapterHandle, IN ULONG Length, IN BOOLEAN Cached, IN PVOID VirtualAddress, IN NDIS_PHYSICAL_ADDRESS PhysicalAddress ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; PDMA_ADAPTER SystemAdapterObject; PNDIS_WRAPPER_CONTEXT WrapperContext; PULONG Page; ULONG Type; PNDIS_SHARED_MEM_SIGNATURE pSharedMemSignature = NULL; PFREE_COMMON_BUFFER freeCommonBuffer; // // Get interesting information from the miniport. // SystemAdapterObject = Miniport->SystemAdapterObject; WrapperContext = Miniport->WrapperContext; if (SystemAdapterObject == NULL) { if (Miniport->SavedSystemAdapterObject) SystemAdapterObject = Miniport->SavedSystemAdapterObject; // // Non-busmasters shouldn't call this routine. // ASSERT(SystemAdapterObject != NULL); #if DBG DbgPrint("Ndis: WARNING... Miniport %p freeing shared memory -after- freeing map registers.\n", Miniport); if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_VERIFYING) && (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING)) DbgBreakPoint(); #endif Miniport->SystemAdapterObject = Miniport->SavedSystemAdapterObject; } freeCommonBuffer = *SystemAdapterObject->DmaOperations->FreeCommonBuffer; // // Compute allocation size by aligning to the proper boundary. // ASSERT(Length != 0); Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 1); // // Free the specified memory. // ExAcquireResourceExclusiveLite(&SharedMemoryResource, TRUE); if ((Length + sizeof(NDIS_SHARED_MEM_SIGNATURE)) >= PAGE_SIZE) { // // The allocation is greater than a page free the page directly. // freeCommonBuffer(SystemAdapterObject, Length, PhysicalAddress, VirtualAddress, Cached); } else { // // Decrement the reference count and if the result is zero, then free // the page. // Page = (PULONG)((ULONG_PTR)VirtualAddress & ~(PAGE_SIZE - 1)); // // First check whether Page is pointing to shared memory. Bugcheck to catch the driver // pSharedMemSignature = (PNDIS_SHARED_MEM_SIGNATURE) ((PUCHAR)Page + (PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE))); if (pSharedMemSignature->Tag != NDIS_TAG_SHARED_MEMORY) { ASSERT (pSharedMemSignature->Tag == NDIS_TAG_SHARED_MEMORY); BAD_MINIPORT(Miniport, "Freeing shared memory not allocated"); KeBugCheckEx(BUGCODE_ID_DRIVER, (ULONG_PTR)Miniport, (ULONG_PTR)Page, (ULONG_PTR)pSharedMemSignature, (ULONG_PTR)VirtualAddress ); } pSharedMemSignature->PageRef -= 1; // // If the references on the page have gone to zero then free the page // if (pSharedMemSignature->PageRef == 0) { // // Compute the physical address of the page and free it. // PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1); freeCommonBuffer(SystemAdapterObject, PAGE_SIZE, PhysicalAddress, Page, Cached); Type = Cached ? 1 : 0; if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type]) { WrapperContext->SharedMemoryLeft[Type] = 0; WrapperContext->SharedMemoryPage[Type] = NULL; } } } ndisDereferenceDmaAdapter(Miniport); ExReleaseResourceLite(&SharedMemoryResource); } VOID NdisMFreeSharedMemory( IN NDIS_HANDLE MiniportAdapterHandle, IN ULONG Length, IN BOOLEAN Cached, IN PVOID VirtualAddress, IN NDIS_PHYSICAL_ADDRESS PhysicalAddress ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; if (CURRENT_IRQL < DISPATCH_LEVEL) { ndisFreeSharedMemory(MiniportAdapterHandle, Length, Cached, VirtualAddress, PhysicalAddress); } else if (MINIPORT_INCREMENT_REF(Miniport)) { PASYNC_WORKITEM pWorkItem = NULL; // Allocate a work-item and queue it up to a worker thread pWorkItem = ALLOC_FROM_POOL(sizeof(ASYNC_WORKITEM), NDIS_TAG_FREE_SHARED_MEM_ASYNC); if (pWorkItem != NULL) { // Initialize the workitem and queue it up to a worker thread pWorkItem->Miniport = Miniport; pWorkItem->Length = Length; pWorkItem->Cached = Cached; pWorkItem->VAddr = VirtualAddress; pWorkItem->PhyAddr = PhysicalAddress; INITIALIZE_WORK_ITEM(&pWorkItem->ExWorkItem, ndisMQueuedFreeSharedHandler, pWorkItem); QUEUE_WORK_ITEM(&pWorkItem->ExWorkItem, CriticalWorkQueue); } // What do we do now ? } } VOID ndisMQueuedFreeSharedHandler( IN PASYNC_WORKITEM pWorkItem ) { // Free the memory ndisFreeSharedMemory(pWorkItem->Miniport, pWorkItem->Length, pWorkItem->Cached, pWorkItem->VAddr, pWorkItem->PhyAddr); // Dereference the miniport MINIPORT_DECREMENT_REF(pWorkItem->Miniport); // And finally free the work-item FREE_POOL(pWorkItem); } NDIS_STATUS NdisMRegisterDmaChannel( OUT PNDIS_HANDLE MiniportDmaHandle, IN NDIS_HANDLE MiniportAdapterHandle, IN UINT DmaChannel, IN BOOLEAN Dma32BitAddresses, IN PNDIS_DMA_DESCRIPTION DmaDescription, IN ULONG MaximumLength ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle); NDIS_STATUS Status; NDIS_INTERFACE_TYPE BusType; ULONG BusNumber; DEVICE_DESCRIPTION DeviceDescription; PDMA_ADAPTER AdapterObject; ULONG MapRegistersNeeded; ULONG MapRegistersAllowed; PNDIS_DMA_BLOCK DmaBlock; KIRQL OldIrql; NTSTATUS NtStatus; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMRegisterDmaChannel: Miniport %p\n", Miniport)); BusType = Miniport->BusType; BusNumber = Miniport->BusNumber; do { // // Set up the device description; zero it out in case its // size changes. // ZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; DeviceDescription.Master = MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER); DeviceDescription.ScatterGather = MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER); DeviceDescription.DemandMode = DmaDescription->DemandMode; DeviceDescription.AutoInitialize = DmaDescription->AutoInitialize; DeviceDescription.Dma32BitAddresses = Dma32BitAddresses; DeviceDescription.BusNumber = Miniport->BusNumber; DeviceDescription.DmaChannel = DmaChannel; DeviceDescription.InterfaceType = BusType; DeviceDescription.DmaWidth = DmaDescription->DmaWidth; DeviceDescription.DmaSpeed = DmaDescription->DmaSpeed; DeviceDescription.MaximumLength = MaximumLength; DeviceDescription.DmaPort = DmaDescription->DmaPort; MapRegistersNeeded = ((MaximumLength - 2) / PAGE_SIZE) + 2; // // Get the adapter object. // AdapterObject = IoGetDmaAdapter(Miniport->PhysicalDeviceObject, &DeviceDescription, &MapRegistersAllowed); if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersNeeded)) { Status = NDIS_STATUS_RESOURCES; break; } // // Allocate storage for our DMA block. // DmaBlock = (PNDIS_DMA_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_DMA_BLOCK), NDIS_TAG_DMA); if (DmaBlock == (PNDIS_DMA_BLOCK)NULL) { Status = NDIS_STATUS_RESOURCES; break; } // // Use this event to tell us when ndisAllocationExecutionRoutine // has been called. // INITIALIZE_EVENT(&DmaBlock->AllocationEvent); // // We save this to call IoFreeAdapterChannel later. // (PDMA_ADAPTER)DmaBlock->SystemAdapterObject = AdapterObject; ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0); PnPReferencePackage(); // // Now allocate the adapter channel. // RAISE_IRQL_TO_DISPATCH(&OldIrql); NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel(AdapterObject, Miniport->DeviceObject, MapRegistersNeeded, ndisDmaExecutionRoutine, (PVOID)DmaBlock); LOWER_IRQL(OldIrql, DISPATCH_LEVEL); PnPDereferencePackage(); if (!NT_SUCCESS(NtStatus)) { DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_ERR, ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus)); FREE_POOL(DmaBlock); Status = NDIS_STATUS_RESOURCES; break; } // // ndisDmaExecutionRoutine will set this event // when it has been called. // NtStatus = WAIT_FOR_OBJECT(&DmaBlock->AllocationEvent, 0); if (!NT_SUCCESS(NtStatus)) { DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_ERR, ("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus)); FREE_POOL(DmaBlock); Status = NDIS_STATUS_RESOURCES; break; } RESET_EVENT(&DmaBlock->AllocationEvent); // // We now have the DMA channel allocated, we are done. // DmaBlock->InProgress = FALSE; *MiniportDmaHandle = (NDIS_HANDLE)DmaBlock; Status = NDIS_STATUS_SUCCESS; } while (FALSE); DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMRegisterDmaChannel: Miniport %p, Status %lx\n", Miniport, Status)); return Status; } VOID NdisMDeregisterDmaChannel( IN NDIS_HANDLE MiniportDmaHandle ) { KIRQL OldIrql; PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)MiniportDmaHandle; PPUT_DMA_ADAPTER putDmaAdapter; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMDeregisterDmaChannel\n")); ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0); PnPReferencePackage(); RAISE_IRQL_TO_DISPATCH(&OldIrql); ((PDMA_ADAPTER)DmaBlock->SystemAdapterObject)->DmaOperations->FreeAdapterChannel(DmaBlock->SystemAdapterObject); LOWER_IRQL(OldIrql, DISPATCH_LEVEL); putDmaAdapter = ((PDMA_ADAPTER)DmaBlock->SystemAdapterObject)->DmaOperations->PutDmaAdapter; putDmaAdapter((PDMA_ADAPTER)DmaBlock->SystemAdapterObject); PnPDereferencePackage(); FREE_POOL(DmaBlock); DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMDeregisterDmaChannel\n")); } NDIS_STATUS NdisMAllocateMapRegisters( IN NDIS_HANDLE MiniportAdapterHandle, IN UINT DmaChannel, IN NDIS_DMA_SIZE DmaSize, IN ULONG BaseMapRegistersNeeded, IN ULONG MaximumPhysicalMapping ) /*++ Routine Description: Allocates map registers for bus mastering devices. Arguments: MiniportAdapterHandle - Handle passed to MiniportInitialize. BaseMapRegistersNeeded - The maximum number of base map registers needed by the Miniport at any one time. MaximumPhysicalMapping - Maximum length of a buffer that will have to be mapped. Return Value: None. --*/ { // // Convert the handle to our internal structure. // PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle; // // This is needed by HalGetAdapter. // DEVICE_DESCRIPTION DeviceDescription; // // Returned by HalGetAdapter. // ULONG MapRegistersAllowed; // // Returned by IoGetDmaAdapter. // PDMA_ADAPTER AdapterObject; PALLOCATE_ADAPTER_CHANNEL allocateAdapterChannel; PFREE_MAP_REGISTERS freeMapRegisters; // // Map registers needed per channel. // ULONG MapRegistersPerChannel; NTSTATUS NtStatus; KIRQL OldIrql; USHORT i; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; BOOLEAN AllocationFailed; KEVENT AllocationEvent; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMAllocateMapRegisters: Miniport %p, BaseMapRegistersNeeded %lx\n", Miniport, BaseMapRegistersNeeded)); ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0); PnPReferencePackage(); // Miniport->InfoFlags |= NDIS_MINIPORT_USES_MAP_REGISTERS; do { if (MINIPORT_VERIFY_TEST_FLAG(Miniport, fMINIPORT_VERIFY_FAIL_MAP_REG_ALLOC)) { #if DBG DbgPrint("NdisMAllocateMapRegisters failed to verify miniport %p\n", Miniport); #endif Status = NDIS_STATUS_RESOURCES; break; } // // If the device is a busmaster, we get an adapter // object for it. // If map registers are needed, we loop, allocating an // adapter channel for each map register needed. // if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER)) { Miniport->BaseMapRegistersNeeded = (USHORT)BaseMapRegistersNeeded; Miniport->MaximumPhysicalMapping = MaximumPhysicalMapping; // // Allocate storage for holding the appropriate // information for each map register. // Miniport->MapRegisters = NULL; if (BaseMapRegistersNeeded > 0) { Miniport->MapRegisters = (PMAP_REGISTER_ENTRY) ALLOC_FROM_POOL(sizeof(MAP_REGISTER_ENTRY) * BaseMapRegistersNeeded, NDIS_TAG_MAP_REG); if (Miniport->MapRegisters == (PMAP_REGISTER_ENTRY)NULL) { // // Error out // NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport, NDIS_ERROR_CODE_OUT_OF_RESOURCES, 1, 0xFFFFFFFF); Status = NDIS_STATUS_RESOURCES; break; } } // // Use this event to tell us when ndisAllocationExecutionRoutine // has been called. // Miniport->AllocationEvent = &AllocationEvent; INITIALIZE_EVENT(&AllocationEvent); // // Set up the device description; zero it out in case its // size changes. // ZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; DeviceDescription.Master = TRUE; DeviceDescription.ScatterGather = TRUE; DeviceDescription.BusNumber = Miniport->BusNumber; DeviceDescription.DmaChannel = DmaChannel; DeviceDescription.InterfaceType = Miniport->AdapterType; if (DeviceDescription.InterfaceType == NdisInterfaceIsa) { // // For ISA devices, the width is based on the DMA channel: // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility // mode. // if (DmaChannel > 4) { DeviceDescription.DmaWidth = Width16Bits; } else { DeviceDescription.DmaWidth = Width8Bits; } DeviceDescription.DmaSpeed = Compatible; } else if (DeviceDescription.InterfaceType == NdisInterfacePci) { if (DmaSize == NDIS_DMA_32BITS) { DeviceDescription.Dma32BitAddresses = TRUE; } else if (DmaSize == NDIS_DMA_64BITS) { DeviceDescription.Dma64BitAddresses = TRUE; MINIPORT_SET_FLAG(Miniport, fMINIPORT_64BITS_DMA); } } DeviceDescription.MaximumLength = MaximumPhysicalMapping; // // Determine how many map registers we need per channel. // MapRegistersPerChannel = ((MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; #if DBG if (MapRegistersPerChannel > 16) { DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_WARN, ("NdisMAllocateMapRegisters: Miniport %p, MaximumPhysicalMapping of 0x%lx\nwould require more than 16 MAP registers per channel, the call may fail\n", Miniport, MaximumPhysicalMapping)); } #endif NDIS_WARN((Miniport->BaseMapRegistersNeeded * MapRegistersPerChannel > 0x40), Miniport, NDIS_GFLAG_WARN_LEVEL_0, ("ndisMInitializeAdapter: Miniport %p is asking for too many %ld > 64 map registers.\n", Miniport, Miniport->BaseMapRegistersNeeded * MapRegistersPerChannel )); // // Get the adapter object. // AdapterObject = IoGetDmaAdapter(Miniport->PhysicalDeviceObject, &DeviceDescription, &MapRegistersAllowed); if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersPerChannel)) { NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport, NDIS_ERROR_CODE_OUT_OF_RESOURCES, 1, 0xFFFFFFFF); FREE_POOL(Miniport->MapRegisters); Miniport->MapRegisters = NULL; Status = NDIS_STATUS_RESOURCES; if (AdapterObject != NULL) { RAISE_IRQL_TO_DISPATCH(&OldIrql); ((PDMA_ADAPTER)AdapterObject)->DmaOperations->PutDmaAdapter((PDMA_ADAPTER)AdapterObject); LOWER_IRQL(OldIrql, DISPATCH_LEVEL); } break; } // // We save this to call IoFreeMapRegisters later. // Miniport->SystemAdapterObject = AdapterObject; Miniport->SavedSystemAdapterObject = NULL; ASSERT(Miniport->DmaAdapterRefCount == 0); InterlockedIncrement(&Miniport->DmaAdapterRefCount); allocateAdapterChannel = *AdapterObject->DmaOperations->AllocateAdapterChannel; freeMapRegisters = *AdapterObject->DmaOperations->FreeMapRegisters; // // Now loop, allocating an adapter channel each time, then // freeing everything but the map registers. // AllocationFailed = FALSE; for (i=0; iBaseMapRegistersNeeded; i++) { Miniport->CurrentMapRegister = i; RAISE_IRQL_TO_DISPATCH(&OldIrql); NtStatus = allocateAdapterChannel(AdapterObject, Miniport->DeviceObject, MapRegistersPerChannel, ndisAllocationExecutionRoutine, Miniport); if (!NT_SUCCESS(NtStatus)) { DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, ("AllocateAdapterChannel: %lx\n", NtStatus)); for (; i != 0; i--) { freeMapRegisters(Miniport->SystemAdapterObject, Miniport->MapRegisters[i-1].MapRegister, MapRegistersPerChannel); } LOWER_IRQL(OldIrql, DISPATCH_LEVEL); NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport, NDIS_ERROR_CODE_OUT_OF_RESOURCES, 1, 0xFFFFFFFF); FREE_POOL(Miniport->MapRegisters); Miniport->MapRegisters = NULL; ndisDereferenceDmaAdapter(Miniport); AllocationFailed = TRUE; break; } LOWER_IRQL(OldIrql, DISPATCH_LEVEL); // // wait indefinitely for allocation routine to be called // NtStatus = WAIT_FOR_OBJECT(&AllocationEvent, 0); if (!NT_SUCCESS(NtStatus)) { DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR, (" NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus)); RAISE_IRQL_TO_DISPATCH(&OldIrql); for (; i != 0; i--) { freeMapRegisters(Miniport->SystemAdapterObject, Miniport->MapRegisters[i-1].MapRegister, MapRegistersPerChannel); } LOWER_IRQL(OldIrql, DISPATCH_LEVEL); NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport, NDIS_ERROR_CODE_OUT_OF_RESOURCES, 1, 0xFFFFFFFF); FREE_POOL(Miniport->MapRegisters); Miniport->MapRegisters = NULL; ndisDereferenceDmaAdapter(Miniport); AllocationFailed = TRUE; break; } RESET_EVENT(&AllocationEvent); } if (AllocationFailed) { Status = NDIS_STATUS_RESOURCES; break; } } } while (FALSE); PnPDereferencePackage(); DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMAllocateMapRegisters: Miniport %p, Status %lx\n", Miniport, Status)); return Status; } VOID NdisMFreeMapRegisters( IN NDIS_HANDLE MiniportAdapterHandle ) /*++ Routine Description: Releases allocated map registers Arguments: MiniportAdapterHandle - Handle passed to MiniportInitialize. Return Value: None. --*/ { // // Convert the handle to our internal structure. // PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle; PFREE_MAP_REGISTERS freeMapRegisters; KIRQL OldIrql; ULONG i; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMFreeMapRegisters: Miniport %p\n", Miniport)); ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0); PnPReferencePackage(); ASSERT(MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER)); ASSERT(Miniport->MapRegisters != NULL); ASSERT(Miniport->SystemAdapterObject != NULL); if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER) && (Miniport->MapRegisters != NULL)) { ULONG MapRegistersPerChannel = ((Miniport->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; freeMapRegisters = *Miniport->SystemAdapterObject->DmaOperations->FreeMapRegisters; RAISE_IRQL_TO_DISPATCH(&OldIrql); for (i = 0; i < Miniport->BaseMapRegistersNeeded; i++) { freeMapRegisters(Miniport->SystemAdapterObject, Miniport->MapRegisters[i].MapRegister, MapRegistersPerChannel); } LOWER_IRQL(OldIrql, DISPATCH_LEVEL); // // Map registers are allocated from non-paged pool. // So this memory can be freed at DISPATCH // FREE_POOL(Miniport->MapRegisters); Miniport->MapRegisters = NULL; ndisDereferenceDmaAdapter(Miniport); } PnPDereferencePackage(); DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMFreeMapRegisters: Miniport %p\n", Miniport)); } ULONG NdisMReadDmaCounter( IN NDIS_HANDLE MiniportDmaHandle ) /*++ Routine Description: Reads the current value of the dma counter Arguments: MiniportDmaHandle - Handle for the DMA transfer. Return Value: current value of a DMA counter --*/ { return ((PDMA_ADAPTER)((PNDIS_DMA_BLOCK)(MiniportDmaHandle))->SystemAdapterObject)->DmaOperations->ReadDmaCounter(((PNDIS_DMA_BLOCK)(MiniportDmaHandle))->SystemAdapterObject); } VOID ndisBugcheckHandler( IN PNDIS_WRAPPER_CONTEXT WrapperContext, IN ULONG Size ) /*++ Routine Description: This routine is called when a bugcheck occurs in the system. Arguments: Buffer -- Ndis wrapper context. Size -- Size of wrapper context Return Value: Void. --*/ { PNDIS_MINIPORT_BLOCK Miniport; if (Size == sizeof(NDIS_WRAPPER_CONTEXT)) { Miniport = (PNDIS_MINIPORT_BLOCK)(WrapperContext + 1); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SHUTTING_DOWN); if (WrapperContext->ShutdownHandler != NULL) { WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext); } } } VOID NdisMRegisterAdapterShutdownHandler( IN NDIS_HANDLE MiniportHandle, IN PVOID ShutdownContext, IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler ) /*++ Routine Description: Deregisters an NDIS adapter. Arguments: MiniportHandle - The miniport. ShutdownHandler - The Handler for the Adapter, to be called on shutdown. Return Value: none. --*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle; PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext; DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("==>NdisMRegisterAdapterShutdownHandler: Miniport %p\n", Miniport)); if (WrapperContext->ShutdownHandler == NULL) { // // Store information // WrapperContext->ShutdownHandler = ShutdownHandler; WrapperContext->ShutdownContext = ShutdownContext; // // Register our shutdown handler for a bugcheck. (Note that we are // already registered for shutdown notification.) // KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord); KeRegisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord, // callback record. ndisBugcheckHandler, // callback routine. WrapperContext, // free form buffer. sizeof(NDIS_WRAPPER_CONTEXT), // buffer size. "Ndis miniport"); // component id. } DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("<==NdisMRegisterAdapterShutdownHandler: Miniport %p\n", Miniport)); } VOID NdisMDeregisterAdapterShutdownHandler( IN NDIS_HANDLE MiniportHandle ) /*++ Routine Description: Arguments: MiniportHandle - The miniport. Return Value: None. --*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle; PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext; DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("==>NdisMDeregisterAdapterShutdownHandler: Miniport %p\n", Miniport)); // // Clear information // if (WrapperContext->ShutdownHandler != NULL) { KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord); WrapperContext->ShutdownHandler = NULL; } DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("<==NdisMDeregisterAdapterShutdownHandler: Miniport %p\n", Miniport)); } NDIS_STATUS NdisMPciAssignResources( IN NDIS_HANDLE MiniportHandle, IN ULONG SlotNumber, OUT PNDIS_RESOURCE_LIST * AssignedResources ) /*++ Routine Description: This routine uses the Hal to assign a set of resources to a PCI device. Arguments: MiniportHandle - The miniport. SlotNumber - Slot number of the device. AssignedResources - The returned resources. Return Value: Status of the operation --*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMPciAssignResources: Miniport %p\n", Miniport)); NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_3, ("NdisMPciAssignResources: Miniport %p should use NdisMQueryAdapterResources to get resources.\n", Miniport)); if ((Miniport->BusType != NdisInterfacePci) || (Miniport->AllocatedResources == NULL)) { *AssignedResources = NULL; DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMPciAssignResources: Miniport %p\n", Miniport)); return NDIS_STATUS_FAILURE; } *AssignedResources = &Miniport->AllocatedResources->List[0].PartialResourceList; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMPciAssignResources: Miniport %p\n", Miniport)); return NDIS_STATUS_SUCCESS; } VOID NdisMQueryAdapterResources( OUT PNDIS_STATUS Status, IN NDIS_HANDLE WrapperConfigurationContext, OUT PNDIS_RESOURCE_LIST ResourceList, IN IN PUINT BufferSize ) { PDEVICE_OBJECT DeviceObject; PNDIS_MINIPORT_BLOCK Miniport; ULONG MemNeeded; DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("==>NdisMQueryAdapterResources: WrapperConfigurationContext %p\n", WrapperConfigurationContext)); DeviceObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DeviceObject; Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("NdisMQueryAdapterResources: Miniport %p\n", Miniport)); if (Miniport->AllocatedResources == NULL) { *Status = NDIS_STATUS_FAILURE; } else { MemNeeded = sizeof(CM_PARTIAL_RESOURCE_LIST) - sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + Miniport->AllocatedResources->List[0].PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); if (*BufferSize < MemNeeded) { *BufferSize = MemNeeded; *Status = NDIS_STATUS_RESOURCES; } else { NdisMoveMemory( ResourceList, &Miniport->AllocatedResources->List[0].PartialResourceList, MemNeeded ); *Status = NDIS_STATUS_SUCCESS; } } DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO, ("<==NdisMQueryAdapterResources: Miniport %p, Status %lx\n", Miniport, *Status)); return; } NTSTATUS ndisPnPAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject ) /*++ Routine Description: The AddDevice entry point is called by the Plug & Play manager to inform the driver when a new device instance arrives that this driver must control. Arguments: Return Value: --*/ { NTSTATUS NtStatus, Status; PWSTR ExportData = NULL; UNICODE_STRING ExportName, BusStr; HANDLE Handle = NULL; PUINT BusTypeData = NULL, CharacteristicsData = NULL; ULONG ValueType; RTL_QUERY_REGISTRY_TABLE LQueryTable[3]; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisPnPAddDevice: DriverObject %p, PDO %p\n", DriverObject, PhysicalDeviceObject)); Status = STATUS_UNSUCCESSFUL; do { #if NDIS_TEST_REG_FAILURE NtStatus = STATUS_UNSUCCESSFUL; #else NtStatus = IoOpenDeviceRegistryKey(PhysicalDeviceObject, PLUGPLAY_REGKEY_DRIVER, GENERIC_READ | MAXIMUM_ALLOWED, &Handle); #endif #if !NDIS_NO_REGISTRY if (!NT_SUCCESS(NtStatus)) break; // // 1. // Switch to the Linkage key below this driver instance key // LQueryTable[0].QueryRoutine = NULL; LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; LQueryTable[0].Name = L"Linkage"; // // 2. // Read the export and rootdevice keywords // LQueryTable[1].QueryRoutine = ndisReadParameter; LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; LQueryTable[1].Name = L"Export"; LQueryTable[1].EntryContext = (PVOID)&ExportData; LQueryTable[1].DefaultType = REG_NONE; LQueryTable[2].QueryRoutine = NULL; LQueryTable[2].Flags = 0; LQueryTable[2].Name = NULL; NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, Handle, LQueryTable, NULL, NULL); if (!NT_SUCCESS(NtStatus) || (ExportData == NULL)) break; RtlInitUnicodeString(&ExportName, ExportData); // // 3. // Read the bus-type and characteristics keywords // LQueryTable[0].QueryRoutine = ndisReadParameter; LQueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND; LQueryTable[0].Name = L"Characteristics"; LQueryTable[0].EntryContext = (PVOID)&CharacteristicsData; LQueryTable[0].DefaultType = REG_NONE; LQueryTable[1].QueryRoutine = NULL; LQueryTable[1].Flags = 0; LQueryTable[1].Name = NULL; NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, Handle, LQueryTable, &ValueType, NULL); #else if (NT_SUCCESS(NtStatus)) { // // 1. // Switch to the Linkage key below this driver instance key // LQueryTable[0].QueryRoutine = NULL; LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; LQueryTable[0].Name = L"Linkage"; // // 2. // Read the export and rootdevice keywords // LQueryTable[1].QueryRoutine = ndisReadParameter; LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; LQueryTable[1].Name = L"Export"; LQueryTable[1].EntryContext = (PVOID)&ExportData; LQueryTable[1].DefaultType = REG_NONE; LQueryTable[2].QueryRoutine = NULL; LQueryTable[2].Flags = 0; LQueryTable[2].Name = NULL; NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, Handle, LQueryTable, NULL, NULL); if (!NT_SUCCESS(NtStatus) || (ExportData == NULL)) break; RtlInitUnicodeString(&ExportName, ExportData); // // 3. // Read the bus-type and characteristics keywords // LQueryTable[0].QueryRoutine = ndisReadParameter; LQueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND; LQueryTable[0].Name = L"Characteristics"; LQueryTable[0].EntryContext = (PVOID)&CharacteristicsData; LQueryTable[0].DefaultType = REG_NONE; LQueryTable[1].QueryRoutine = NULL; LQueryTable[1].Flags = 0; LQueryTable[1].Name = NULL; NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, Handle, LQueryTable, &ValueType, NULL); } else { ExportData = (PWSTR)ALLOC_FROM_POOL(sizeof(NDIS_DEFAULT_EXPORT_NAME), NDIS_TAG_NAME_BUF); if (ExportData == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory(ExportData, ndisDefaultExportName, sizeof(NDIS_DEFAULT_EXPORT_NAME)); RtlInitUnicodeString(&ExportName, ExportData); } #endif DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("ndisPnPAddDevice: Device: ")); DBGPRINT_UNICODE(DBG_COMP_PNP, DBG_LEVEL_INFO, &ExportName); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("\n")); Status = ndisAddDevice(DriverObject, &ExportName, PhysicalDeviceObject, (CharacteristicsData != NULL) ? *CharacteristicsData : 0); } while (FALSE); if (Handle) ZwClose(Handle); if (ExportData != NULL) FREE_POOL(ExportData); if (CharacteristicsData != NULL) FREE_POOL(CharacteristicsData); DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, (" ndisPnPAddDevice returning %lx\n", Status)); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisPnPAddDevice: PDO %p\n", PhysicalDeviceObject)); return Status; } NDIS_STATUS FASTCALL ndisPnPStartDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp OPTIONAL ) /*+++ Routine Description: The handler for IRP_MN_START_DEVICE. Arguments: DeviceObject - The adapter's device object. Irp - The IRP. Adapter - a pointer to either AdapterBlock or MiniportBlock Return Value: NDIS_STATUS_SUCCESS if intializing the device was successful Note: This routine can also be called from NdisImInitializeDeviceInstanceEx in which case the Irp woud be NULL ---*/ { PNDIS_MINIPORT_BLOCK Miniport; PCM_RESOURCE_LIST AllocatedResources, AllocatedResourcesTranslated, pTempResources = NULL; NDIS_STATUS Status; PIO_STACK_LOCATION IrpSp; NTSTATUS NtStatus; ULONG MemNeeded = 0; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisPnPStartDevice: DeviceObject\n", DeviceObject)); Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("ndisPnPStartDevice: Miniport %p, ", Miniport)); DBGPRINT_UNICODE(DBG_COMP_PNP, DBG_LEVEL_INFO, Miniport->pAdapterInstanceName); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("\n")); DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("\n")); if (Miniport->PnPDeviceState == NdisPnPDeviceStopped) { // // re-initialize the miniport block structure without destroying what // we set during AddDevice // ndisReinitializeMiniportBlock(Miniport); MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_RECEIVED_START); } do { if (Irp != NULL) { IrpSp = IoGetCurrentIrpStackLocation (Irp); // // save allocated resources with miniport/adapter structure // AllocatedResources = IrpSp->Parameters.StartDevice.AllocatedResources; AllocatedResourcesTranslated = IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated; if (AllocatedResources) { MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_HARDWARE_DEVICE); MemNeeded = sizeof(CM_RESOURCE_LIST) - sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + AllocatedResources->List[0].PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); pTempResources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(2 * MemNeeded, NDIS_TAG_ALLOCATED_RESOURCES); if (pTempResources == NULL) { Status = NDIS_STATUS_RESOURCES; break; } NdisMoveMemory(pTempResources, AllocatedResources, MemNeeded); NdisMoveMemory((PUCHAR)pTempResources + MemNeeded, IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated, MemNeeded); #if DBG if ((ndisDebugLevel == DBG_LEVEL_INFO) && (ndisDebugSystems & DBG_COMP_PNP)) { UINT j; PCM_PARTIAL_RESOURCE_LIST pResourceList; DbgPrint("ndisPnPStartDevice: Miniport %p, Non-Translated allocated resources\n", Miniport); pResourceList = &(AllocatedResources->List[0].PartialResourceList); for (j = 0; j < pResourceList->Count; j++) { switch (pResourceList->PartialDescriptors[j].Type) { case CmResourceTypePort: DbgPrint("IO Port: %p, Length: %lx\n", pResourceList->PartialDescriptors[j].u.Port.Start.LowPart, pResourceList->PartialDescriptors[j].u.Port.Length); break; case CmResourceTypeMemory: DbgPrint("Memory: %p, Length: %lx\n", pResourceList->PartialDescriptors[j].u.Memory.Start.LowPart, pResourceList->PartialDescriptors[j].u.Memory.Length); break; case CmResourceTypeInterrupt: DbgPrint("Interrupt Level: %lx, Vector: %lx\n", pResourceList->PartialDescriptors[j].u.Interrupt.Level, pResourceList->PartialDescriptors[j].u.Interrupt.Vector); break; case CmResourceTypeDma: DbgPrint("DMA Channel: %lx\n", pResourceList->PartialDescriptors[j].u.Dma.Channel); break; } } DbgPrint("ndisPnPStartDevice: Miniport %p, Translated allocated resources\n", Miniport); pResourceList = &(AllocatedResourcesTranslated->List[0].PartialResourceList); for (j = 0; j < pResourceList->Count; j++) { switch (pResourceList->PartialDescriptors[j].Type) { case CmResourceTypePort: DbgPrint("IO Port: %p, Length: %lx\n", pResourceList->PartialDescriptors[j].u.Port.Start.LowPart, pResourceList->PartialDescriptors[j].u.Port.Length); break; case CmResourceTypeMemory: DbgPrint("Memory: %p, Length: %lx\n", pResourceList->PartialDescriptors[j].u.Memory.Start.LowPart, pResourceList->PartialDescriptors[j].u.Memory.Length); break; case CmResourceTypeInterrupt: DbgPrint("Interrupt Level: %lx, Vector: %lx\n", pResourceList->PartialDescriptors[j].u.Interrupt.Level, pResourceList->PartialDescriptors[j].u.Interrupt.Vector); break; case CmResourceTypeDma: DbgPrint("DMA Channel: %lx\n", pResourceList->PartialDescriptors[j].u.Dma.Channel); break; } } } #endif } // end of if AllocatedResources != NULL } Miniport->AllocatedResources = pTempResources; Miniport->AllocatedResourcesTranslated = (PCM_RESOURCE_LIST)((PUCHAR)pTempResources + MemNeeded); Status = ndisInitializeAdapter(Miniport->DriverHandle, DeviceObject, Miniport->pAdapterInstanceName, Miniport->DeviceContext); if (Status == NDIS_STATUS_SUCCESS) { Miniport->PnPDeviceState = NdisPnPDeviceStarted; NdisSetEvent(&Miniport->OpenReadyEvent); KeQueryTickCount(&Miniport->NdisStats.StartTicks); } } while (FALSE); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisPnPStartDevice: Miniport %p\n", Miniport)); return Status; } NTSTATUS ndisQueryReferenceBusInterface( IN PDEVICE_OBJECT PnpDeviceObject, OUT PBUS_INTERFACE_REFERENCE* pBusInterface ) /*++ Routine Description: Queries the bus for the standard information interface. Arguments: PnpDeviceObject - Contains the next device object on the Pnp stack. PhysicalDeviceObject - Contains the physical device object which was passed to the FDO during the Add Device. BusInterface - The place in which to return the pointer to the Reference interface. Return Value: Returns STATUS_SUCCESS if the interface was retrieved, else an error. --*/ { NTSTATUS Status; KEVENT Event; IO_STATUS_BLOCK IoStatusBlock; PIRP Irp; PIO_STACK_LOCATION IrpStackNext; PAGED_CODE(); *pBusInterface = (PBUS_INTERFACE_REFERENCE)ALLOC_FROM_POOL(sizeof(BUS_INTERFACE_REFERENCE), NDIS_TAG_BUS_INTERFACE); if (*pBusInterface == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } // // There is no file object associated with this Irp, so the event may be located // on the stack as a non-object manager object. // INITIALIZE_EVENT(&Event); Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, PnpDeviceObject, NULL, 0, NULL, &Event, &IoStatusBlock); if (Irp != NULL) { Irp->RequestorMode = KernelMode; Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; IrpStackNext = IoGetNextIrpStackLocation(Irp); // // Create an interface query out of the Irp. // IrpStackNext->MinorFunction = IRP_MN_QUERY_INTERFACE; IrpStackNext->Parameters.QueryInterface.InterfaceType = (GUID*)&REFERENCE_BUS_INTERFACE; IrpStackNext->Parameters.QueryInterface.Size = sizeof(**pBusInterface); IrpStackNext->Parameters.QueryInterface.Version = BUS_INTERFACE_REFERENCE_VERSION; IrpStackNext->Parameters.QueryInterface.Interface = (PINTERFACE)*pBusInterface; IrpStackNext->Parameters.QueryInterface.InterfaceSpecificData = NULL; Status = IoCallDriver(PnpDeviceObject, Irp); if (Status == STATUS_PENDING) { // // This waits using KernelMode, so that the stack, and therefore the // event on that stack, is not paged out. // WAIT_FOR_OBJECT(&Event, NULL); Status = IoStatusBlock.Status; } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } if (!NT_SUCCESS(Status)) { FREE_POOL(*pBusInterface); *pBusInterface = NULL; } return Status; } NTSTATUS ndisAddDevice( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING pExportName, IN PDEVICE_OBJECT PhysicalDeviceObject, IN ULONG Characteristics ) /*++ Routine Description: The AddDevice entry point is called by the Plug & Play manager to inform the driver when a new device instance arrives that this driver must control. Arguments: Return Value: --*/ { PDEVICE_OBJECT NextDeviceObject = NULL; NTSTATUS NtStatus, Status = STATUS_UNSUCCESSFUL; PDEVICE_OBJECT DevicePtr = NULL; PNDIS_MINIPORT_BLOCK Miniport; UNICODE_STRING us; PWCHAR pPath; PNDIS_M_DRIVER_BLOCK MiniBlock, TmpMiniBlock; UINT NumComponents; LONG Size; BOOLEAN FreeDevice = FALSE; PCM_RESOURCE_LIST pResourceList; KIRQL OldIrql; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisAddDevice: PDO %p\n", PhysicalDeviceObject)); PnPReferencePackage(); do { MiniBlock = (PNDIS_M_DRIVER_BLOCK)IoGetDriverObjectExtension(DriverObject, (PVOID)NDIS_PNP_MINIPORT_DRIVER_ID); { // // check to make sure the mini block is on our queue // ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql); TmpMiniBlock = ndisMiniDriverList; while (TmpMiniBlock) { if (TmpMiniBlock == MiniBlock) break; TmpMiniBlock = TmpMiniBlock->NextDriver; } RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql); ASSERT(TmpMiniBlock == MiniBlock); if (TmpMiniBlock != MiniBlock) { #if TRACK_UNLOAD DbgPrint("ndisAddDevice: AddDevice called with a MiniBlock that is not on ndisMiniDriverList\n"); KeBugCheckEx(BUGCODE_ID_DRIVER, (ULONG_PTR)MiniBlock, (ULONG_PTR)DriverObject, 0, 0); #endif break; } } // // create DeviceObject and Miniport/Adapter structure now, // we will set a few field here and the rest will be set during // processing IRP_MN_START_DEVICE and InitializeAdapter call. // // Note: We need the device-name field double null terminated. // Size = sizeof(NDIS_MINIPORT_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT) + pExportName->Length + sizeof(WCHAR) + sizeof(WCHAR); NtStatus = IoCreateDevice(DriverObject, Size, pExportName, FILE_DEVICE_PHYSICAL_NETCARD, FILE_DEVICE_SECURE_OPEN, FALSE, // exclusive flag &DevicePtr); if(!NT_SUCCESS(NtStatus)) break; DevicePtr->Flags &= ~DO_DEVICE_INITIALIZING; DevicePtr->Flags |= DO_DIRECT_IO; PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; FreeDevice = TRUE; // // Mark the device as being pageable. // DevicePtr->Flags |= DO_POWER_PAGABLE; // // Attach our FDO to the PDO. This routine will return the top most // device that is attached to the PDO or the PDO itself if no other // device objects have attached to it. // NextDeviceObject = IoAttachDeviceToDeviceStack(DevicePtr, PhysicalDeviceObject); ZeroMemory(DevicePtr->DeviceExtension, Size); Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DevicePtr->DeviceExtension + 1); Miniport->Signature = (PVOID)MINIPORT_DEVICE_MAGIC_VALUE; Miniport->DriverHandle = MiniBlock; // // initialize OpenReady event in case we get an open request before start IRP // NdisInitializeEvent(&Miniport->OpenReadyEvent); INITIALIZE_SPIN_LOCK(&Miniport->Lock); #if CHECK_TIMER if (Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING) INITIALIZE_SPIN_LOCK(&Miniport->TimerQueueLock); #endif Miniport->PrimaryMiniport = Miniport; Miniport->PnPDeviceState = NdisPnPDeviceAdded; Miniport->PhysicalDeviceObject = PhysicalDeviceObject; Miniport->DeviceObject = DevicePtr; Miniport->NextDeviceObject = NextDeviceObject; Miniport->WrapperContext = DevicePtr->DeviceExtension; InitializeListHead(&Miniport->PacketList); // // intialize the reference and set it to 0; we will increment it // in ndisMinitializeAdapter // ndisInitializeULongRef(&Miniport->Ref); Miniport->Ref.ReferenceCount = 0; #ifdef TRACK_MINIPORT_REFCOUNTS M_LOG_MINIPORT_SET_REF(Miniport, 0); #endif // // Read the characteristics. This determines if the device is hidden or not (from device-manager) // if (Characteristics & 0x08) { // // Bit 0x08 is NCF_HIDDEN // MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_HIDDEN); } if (Characteristics & 0x02) { // // Bit 0x02 is NCF_SOFTWARE_ENUMERATED // MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SWENUM); } // // MiniportName must follow the MINIPORT_BLOCK. // ndisSetDeviceNames(pExportName, &Miniport->MiniportName, &Miniport->BaseName, (PUCHAR)Miniport + sizeof(NDIS_MINIPORT_BLOCK)); NtStatus = ndisCreateAdapterInstanceName(&Miniport->pAdapterInstanceName, PhysicalDeviceObject); if (!NT_SUCCESS(NtStatus)) { break; } Miniport->InstanceNumber = (USHORT)InterlockedIncrement(&ndisInstanceNumber); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("ndisAddDevice: Miniport %p, ", Miniport)); DBGPRINT_UNICODE(DBG_COMP_PNP, DBG_LEVEL_INFO, Miniport->pAdapterInstanceName); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("\n")); if (Characteristics & 0x02) { PBUS_INTERFACE_REFERENCE BusInterface = NULL; Status = ndisQueryReferenceBusInterface(PhysicalDeviceObject, &BusInterface); if (NT_SUCCESS(Status)) { Miniport->BusInterface = BusInterface; } else { ASSERT(BusInterface == NULL); break; } } // // create a security descriptor for the device // Status = ndisCreateSecurityDescriptor(Miniport->DeviceObject, &Miniport->SecurityDescriptor, TRUE); if (!NT_SUCCESS(Status)) { FREE_POOL(Miniport->pAdapterInstanceName); Status = STATUS_UNSUCCESSFUL; break; } Status = STATUS_SUCCESS; // // Don't want to free up the device object. // FreeDevice = FALSE; } while (FALSE); if (FreeDevice) { // // if device is created it is also attached // if (NextDeviceObject) IoDetachDevice(NextDeviceObject); IoDeleteDevice(DevicePtr); DevicePtr = NULL; } if (DevicePtr && (NT_SUCCESS(Status))) { // // if DevicePtr is not NULL, we do have a valid // miniport. queue the miniport on global miniport queue // ACQUIRE_SPIN_LOCK(&ndisMiniportListLock, &OldIrql); Miniport->NextGlobalMiniport = ndisMiniportList; ndisMiniportList = Miniport; RELEASE_SPIN_LOCK(&ndisMiniportListLock, OldIrql); } PnPDereferencePackage(); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisAddDevice: Miniport %p\n", Miniport)); return Status; } VOID ndisSetDeviceNames( IN PNDIS_STRING ExportName, OUT PNDIS_STRING DeviceName, OUT PNDIS_STRING BaseName, IN PUCHAR Buffer ) { PNDIS_STRING BindPath; PWSTR pComp, p; USHORT i; NDIS_STRING Str, SubStr; DeviceName->Buffer = (PWSTR)Buffer; DeviceName->Length = ExportName->Length; DeviceName->MaximumLength = DeviceName->Length + sizeof(WCHAR); RtlUpcaseUnicodeString(DeviceName, ExportName, FALSE); // // ExportName is in the form of \Device\ // Extract BaseName which is the name w/o the "\Device\" // BaseName->Buffer = DeviceName->Buffer + (ndisDeviceStr.Length/sizeof(WCHAR)); BaseName->Length = DeviceName->Length - ndisDeviceStr.Length; BaseName->MaximumLength = BaseName->Length + sizeof(WCHAR); } NTSTATUS FASTCALL ndisPnPQueryStopDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS Status; PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); KIRQL OldIrql; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisPnPQueryStopDevice: Miniport %p\n", Miniport)); do { if (Miniport->PnPCapabilities & NDIS_DEVICE_NOT_STOPPABLE) { Status = STATUS_UNSUCCESSFUL; break; } // // query_stop and stop are not reported to the user mode // so we have to protect ourselves against cases that apps // may have pending IO against the miniport // NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); if (Miniport->UserModeOpenReferences != 0) { Status = STATUS_UNSUCCESSFUL; NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); break; } NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); // // for now do the same as query remove // Status = ndisPnPQueryRemoveDevice(DeviceObject, Irp); } while (FALSE); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisPnPQueryStopDevice: Miniport %p\n", Miniport)); return Status; } NTSTATUS FASTCALL ndisPnPCancelStopDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS Status; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisPnPCancelStopDevice\n")); // // for now do the same as cancel remove // Status = ndisPnPCancelRemoveDevice(DeviceObject, Irp); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisPnPCancelStopDevice\n")); return Status; } NTSTATUS FASTCALL ndisPnPStopDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS Status; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisPnPStopDevice\n")); // // do the same as remove // Status = ndisPnPRemoveDevice(DeviceObject, Irp); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisPnPStopDevice\n")); return Status; } NTSTATUS FASTCALL ndisPnPQueryRemoveDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); NTSTATUS Status = STATUS_SUCCESS; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisPnPQueryRemoveDevice: Miniport %p, UserModeOpenReferences %lx\n", Miniport, Miniport->UserModeOpenReferences)); do { // // If this was the network card used in a remote boot, then we // can't remove it. // if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_NETBOOT_CARD)) { Status = STATUS_UNSUCCESSFUL; break; } Status = ndisPnPNotifyAllTransports(Miniport, NetEventQueryRemoveDevice, NULL, 0); } while (FALSE); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisPnPQueryRemoveDevice: Miniport %p, Status 0x%x\n", Miniport, Status)); return Status; } NTSTATUS FASTCALL ndisPnPCancelRemoveDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); NTSTATUS Status = NDIS_STATUS_SUCCESS; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisPnPCancelRemoveDevice: Miniport %p\n", Miniport)); Status = ndisPnPNotifyAllTransports(Miniport, NetEventCancelRemoveDevice, NULL, 0); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisPnPCancelRemoveDevice: Miniport %p\n", Miniport)); return STATUS_SUCCESS; } NTSTATUS FASTCALL ndisPnPRemoveDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp OPTIONAL ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); NTSTATUS Status = NDIS_STATUS_SUCCESS; PNDIS_OPEN_BLOCK Open, NextOpen; NDIS_BIND_CONTEXT UnbindContext; KIRQL OldIrql; BOOLEAN fAcquiredImMutex = FALSE; PKMUTEX pIMStartRemoveMutex = NULL; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisPnPRemoveDevice: Miniport %p\n", Miniport)); PnPReferencePackage(); // // there are three different cases that we can get a remove request // a: the request is coming from PnP manager in response to a user mode // app. In this case, the remove has been proceeded by a query remove // which we happily failed if there was any legacy protocol bound to // the adapter // // b. the request is coming from PnP manager because Starting the device failed // in this case (hopefully) there is no binding at all. in this case it is not // proceeded by query_remove and neet not be. we don't have any protocol bound // to the adapter to worry about // // c. or it can come in response to a surprise style removal in which case we are // hosed anyway. sending query_remove to protocols does not do any good // do { PNDIS_M_DRIVER_BLOCK MiniBlock; PNDIS_MINIPORT_BLOCK TmpMiniport; // // find the miniport on driver queue // MiniBlock = Miniport->DriverHandle; if (MiniBlock == NULL) break; // // Intermediate drivers could be in the middle of initialization through the // NdisIMInitializeDeviceInstance Code path. We need to synchronize // if (MiniBlock->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER) { pIMStartRemoveMutex = &MiniBlock->IMStartRemoveMutex; WAIT_FOR_OBJECT(pIMStartRemoveMutex, NULL); fAcquiredImMutex = TRUE; } ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql); for (TmpMiniport = MiniBlock->MiniportQueue; TmpMiniport != NULL; TmpMiniport = TmpMiniport->NextMiniport) { if (TmpMiniport == Miniport) { break; } } RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql); if ((TmpMiniport != Miniport) || (Miniport->Ref.Closing == TRUE)) { break; } ndisReferenceDriver(MiniBlock); NdisResetEvent(&Miniport->OpenReadyEvent); // // Notify WMI of adapter removal. // if (Miniport->pAdapterInstanceName != NULL) { PWNODE_SINGLE_INSTANCE wnode; PUCHAR ptmp; NTSTATUS NtStatus; ndisSetupWmiNode(Miniport, Miniport->pAdapterInstanceName, Miniport->MiniportName.Length + sizeof(USHORT), (PVOID)&GUID_NDIS_NOTIFY_ADAPTER_REMOVAL, &wnode); if (wnode != NULL) { // // Save the number of elements in the first ULONG. // ptmp = (PUCHAR)wnode + wnode->DataBlockOffset; *((PUSHORT)ptmp) = Miniport->MiniportName.Length; // // Copy the data after the number of elements. // RtlCopyMemory(ptmp + sizeof(USHORT), Miniport->MiniportName.Buffer, Miniport->MiniportName.Length); // // Indicate the event to WMI. WMI will take care of freeing // the WMI struct back to pool. // NtStatus = IoWMIWriteEvent(wnode); if (!NT_SUCCESS(NtStatus)) { DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR, ("ndisPnPRemoveDevice: Failed to indicate adapter removal\n")); FREE_POOL(wnode); } } } // // this will take care of closing all the bindings // ndisCloseMiniportBindings(Miniport); if (Miniport->pIrpWaitWake) { if (IoCancelIrp(Miniport->pIrpWaitWake)) { DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO, ("ndisPnPRemoveDevice: Miniport %p, Successfully canceled wake irp\n", Miniport)); } } // // get rid of wakeup patterns set on the miniport // { PSINGLE_LIST_ENTRY Link; PNDIS_PACKET_PATTERN_ENTRY pPatternEntry; while (Miniport->PatternList.Next != NULL) { Link = PopEntryList(&Miniport->PatternList); pPatternEntry = CONTAINING_RECORD(Link, NDIS_PACKET_PATTERN_ENTRY, Link); // // Free the memory taken by the pattern. // FREE_POOL(pPatternEntry); } } // // and this one will take care of the rest! // we call this function even if the device has already been halted by // ndisPMHaltMiniport. because that functions does not clean up everything. // ndisMHaltMiniport will check for PM_HALTED flag and avoid re-doing what PMHalt // has already done. // ndisMHaltMiniport(Miniport); // // Free the media-request structure, if present // if (Miniport->MediaRequest != NULL) { FREE_POOL(Miniport->MediaRequest); Miniport->MediaRequest = NULL; } ndisDereferenceDriver(MiniBlock, FALSE); { UNICODE_STRING DeviceName, UpcaseDeviceName; UNICODE_STRING SymbolicLink; NTSTATUS NtStatus; WCHAR SymLnkBuf[128]; SymbolicLink.Buffer = SymLnkBuf; SymbolicLink.Length = 0; SymbolicLink.MaximumLength = sizeof(SymLnkBuf); RtlCopyUnicodeString(&SymbolicLink, &ndisDosDevicesStr); RtlAppendUnicodeStringToString(&SymbolicLink, &Miniport->BaseName); NtStatus = IoDeleteSymbolicLink(&SymbolicLink); if (!NT_SUCCESS(NtStatus)) { #if DBG DbgPrint("ndisPnPRemoveDevice: deleting symbolic link name failed for miniport %p, SymbolicLinkName %p, NtStatus %lx\n", Miniport, &SymbolicLink, NtStatus); #endif } } } while (FALSE); if(fAcquiredImMutex == TRUE) { RELEASE_MUTEX(pIMStartRemoveMutex); } PnPDereferencePackage(); DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisPnPRemoveDevice: Miniport %p\n", Miniport)); return Status; } VOID FASTCALL ndisReinitializeMiniportBlock( IN PNDIS_MINIPORT_BLOCK Miniport ) { PDEVICE_OBJECT PhysicalDeviceObject, DeviceObject, NextDeviceObject; PNDIS_M_DRIVER_BLOCK MiniBlock; PNDIS_MINIPORT_BLOCK NextGlobalMiniport; PNDIS_MINIPORT_BLOCK PrimaryMiniport; UNICODE_STRING BaseName, MiniportName; PUNICODE_STRING InstanceName; PNDIS_BIND_PATHS BindPaths; PVOID WrapperContext; NDIS_HANDLE DeviceContext; ULONG PnPCapabilities; ULONG FlagsToSave = 0; ULONG PnPFlagsToSave = 0; DEVICE_POWER_STATE CurrentDevicePowerState; PVOID BusInterface; USHORT InstanceNumber; PSECURITY_DESCRIPTOR SecurityDescriptor; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisReinitializeMiniportBlock: Miniport %p\n", Miniport)); PhysicalDeviceObject = Miniport->PhysicalDeviceObject; DeviceObject= Miniport->DeviceObject; NextDeviceObject = Miniport->NextDeviceObject; MiniBlock = Miniport->DriverHandle; WrapperContext = Miniport->WrapperContext; BaseName = Miniport->BaseName; MiniportName = Miniport->MiniportName; InstanceName = Miniport->pAdapterInstanceName; DeviceContext = Miniport->DeviceContext; BindPaths = Miniport->BindPaths; PnPCapabilities = Miniport->PnPCapabilities; PnPFlagsToSave = Miniport->PnPFlags & (fMINIPORT_RECEIVED_START | fMINIPORT_SWENUM | fMINIPORT_HIDDEN | fMINIPORT_HARDWARE_DEVICE | fMINIPORT_NDIS_WDM_DRIVER | fMINIPORT_FILTER_IM ); FlagsToSave = Miniport->Flags & fMINIPORT_REQUIRES_MEDIA_POLLING; CurrentDevicePowerState = Miniport->CurrentDevicePowerState; NextGlobalMiniport = Miniport->NextGlobalMiniport; PrimaryMiniport = Miniport->PrimaryMiniport; InstanceNumber = Miniport->InstanceNumber; BusInterface = Miniport->BusInterface; SecurityDescriptor = Miniport->SecurityDescriptor; ZeroMemory(Miniport, FIELD_OFFSET(NDIS_MINIPORT_BLOCK, OpenReadyEvent)); ZeroMemory((PUCHAR)Miniport + FIELD_OFFSET(NDIS_MINIPORT_BLOCK, OpenReadyEvent) + sizeof(Miniport->OpenReadyEvent), sizeof(NDIS_MINIPORT_BLOCK) - FIELD_OFFSET(NDIS_MINIPORT_BLOCK, OpenReadyEvent) - sizeof(Miniport->OpenReadyEvent)); // // restore what we saved // Miniport->PnPDeviceState = NdisPnPDeviceAdded; Miniport->Signature = (PVOID)MINIPORT_DEVICE_MAGIC_VALUE; Miniport->DriverHandle = MiniBlock; INITIALIZE_SPIN_LOCK(&Miniport->Lock); #if CHECK_TIMER if (Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING) INITIALIZE_SPIN_LOCK(&Miniport->TimerQueueLock); #endif Miniport->PhysicalDeviceObject = PhysicalDeviceObject; Miniport->DeviceObject = DeviceObject; Miniport->NextDeviceObject = NextDeviceObject; Miniport->WrapperContext = WrapperContext; Miniport->BaseName = BaseName; Miniport->MiniportName = MiniportName; Miniport->pAdapterInstanceName = InstanceName; Miniport->DeviceContext = DeviceContext; Miniport->BindPaths = BindPaths; Miniport->PnPCapabilities = PnPCapabilities; Miniport->Flags = FlagsToSave; Miniport->PnPFlags = PnPFlagsToSave; Miniport->CurrentDevicePowerState = CurrentDevicePowerState; Miniport->NextGlobalMiniport = NextGlobalMiniport; Miniport->PrimaryMiniport = PrimaryMiniport; Miniport->InstanceNumber = InstanceNumber; Miniport->BusInterface = BusInterface; InitializeListHead(&Miniport->PacketList); Miniport->FirstPendingPacket = NULL; if (MiniBlock->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER) { MINIPORT_SET_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER); } Miniport->SecurityDescriptor = SecurityDescriptor; DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisReinitializeMiniportBlock: Miniport %p\n", Miniport)); } EXPORT VOID NdisMGetDeviceProperty( IN NDIS_HANDLE MiniportAdapterHandle, IN OUT PDEVICE_OBJECT * PhysicalDeviceObject OPTIONAL, IN OUT PDEVICE_OBJECT * FunctionalDeviceObject OPTIONAL, IN OUT PDEVICE_OBJECT * NextDeviceObject OPTIONAL, IN OUT PCM_RESOURCE_LIST * AllocatedResources OPTIONAL, IN OUT PCM_RESOURCE_LIST * AllocatedResourcesTranslated OPTIONAL ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; // // very likely this is a NDIS_WDM driver. // if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HARDWARE_DEVICE)) { MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_NDIS_WDM_DRIVER); } if (ARGUMENT_PRESENT(PhysicalDeviceObject)) { *PhysicalDeviceObject = Miniport->PhysicalDeviceObject; } if (ARGUMENT_PRESENT(FunctionalDeviceObject)) { *FunctionalDeviceObject = Miniport->DeviceObject; } if (ARGUMENT_PRESENT(NextDeviceObject)) { *NextDeviceObject = Miniport->NextDeviceObject; } if (ARGUMENT_PRESENT(AllocatedResources)) { *AllocatedResources = Miniport->AllocatedResources; } if (ARGUMENT_PRESENT(AllocatedResourcesTranslated)) { *AllocatedResourcesTranslated = Miniport->AllocatedResourcesTranslated; } return; } NTSTATUS ndisWritePnPCapabilities( IN PNDIS_MINIPORT_BLOCK Miniport, IN ULONG PnPCapabilities ) { NTSTATUS RegistryStatus; HANDLE Handle, RootHandle; OBJECT_ATTRIBUTES ObjAttr; UNICODE_STRING Root={0, 0, NULL}; do { #if NDIS_TEST_REG_FAILURE RegistryStatus = STATUS_UNSUCCESSFUL; RootHandle = NULL; #else RegistryStatus = IoOpenDeviceRegistryKey(Miniport->PhysicalDeviceObject, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE | MAXIMUM_ALLOWED, &RootHandle); #endif if (!NT_SUCCESS(RegistryStatus)) { break; } InitializeObjectAttributes(&ObjAttr, &Root, OBJ_CASE_INSENSITIVE, RootHandle, NULL); RegistryStatus = ZwOpenKey(&Handle, GENERIC_READ | MAXIMUM_ALLOWED, &ObjAttr); if (NT_SUCCESS(RegistryStatus)) { RegistryStatus = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE, Handle, L"PnPCapabilities", REG_DWORD, &PnPCapabilities, sizeof(ULONG)); ZwClose(Handle); } ZwClose(RootHandle); } while (FALSE); return RegistryStatus; } NDIS_STATUS NdisMRemoveMiniport( IN NDIS_HANDLE MiniportHandle ) /*++ Routine Description: Miniports call this routine to signal a device failure. in response, ndis will ask PnP to send a REMOVE IRP for this device Arguments: MiniportHandle - Miniport Return Value: always successful --*/ { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportHandle; MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_DEVICE_FAILED); IoInvalidateDeviceState(Miniport->PhysicalDeviceObject); return(NDIS_STATUS_SUCCESS); } PNDIS_MINIPORT_BLOCK ndisFindMiniportOnGlobalList( IN PNDIS_STRING DeviceName ) /*++ Routine Description: Find the Miniport with a matching device name on ndisMiniportList. Arguments: Return Value: a pointer to MiniportBlock if found. NULL otherwise --*/ { KIRQL OldIrql; PNDIS_MINIPORT_BLOCK Miniport; NDIS_STRING UpcaseDevice; PWSTR pwch; DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO, ("==>ndisFindMiniportOnGlobalList: DeviceName %p\n", DeviceName)); // // First we need to upcase the device-name before checking // UpcaseDevice.Length = DeviceName->Length; UpcaseDevice.MaximumLength = DeviceName->Length + sizeof(WCHAR); UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING); if ((pwch = UpcaseDevice.Buffer) == NULL) { return NULL; } RtlUpcaseUnicodeString(&UpcaseDevice, DeviceName, FALSE); ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0); PnPReferencePackage(); ACQUIRE_SPIN_LOCK(&ndisMiniportListLock, &OldIrql); for (Miniport = ndisMiniportList; Miniport != NULL; Miniport = Miniport->NextGlobalMiniport) { if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->MiniportName)) { break; } } RELEASE_SPIN_LOCK(&ndisMiniportListLock, OldIrql); PnPDereferencePackage(); FREE_POOL(pwch); DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO, ("<==ndisFindMiniportOnGlobalList: Miniport %p\n", Miniport)); return Miniport; } ULONG NdisMGetDmaAlignment( IN NDIS_HANDLE MiniportAdapterHandle ) { PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; ASSERT(CURRENT_IRQL < DISPATCH_LEVEL); ASSERT(Miniport->SystemAdapterObject != NULL); if (Miniport->SystemAdapterObject) { return (Miniport->SystemAdapterObject->DmaOperations->GetDmaAlignment(Miniport->SystemAdapterObject)); } else { return 0; } } ULONG NdisGetSharedDataAlignment( VOID ) { return KeGetRecommendedSharedDataAlignment(); } VOID ndisDereferenceDmaAdapter( IN PNDIS_MINIPORT_BLOCK Miniport ) { PDMA_ADAPTER DmaAdapter; PPUT_DMA_ADAPTER putDmaAdapter; LONG DmaAdapterRefCount; KIRQL OldIrql; NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql); DmaAdapterRefCount = InterlockedDecrement(&Miniport->DmaAdapterRefCount); ASSERT(DmaAdapterRefCount >= 0); if (DmaAdapterRefCount == 0) { // // free the dma adapter // DmaAdapter = Miniport->SystemAdapterObject; ASSERT(DmaAdapter != NULL); if (DmaAdapter != NULL) { Miniport->SavedSystemAdapterObject = Miniport->SystemAdapterObject; putDmaAdapter = *DmaAdapter->DmaOperations->PutDmaAdapter; putDmaAdapter(DmaAdapter); Miniport->SystemAdapterObject = NULL; } if (Miniport->SGListLookasideList) { ExDeleteNPagedLookasideList(Miniport->SGListLookasideList); FREE_POOL(Miniport->SGListLookasideList); Miniport->SGListLookasideList = NULL; } if (Miniport->DmaResourcesReleasedEvent != NULL) { SET_EVENT(Miniport->DmaResourcesReleasedEvent); } } NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql); }