BOOLEAN NTAPI ServiceRoutine( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext) /* * FUNCTION: Interrupt service routine * ARGUMENTS: * Interrupt = Pointer to interrupt object * ServiceContext = Pointer to context information (PNDIS_MINIPORT_INTERRUPT) * RETURNS * TRUE if a miniport controlled device generated the interrupt */ { BOOLEAN InterruptRecognized = FALSE; BOOLEAN QueueMiniportHandleInterrupt = FALSE; PNDIS_MINIPORT_INTERRUPT NdisInterrupt = ServiceContext; PNDIS_MINIPORT_BLOCK NdisMiniportBlock = NdisInterrupt->Miniport; BOOLEAN Initializing; NDIS_DbgPrint(MAX_TRACE, ("Called. Interrupt (0x%X)\n", NdisInterrupt)); /* Certain behavior differs if MiniportInitialize is executing when the interrupt is generated */ Initializing = (NdisMiniportBlock->PnPDeviceState != NdisPnPDeviceStarted); NDIS_DbgPrint(MAX_TRACE, ("MiniportInitialize executing: %s\n", (Initializing ? "yes" : "no"))); /* MiniportISR is always called for interrupts during MiniportInitialize */ if ((Initializing) || (NdisInterrupt->IsrRequested) || (NdisInterrupt->SharedInterrupt)) { NDIS_DbgPrint(MAX_TRACE, ("Calling MiniportISR\n")); (*NdisMiniportBlock->DriverHandle->MiniportCharacteristics.ISRHandler)( &InterruptRecognized, &QueueMiniportHandleInterrupt, NdisMiniportBlock->MiniportAdapterContext); } else if (NdisMiniportBlock->DriverHandle->MiniportCharacteristics.DisableInterruptHandler) { NDIS_DbgPrint(MAX_TRACE, ("Calling MiniportDisableInterrupt\n")); (*NdisMiniportBlock->DriverHandle->MiniportCharacteristics.DisableInterruptHandler)( NdisMiniportBlock->MiniportAdapterContext); QueueMiniportHandleInterrupt = TRUE; InterruptRecognized = TRUE; } /* TODO: Figure out if we should call this or not if Initializing is true. It appears * that calling it fixes some NICs, but documentation is contradictory on it. */ if (QueueMiniportHandleInterrupt) { NDIS_DbgPrint(MAX_TRACE, ("Queuing DPC.\n")); KeInsertQueueDpc(&NdisInterrupt->InterruptDpc, NULL, NULL); } NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n")); return InterruptRecognized; }
/* * @implemented */ VOID EXPORT NdisCompleteUnbindAdapter( IN NDIS_HANDLE UnbindAdapterContext, IN NDIS_STATUS Status) { /* We probably need to do more here but for now we just do * the opposite of what NdisCompleteBindAdapter does */ PROTOCOL_BINDING *Protocol = (PROTOCOL_BINDING *)UnbindAdapterContext; if (!NT_SUCCESS(Status)) { NDIS_DbgPrint(MIN_TRACE, ("Unbinding failed (%x)\n", Status)); return; } ExInterlockedRemoveEntryList(&Protocol->ListEntry, &ProtocolListLock); }
NTSTATUS NTAPI NdisIPwrQueryPower( IN PDEVICE_OBJECT DeviceObject, PIRP Irp) { PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension; PNET_PNP_EVENT PnPEvent; PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); ASSERT(Stack->Parameters.Power.Type == DevicePowerState); PnPEvent = ProSetupPnPEvent(NetEventQueryPower, &Stack->Parameters.Power.State, sizeof(NDIS_DEVICE_POWER_STATE)); if (!PnPEvent) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n")); return NDIS_STATUS_RESOURCES; } return ProSendAndFreePnPEvent(Adapter, PnPEvent, Irp); }
NDIS_STATUS NTAPI ProRequest( IN NDIS_HANDLE MacBindingHandle, IN PNDIS_REQUEST NdisRequest) /* * FUNCTION: Forwards a request to an NDIS miniport * ARGUMENTS: * MacBindingHandle = Adapter binding handle * NdisRequest = Pointer to request to perform * RETURNS: * Status of operation */ { PADAPTER_BINDING AdapterBinding; PLOGICAL_ADAPTER Adapter; PNDIS_REQUEST_MAC_BLOCK MacBlock = (PNDIS_REQUEST_MAC_BLOCK)NdisRequest->MacReserved; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); ASSERT(MacBindingHandle); AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle); ASSERT(AdapterBinding->Adapter); Adapter = AdapterBinding->Adapter; MacBlock->Binding = &AdapterBinding->NdisOpenBlock; #if WORKER_TEST MiniQueueWorkItem(Adapter, NdisWorkItemRequest, NdisRequest, FALSE); return NDIS_STATUS_PENDING; #else if (MiniIsBusy(Adapter, NdisWorkItemRequest)) { MiniQueueWorkItem(Adapter, NdisWorkItemRequest, NdisRequest, FALSE); return NDIS_STATUS_PENDING; } return MiniDoRequest(Adapter, NdisRequest); #endif }
/* * @implemented */ VOID EXPORT EthFilterDprIndicateReceive( IN PETH_FILTER Filter, IN NDIS_HANDLE MacReceiveContext, IN PCHAR Address, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookaheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize) /* * FUNCTION: Receive indication function for Ethernet devices * ARGUMENTS: * MiniportAdapter = Miniport Adapter Handle (PLOGICAL_ADAPTER) * MacReceiveContext = MAC receive context handle * Address = Pointer to destination Ethernet address * HeaderBuffer = Pointer to Ethernet header buffer * HeaderBufferSize = Size of Ethernet header buffer * LookaheadBuffer = Pointer to lookahead buffer * LookaheadBufferSize = Size of lookahead buffer * PacketSize = Total size of received packet */ { /* Not sure if this is a valid thing to do, but we do arrive here early * in the boot process with Filter NULL. We need to investigate whether * this should be handled or not allowed. */ if( !Filter ) { NDIS_DbgPrint(MIN_TRACE, ("Filter is NULL\n")); return; } MiniIndicateData((PLOGICAL_ADAPTER)((PETHI_FILTER)Filter)->Miniport, MacReceiveContext, HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize, PacketSize); }
BOOLEAN NTAPI EthCreateFilter( IN UINT MaximumMulticastAddresses, IN PUCHAR AdapterAddress, OUT PETH_FILTER * Filter) /* * FUNCTION: Construct an ethernet filter * ARGUMENTS: * MaximumMulticastAddresses: Maximum number of multicast adderesses. * AdapterAddress: Current ethernet address of the adapter. * Filter: The created filter on successful return. * RETURNS: * TRUE if the filter was created * FALSE otherwise * NOTE: * - This function is no longer exported and intentionally doesn't * follow the W2K prototype. It was deprecated since NDIS 4 so it * shouldn't be problem. */ { PETHI_FILTER NewFilter; NewFilter = ExAllocatePool(NonPagedPool, sizeof(ETHI_FILTER)); if (NewFilter != NULL) { RtlZeroMemory(NewFilter, sizeof(ETHI_FILTER)); NewFilter->MaxMulticastAddresses = MaximumMulticastAddresses; RtlCopyMemory(NewFilter->AdapterAddress, AdapterAddress, ETH_LENGTH_OF_ADDRESS); *Filter = (PETH_FILTER)NewFilter; return TRUE; } else { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n")); *Filter = NULL; return FALSE; } }
/* * @implemented */ VOID EXPORT NdisGetDriverHandle( IN PNDIS_HANDLE NdisBindingHandle, OUT PNDIS_HANDLE NdisDriverHandle) /* * FUNCTION: * ARGUMENTS: * NOTES: * NDIS 5.0 */ { PADAPTER_BINDING Binding = (PADAPTER_BINDING)NdisBindingHandle; if (!Binding) { NDIS_DbgPrint(MIN_TRACE, ("Bad binding handle\n")); *NdisDriverHandle = NULL; return; } *NdisDriverHandle = Binding->Adapter->NdisMiniportBlock.DriverHandle; }
/* * @implemented */ VOID EXPORT NdisOpenAdapter( OUT PNDIS_STATUS Status, OUT PNDIS_STATUS OpenErrorStatus, OUT PNDIS_HANDLE NdisBindingHandle, OUT PUINT SelectedMediumIndex, IN PNDIS_MEDIUM MediumArray, IN UINT MediumArraySize, IN NDIS_HANDLE NdisProtocolHandle, IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_STRING AdapterName, IN UINT OpenOptions, IN PSTRING AddressingInformation OPTIONAL) /* * FUNCTION: Opens an adapter for communication * ARGUMENTS: * Status = Address of buffer for status information * OpenErrorStatus = Address of buffer for secondary error code * NdisBindingHandle = Address of buffer for adapter binding handle * SelectedMediumIndex = Address of buffer for selected medium * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support * MediumArraySize = Number of elements in MediumArray * NdisProtocolHandle = Handle returned by NdisRegisterProtocol * ProtocolBindingContext = Pointer to caller suplied context area * AdapterName = Pointer to buffer with name of adapter * OpenOptions = Bitmask with flags passed to next-lower driver * AddressingInformation = Optional pointer to buffer with NIC specific information */ { UINT i; BOOLEAN Found; PLOGICAL_ADAPTER Adapter; PADAPTER_BINDING AdapterBinding; PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle); NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); if(!NdisProtocolHandle) { NDIS_DbgPrint(MIN_TRACE, ("NdisProtocolHandle is NULL\n")); *OpenErrorStatus = *Status = NDIS_STATUS_FAILURE; return; } Adapter = MiniLocateDevice(AdapterName); if (!Adapter) { NDIS_DbgPrint(MIN_TRACE, ("Adapter not found.\n")); *Status = NDIS_STATUS_ADAPTER_NOT_FOUND; return; } /* Find the media type in the list provided by the protocol driver */ Found = FALSE; for (i = 0; i < MediumArraySize; i++) { if (Adapter->NdisMiniportBlock.MediaType == MediumArray[i]) { *SelectedMediumIndex = i; Found = TRUE; break; } } if (!Found) { NDIS_DbgPrint(MIN_TRACE, ("Medium is not supported.\n")); *Status = NDIS_STATUS_UNSUPPORTED_MEDIA; return; } /* Now that we have confirmed that the adapter can be opened, create a binding */ AdapterBinding = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_BINDING)); if (!AdapterBinding) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); *Status = NDIS_STATUS_RESOURCES; return; } RtlZeroMemory(AdapterBinding, sizeof(ADAPTER_BINDING)); AdapterBinding->ProtocolBinding = Protocol; AdapterBinding->Adapter = Adapter; AdapterBinding->NdisOpenBlock.ProtocolBindingContext = ProtocolBindingContext; /* Set fields required by some NDIS macros */ AdapterBinding->NdisOpenBlock.BindingHandle = (NDIS_HANDLE)AdapterBinding; /* Set handlers (some NDIS macros require these) */ AdapterBinding->NdisOpenBlock.RequestHandler = ProRequest; AdapterBinding->NdisOpenBlock.ResetHandler = ProReset; AdapterBinding->NdisOpenBlock.SendHandler = ProSend; AdapterBinding->NdisOpenBlock.SendPacketsHandler = ProSendPackets; AdapterBinding->NdisOpenBlock.TransferDataHandler = ProTransferData; AdapterBinding->NdisOpenBlock.RequestCompleteHandler = Protocol->Chars.RequestCompleteHandler; /* Put on protocol's bound adapters list */ ExInterlockedInsertTailList(&Protocol->AdapterListHead, &AdapterBinding->ProtocolListEntry, &Protocol->Lock); /* Put protocol on adapter's bound protocols list */ NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n")); ExInterlockedInsertTailList(&Adapter->ProtocolListHead, &AdapterBinding->AdapterListEntry, &Adapter->NdisMiniportBlock.Lock); *NdisBindingHandle = (NDIS_HANDLE)AdapterBinding; *Status = NDIS_STATUS_SUCCESS; }
VOID NTAPI ndisBindMiniportsToProtocol(OUT PNDIS_STATUS Status, IN PPROTOCOL_BINDING Protocol) { /* * bind the protocol to all of its miniports * * open registry path * get list of devices from Bind key * call BindAdapterHandler for each */ OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING RegistryPath; WCHAR *RegistryPathStr, *DataPtr = NULL; NTSTATUS NtStatus; HANDLE DriverKeyHandle = NULL; PKEY_VALUE_PARTIAL_INFORMATION KeyInformation = NULL; PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics = &Protocol->Chars; UNICODE_STRING ValueName; ULONG ResultLength; PLIST_ENTRY CurrentEntry = NULL; RegistryPathStr = ExAllocatePoolWithTag(PagedPool, sizeof(SERVICES_KEY) + ProtocolCharacteristics->Name.Length + sizeof(LINKAGE_KEY), NDIS_TAG + __LINE__); if(!RegistryPathStr) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); *Status = NDIS_STATUS_RESOURCES; return; } wcscpy(RegistryPathStr, SERVICES_KEY); wcsncat(RegistryPathStr, ((WCHAR *)ProtocolCharacteristics->Name.Buffer), ProtocolCharacteristics->Name.Length / sizeof(WCHAR)); RegistryPathStr[wcslen(SERVICES_KEY)+ProtocolCharacteristics->Name.Length/sizeof(WCHAR)] = 0; wcscat(RegistryPathStr, LINKAGE_KEY); RtlInitUnicodeString(&RegistryPath, RegistryPathStr); NDIS_DbgPrint(MAX_TRACE, ("Opening configuration key: %wZ\n", &RegistryPath)); InitializeObjectAttributes(&ObjectAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); NtStatus = ZwOpenKey(&DriverKeyHandle, KEY_READ, &ObjectAttributes); ExFreePool(RegistryPathStr); if(NT_SUCCESS(NtStatus)) { NDIS_DbgPrint(MAX_TRACE, ("Successfully opened the registry configuration\n")); RtlInitUnicodeString(&ValueName, L"Bind"); NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, NULL, 0, &ResultLength); if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL && NtStatus != STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value for size\n")); ZwClose(DriverKeyHandle); } else { KeyInformation = ExAllocatePoolWithTag(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, NDIS_TAG + __LINE__); if(!KeyInformation) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); ZwClose(DriverKeyHandle); NtStatus = STATUS_NO_MEMORY; } else { NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, KeyInformation, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, &ResultLength); ZwClose(DriverKeyHandle); if(!NT_SUCCESS(NtStatus)) { NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value\n")); ExFreePool(KeyInformation); KeyInformation = NULL; } } } } if (!NT_SUCCESS(NtStatus)) { NDIS_DbgPrint(MID_TRACE, ("Performing global bind for protocol '%wZ'\n", &ProtocolCharacteristics->Name)); KeyInformation = NULL; CurrentEntry = AdapterListHead.Flink; } else { NDIS_DbgPrint(MID_TRACE, ("Performing standard bind for protocol '%wZ'\n", &ProtocolCharacteristics->Name)); DataPtr = (WCHAR*)KeyInformation->Data; } /* Assume success for now */ *Status = NDIS_STATUS_SUCCESS; while (TRUE) { /* BindContext is for tracking pending binding operations */ VOID *BindContext = 0; NDIS_STRING DeviceName; NDIS_STRING RegistryPath; WCHAR *RegistryPathStr = NULL; ULONG PathLength = 0; PLOGICAL_ADAPTER Adapter; if (KeyInformation) { /* Parse the REG_MULTI_SZ entry for device names */ if (!(*DataPtr)) break; RtlInitUnicodeString(&DeviceName, DataPtr); } else { /* Use the device name from the global adapter list */ if (CurrentEntry == &AdapterListHead) break; Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry); DeviceName = Adapter->NdisMiniportBlock.MiniportName; } /* Make sure the adapter has started */ if (!MiniLocateDevice(&DeviceName)) { /* It wasn't in the global miniport list, so skip the bind entry */ goto next; } /* Make sure this device isn't already bound to this protocol */ if (LocateAdapterBindingByName(Protocol, &DeviceName)) { /* It was already in this protocol's bound adapter list, so skip the bind entry */ goto next; } /* * RegistryPath should be: * \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip * * This is constructed as follows: * SERVICES_KEY + extracted device name + Protocol name from characteristics */ PathLength = sizeof(SERVICES_KEY) + /* \Registry\Machine\System\CurrentControlSet\Services\ */ wcslen( DeviceName.Buffer + 8 ) * sizeof(WCHAR) + /* Adapter1 (extracted from \Device\Adapter1) */ sizeof(PARAMETERS_KEY) + /* \Parameters\ */ ProtocolCharacteristics->Name.Length + sizeof(WCHAR); /* Tcpip */ RegistryPathStr = ExAllocatePool(PagedPool, PathLength); if(!RegistryPathStr) { NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n")); *Status = NDIS_STATUS_RESOURCES; break; } wcscpy(RegistryPathStr, SERVICES_KEY); wcscat(RegistryPathStr, DeviceName.Buffer + 8 ); wcscat(RegistryPathStr, PARAMETERS_KEY); wcsncat(RegistryPathStr, ProtocolCharacteristics->Name.Buffer, ProtocolCharacteristics->Name.Length / sizeof(WCHAR) ); RegistryPathStr[PathLength/sizeof(WCHAR) - 1] = 0; RtlInitUnicodeString(&RegistryPath, RegistryPathStr); NDIS_DbgPrint(MAX_TRACE, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n", &DeviceName, &RegistryPath)); { BIND_HANDLER BindHandler = ProtocolCharacteristics->BindAdapterHandler; if(BindHandler) { BindHandler(Status, BindContext, &DeviceName, &RegistryPath, 0); NDIS_DbgPrint(MID_TRACE, ("%wZ's BindAdapter handler returned 0x%x for %wZ\n", &ProtocolCharacteristics->Name, *Status, &DeviceName)); } else NDIS_DbgPrint(MID_TRACE, ("No protocol bind handler specified\n")); } next: if (KeyInformation) { /* Advance to the next adapter in the REG_MULTI_SZ */ DataPtr += (DeviceName.Length / sizeof(WCHAR)) + 1; } else { /* Advance to the next adapter in the global list */ CurrentEntry = CurrentEntry->Flink; } } if (KeyInformation) { ExFreePool(KeyInformation); } }
NDIS_STATUS proSendPacketToMiniport(PLOGICAL_ADAPTER Adapter, PNDIS_PACKET Packet) { #if WORKER_TEST MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, FALSE); return NDIS_STATUS_PENDING; #else KIRQL RaiseOldIrql; NDIS_STATUS NdisStatus; if(MiniIsBusy(Adapter, NdisWorkItemSend)) { MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, FALSE); return NDIS_STATUS_PENDING; } if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler) { if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE) { NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n")); (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)( Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1); NdisStatus = NDIS_STATUS_PENDING; } else { /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */ KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql); { NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n")); (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)( Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1); } KeLowerIrql(RaiseOldIrql); NdisStatus = NDIS_GET_PACKET_STATUS(Packet); if (NdisStatus == NDIS_STATUS_RESOURCES) { MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, TRUE); NdisStatus = NDIS_STATUS_PENDING; } } if (NdisStatus != NDIS_STATUS_PENDING) { MiniWorkItemComplete(Adapter, NdisWorkItemSend); } return NdisStatus; } else { if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE) { NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n")); NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)( Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, Packet->Private.Flags); NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n")); } else { /* Send is called at DISPATCH_LEVEL for all serialized miniports */ KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql); NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n")); NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)( Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, Packet->Private.Flags); NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n")); KeLowerIrql(RaiseOldIrql); if (NdisStatus == NDIS_STATUS_RESOURCES) { MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, TRUE); NdisStatus = NDIS_STATUS_PENDING; } } if (NdisStatus != NDIS_STATUS_PENDING) { MiniWorkItemComplete(Adapter, NdisWorkItemSend); } return NdisStatus; } #endif }
NDIS_STATUS NTAPI ProSend( IN NDIS_HANDLE MacBindingHandle, IN PNDIS_PACKET Packet) /* * FUNCTION: Forwards a request to send a packet to an NDIS miniport * ARGUMENTS: * MacBindingHandle = Adapter binding handle * Packet = Pointer to NDIS packet descriptor * RETURNS: * NDIS_STATUS_SUCCESS if the packet was successfully sent * NDIS_STATUS_PENDING if the miniport was busy or a serialized miniport returned NDIS_STATUS_RESOURCES */ { PADAPTER_BINDING AdapterBinding; PLOGICAL_ADAPTER Adapter; PNDIS_BUFFER NdisBuffer; PDMA_CONTEXT Context; NDIS_STATUS NdisStatus; UINT PacketLength; KIRQL OldIrql; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); ASSERT(MacBindingHandle); AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle); ASSERT(AdapterBinding); Adapter = AdapterBinding->Adapter; ASSERT(Adapter); /* if the following is not true, KeRaiseIrql() below will break */ ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); /* XXX what is this crazy black magic? */ Packet->Reserved[1] = (ULONG_PTR)MacBindingHandle; /* * Test the packet to see if it is a MAC loopback. * * We may have to loop this packet if miniport cannot. * If dest MAC address of packet == MAC address of adapter, * this is a loopback frame. */ if ((Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) && MiniAdapterHasAddress(Adapter, Packet)) { #if WORKER_TEST MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, Packet, FALSE); return NDIS_STATUS_PENDING; #else return ProIndicatePacket(Adapter, Packet); #endif } else { if (Adapter->NdisMiniportBlock.ScatterGatherListSize != 0) { NDIS_DbgPrint(MID_TRACE, ("Using Scatter/Gather DMA\n")); NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, &PacketLength); Context = ExAllocatePool(NonPagedPool, sizeof(DMA_CONTEXT)); if (!Context) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n")); return NDIS_STATUS_RESOURCES; } Context->Adapter = Adapter; Context->Packet = Packet; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KeFlushIoBuffers(NdisBuffer, FALSE, TRUE); NdisStatus = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->GetScatterGatherList( Adapter->NdisMiniportBlock.SystemAdapterObject, Adapter->NdisMiniportBlock.PhysicalDeviceObject, NdisBuffer, MmGetMdlVirtualAddress(NdisBuffer), PacketLength, ScatterGatherSendPacket, Context, TRUE); KeLowerIrql(OldIrql); if (!NT_SUCCESS(NdisStatus)) { NDIS_DbgPrint(MIN_TRACE, ("GetScatterGatherList failed! (%x)\n", NdisStatus)); return NdisStatus; } return NDIS_STATUS_PENDING; } return proSendPacketToMiniport(Adapter, Packet); } }
NDIS_STATUS ProIndicatePacket( PLOGICAL_ADAPTER Adapter, PNDIS_PACKET Packet) /* * FUNCTION: Indicates a packet to bound protocols * ARGUMENTS: * Adapter = Pointer to logical adapter * Packet = Pointer to packet to indicate * RETURNS: * STATUS_SUCCESS in all cases * NOTES: * - XXX ATM, this only handles loopback packets - is that its designed function? */ { UINT BufferedLength; UINT PacketLength; KIRQL OldIrql; PUCHAR LookaheadBuffer; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); #if DBG MiniDisplayPacket(Packet); #endif NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength); LookaheadBuffer = ExAllocatePool(NonPagedPool, PacketLength); if (!LookaheadBuffer) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n")); return NDIS_STATUS_RESOURCES; } NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n")); KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql); { BufferedLength = CopyPacketToBuffer(LookaheadBuffer, Packet, 0, PacketLength); Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = Packet; } KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); if (BufferedLength > Adapter->MediumHeaderSize) { /* XXX Change this to call SendPackets so we don't have to duplicate this wacky logic */ MiniIndicateData(Adapter, NULL, LookaheadBuffer, Adapter->MediumHeaderSize, &LookaheadBuffer[Adapter->MediumHeaderSize], BufferedLength - Adapter->MediumHeaderSize, PacketLength - Adapter->MediumHeaderSize); } else { MiniIndicateData(Adapter, NULL, LookaheadBuffer, Adapter->MediumHeaderSize, NULL, 0, 0); } ExFreePool(LookaheadBuffer); KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql); { Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = NULL; } KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); return NDIS_STATUS_SUCCESS; }
/* * @implemented */ NDIS_STATUS EXPORT NdisMRegisterIoPortRange( OUT PVOID *PortOffset, IN NDIS_HANDLE MiniportAdapterHandle, IN UINT InitialPort, IN UINT NumberOfPorts) /* * FUNCTION: Sets up driver access to device I/O ports * ARGUMENTS: * PortOffset = Address of buffer to place mapped base port address * MiniportAdapterHandle = Specifies handle input to MiniportInitialize * InitialPort = Bus-relative base port address of a range to be mapped * NumberOfPorts = Specifies number of ports to be mapped * RETURNS: * Status of operation */ { PHYSICAL_ADDRESS PortAddress, TranslatedAddress; PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle; ULONG AddressSpace = 1; /* FIXME The HAL handles this wrong atm */ *PortOffset = 0; NDIS_DbgPrint(MAX_TRACE, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x\n", InitialPort, NumberOfPorts)); memset(&PortAddress, 0, sizeof(PortAddress)); /* * FIXME: NDIS 5+ completely ignores the InitialPort parameter, but * we don't have a way to get the I/O base address yet (see * NDIS_MINIPORT_BLOCK->AllocatedResources and * NDIS_MINIPORT_BLOCK->AllocatedResourcesTranslated). */ if(InitialPort) PortAddress = RtlConvertUlongToLargeInteger(InitialPort); else ASSERT(FALSE); NDIS_DbgPrint(MAX_TRACE, ("Translating address 0x%x 0x%x\n", PortAddress.u.HighPart, PortAddress.u.LowPart)); if(!HalTranslateBusAddress(Adapter->NdisMiniportBlock.BusType, Adapter->NdisMiniportBlock.BusNumber, PortAddress, &AddressSpace, &TranslatedAddress)) { NDIS_DbgPrint(MIN_TRACE, ("Unable to translate address\n")); return NDIS_STATUS_RESOURCES; } NDIS_DbgPrint(MAX_TRACE, ("Hal returned AddressSpace=0x%x TranslatedAddress=0x%x 0x%x\n", AddressSpace, TranslatedAddress.u.HighPart, TranslatedAddress.u.LowPart)); if(AddressSpace) { ASSERT(TranslatedAddress.u.HighPart == 0); *PortOffset = (PVOID)(ULONG_PTR)TranslatedAddress.QuadPart; NDIS_DbgPrint(MAX_TRACE, ("Returning 0x%x\n", *PortOffset)); return NDIS_STATUS_SUCCESS; } NDIS_DbgPrint(MAX_TRACE, ("calling MmMapIoSpace\n")); *PortOffset = MmMapIoSpace(TranslatedAddress, NumberOfPorts, MmNonCached); NDIS_DbgPrint(MAX_TRACE, ("Returning 0x%x for port range\n", *PortOffset)); if(!*PortOffset) { NDIS_DbgPrint(MIN_TRACE, ("MmMapIoSpace failed\n")); return NDIS_STATUS_RESOURCES; } return NDIS_STATUS_SUCCESS; }
/* * @implemented */ NDIS_STATUS EXPORT NdisMAllocateMapRegisters( IN NDIS_HANDLE MiniportAdapterHandle, IN UINT DmaChannel, IN NDIS_DMA_SIZE DmaSize, IN ULONG BaseMapRegistersNeeded, IN ULONG MaximumBufferSize) /* * FUNCTION: Allocate map registers for use in DMA transfers * ARGUMENTS: * MiniportAdapterHandle: Passed in to MiniportInitialize * DmaChannel: DMA channel to use * DmaSize: bit width of DMA transfers * BaseMapRegistersNeeded: number of base map registers requested * MaximumBufferSize: largest single buffer transferred * RETURNS: * NDIS_STATUS_SUCCESS on success * NDIS_STATUS_RESOURCES on failure * NOTES: * - the win2k ddk and the nt4 ddk have conflicting prototypes for this. * I'm implementing the 2k one. * - do not confuse a "base map register" with a "map register" - they * are different. Only NDIS seems to use the base concept. The idea * is that a miniport supplies the number of base map registers it will * need, which is equal to the number of DMA send buffers it manages. * NDIS then allocates a number of map registers to go with each base * map register, so that a driver just has to send the base map register * number during dma operations and NDIS can find the group of real * map registers that represent the transfer. * - Because of the above sillyness, you can only specify a few base map * registers at most. a 1514-byte packet is two map registers at 4k * page size. * - NDIS limits the total number of allocated map registers to 64, * which (in the case of the above example) limits the number of base * map registers to 32. */ { DEVICE_DESCRIPTION Description; PDMA_ADAPTER AdapterObject = 0; UINT MapRegistersPerBaseRegister = 0; ULONG AvailableMapRegisters; NTSTATUS NtStatus; PLOGICAL_ADAPTER Adapter; PDEVICE_OBJECT DeviceObject = 0; KEVENT AllocationEvent; KIRQL OldIrql; NDIS_DbgPrint(MAX_TRACE, ("called: Handle 0x%x, DmaChannel 0x%x, DmaSize 0x%x, BaseMapRegsNeeded: 0x%x, MaxBuffer: 0x%x.\n", MiniportAdapterHandle, DmaChannel, DmaSize, BaseMapRegistersNeeded, MaximumBufferSize)); memset(&Description,0,sizeof(Description)); Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle; ASSERT(Adapter); /* only bus masters may call this routine */ if(!(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_BUS_MASTER)) { NDIS_DbgPrint(MIN_TRACE, ("Not a bus master\n")); return NDIS_STATUS_NOT_SUPPORTED; } DeviceObject = Adapter->NdisMiniportBlock.DeviceObject; KeInitializeEvent(&AllocationEvent, NotificationEvent, FALSE); Adapter->NdisMiniportBlock.AllocationEvent = &AllocationEvent; /* * map registers correlate to physical pages. ndis documents a * maximum of 64 map registers that it will return. * at 4k pages, a 1514-byte buffer can span not more than 2 pages. * * the number of registers required for a given physical mapping * is (first register + last register + one per page size), * given that physical mapping is > 2. */ /* unhandled corner case: {1,2}-byte max buffer size */ ASSERT(MaximumBufferSize > 2); MapRegistersPerBaseRegister = ((MaximumBufferSize-2) / (2*PAGE_SIZE)) + 2; Description.Version = DEVICE_DESCRIPTION_VERSION; Description.Master = TRUE; /* implied by calling this function */ Description.ScatterGather = TRUE; /* XXX UNTRUE: All BM DMA are S/G (ms seems to do this) */ Description.BusNumber = Adapter->NdisMiniportBlock.BusNumber; Description.InterfaceType = Adapter->NdisMiniportBlock.BusType; Description.DmaChannel = DmaChannel; Description.MaximumLength = MaximumBufferSize; if(DmaSize == NDIS_DMA_64BITS) Description.Dma64BitAddresses = TRUE; else if(DmaSize == NDIS_DMA_32BITS) Description.Dma32BitAddresses = TRUE; AdapterObject = IoGetDmaAdapter( Adapter->NdisMiniportBlock.PhysicalDeviceObject, &Description, &AvailableMapRegisters); if(!AdapterObject) { NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate an adapter object; bailing out\n")); return NDIS_STATUS_RESOURCES; } Adapter->NdisMiniportBlock.SystemAdapterObject = AdapterObject; if(AvailableMapRegisters < MapRegistersPerBaseRegister) { NDIS_DbgPrint(MIN_TRACE, ("Didn't get enough map registers from hal - requested 0x%x, got 0x%x\n", MapRegistersPerBaseRegister, AvailableMapRegisters)); AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject); Adapter->NdisMiniportBlock.SystemAdapterObject = NULL; return NDIS_STATUS_RESOURCES; } /* allocate & zero space in the miniport block for the registers */ Adapter->NdisMiniportBlock.MapRegisters = ExAllocatePool(NonPagedPool, BaseMapRegistersNeeded * sizeof(MAP_REGISTER_ENTRY)); if(!Adapter->NdisMiniportBlock.MapRegisters) { NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n")); AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject); Adapter->NdisMiniportBlock.SystemAdapterObject = NULL; return NDIS_STATUS_RESOURCES; } memset(Adapter->NdisMiniportBlock.MapRegisters, 0, BaseMapRegistersNeeded * sizeof(MAP_REGISTER_ENTRY)); Adapter->NdisMiniportBlock.BaseMapRegistersNeeded = (USHORT)BaseMapRegistersNeeded; while(BaseMapRegistersNeeded) { NDIS_DbgPrint(MAX_TRACE, ("iterating, basemapregistersneeded = %d\n", BaseMapRegistersNeeded)); BaseMapRegistersNeeded--; Adapter->NdisMiniportBlock.CurrentMapRegister = (USHORT)BaseMapRegistersNeeded; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); { NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel( AdapterObject, DeviceObject, MapRegistersPerBaseRegister, NdisBusMasterMapRegisterCallback, Adapter); } KeLowerIrql(OldIrql); if(!NT_SUCCESS(NtStatus)) { NDIS_DbgPrint(MIN_TRACE, ("IoAllocateAdapterChannel failed: 0x%x\n", NtStatus)); ExFreePool(Adapter->NdisMiniportBlock.MapRegisters); AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject); Adapter->NdisMiniportBlock.CurrentMapRegister = Adapter->NdisMiniportBlock.BaseMapRegistersNeeded = 0; Adapter->NdisMiniportBlock.SystemAdapterObject = NULL; return NDIS_STATUS_RESOURCES; } NDIS_DbgPrint(MAX_TRACE, ("waiting on event\n")); NtStatus = KeWaitForSingleObject(&AllocationEvent, Executive, KernelMode, FALSE, 0); if(!NT_SUCCESS(NtStatus)) { NDIS_DbgPrint(MIN_TRACE, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus)); ExFreePool(Adapter->NdisMiniportBlock.MapRegisters); AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject); Adapter->NdisMiniportBlock.CurrentMapRegister = Adapter->NdisMiniportBlock.BaseMapRegistersNeeded = 0; Adapter->NdisMiniportBlock.SystemAdapterObject = NULL; return NDIS_STATUS_RESOURCES; } NDIS_DbgPrint(MAX_TRACE, ("resetting event\n")); KeResetEvent(&AllocationEvent); } NDIS_DbgPrint(MAX_TRACE, ("returning success\n")); return NDIS_STATUS_SUCCESS; }
/* * @implemented */ VOID EXPORT NdisMSetupDmaTransfer(OUT PNDIS_STATUS Status, IN NDIS_HANDLE MiniportDmaHandle, IN PNDIS_BUFFER Buffer, IN ULONG Offset, IN ULONG Length, IN BOOLEAN WriteToDevice) { PNDIS_DMA_BLOCK DmaBlock = MiniportDmaHandle; NTSTATUS NtStatus; PLOGICAL_ADAPTER Adapter; KIRQL OldIrql; PDMA_ADAPTER AdapterObject; ULONG MapRegistersNeeded; NDIS_DbgPrint(MAX_TRACE, ("called: Handle 0x%x, Buffer 0x%x, Offset 0x%x, Length 0x%x, WriteToDevice 0x%x\n", MiniportDmaHandle, Buffer, Offset, Length, WriteToDevice)); Adapter = (PLOGICAL_ADAPTER)DmaBlock->Miniport; AdapterObject = (PDMA_ADAPTER)DmaBlock->SystemAdapterObject; MapRegistersNeeded = (Length + (PAGE_SIZE - 1)) / PAGE_SIZE; KeFlushIoBuffers(Buffer, !WriteToDevice, TRUE); KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); { NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel(AdapterObject, Adapter->NdisMiniportBlock.PhysicalDeviceObject, MapRegistersNeeded, NdisSubordinateMapRegisterCallback, Adapter); } KeLowerIrql(OldIrql); if(!NT_SUCCESS(NtStatus)) { NDIS_DbgPrint(MIN_TRACE, ("AllocateAdapterChannel failed: 0x%x\n", NtStatus)); AdapterObject->DmaOperations->FreeAdapterChannel(AdapterObject); *Status = NDIS_STATUS_RESOURCES; return; } NtStatus = KeWaitForSingleObject(&DmaBlock->AllocationEvent, Executive, KernelMode, FALSE, 0); if(!NT_SUCCESS(NtStatus)) { NDIS_DbgPrint(MIN_TRACE, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus)); AdapterObject->DmaOperations->FreeAdapterChannel(AdapterObject); *Status = NDIS_STATUS_RESOURCES; return; } /* We must throw away the return value of MapTransfer for a system DMA device */ AdapterObject->DmaOperations->MapTransfer(AdapterObject, Buffer, DmaBlock->MapRegisterBase, (PUCHAR)MmGetMdlVirtualAddress(Buffer) + Offset, &Length, WriteToDevice); NDIS_DbgPrint(MAX_TRACE, ("returning success\n")); *Status = NDIS_STATUS_SUCCESS; }
NDIS_STATUS NTAPI MiniportInitialize ( OUT PNDIS_STATUS OpenErrorStatus, OUT PUINT SelectedMediumIndex, IN PNDIS_MEDIUM MediumArray, IN UINT MediumArraySize, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE WrapperConfigurationContext ) { PRTL_ADAPTER adapter; NDIS_STATUS status; UINT i; PNDIS_RESOURCE_LIST resourceList; UINT resourceListSize; // // Make sure the medium is supported // for (i = 0; i < MediumArraySize; i++) { if (MediumArray[i] == NdisMedium802_3) { *SelectedMediumIndex = i; break; } } if (i == MediumArraySize) { NDIS_DbgPrint(MIN_TRACE, ("802.3 medium was not found in the medium array\n")); return NDIS_STATUS_UNSUPPORTED_MEDIA; } // // Allocate our adapter context // status = NdisAllocateMemoryWithTag((PVOID*)&adapter, sizeof(*adapter), ADAPTER_TAG); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate adapter context\n")); return NDIS_STATUS_RESOURCES; } RtlZeroMemory(adapter, sizeof(*adapter)); adapter->MiniportAdapterHandle = MiniportAdapterHandle; NdisAllocateSpinLock(&adapter->Lock); // // Notify NDIS of some characteristics of our NIC // NdisMSetAttributesEx(MiniportAdapterHandle, adapter, 0, NDIS_ATTRIBUTE_BUS_MASTER, NdisInterfacePci); // // Get our resources for IRQ and IO base information // resourceList = NULL; resourceListSize = 0; NdisMQueryAdapterResources(&status, WrapperConfigurationContext, resourceList, &resourceListSize); if (status != NDIS_STATUS_RESOURCES) { NDIS_DbgPrint(MIN_TRACE, ("Unexpected failure of NdisMQueryAdapterResources #1\n")); status = NDIS_STATUS_FAILURE; goto Cleanup; } status = NdisAllocateMemoryWithTag((PVOID*)&resourceList, resourceListSize, RESOURCE_LIST_TAG); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate resource list\n")); goto Cleanup; } NdisMQueryAdapterResources(&status, WrapperConfigurationContext, resourceList, &resourceListSize); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unexpected failure of NdisMQueryAdapterResources #2\n")); goto Cleanup; } ASSERT(resourceList->Version == 1); ASSERT(resourceList->Revision == 1); for (i = 0; i < resourceList->Count; i++) { switch (resourceList->PartialDescriptors[i].Type) { case CmResourceTypePort: ASSERT(adapter->IoRangeStart == 0); ASSERT(resourceList->PartialDescriptors[i].u.Port.Start.HighPart == 0); adapter->IoRangeStart = resourceList->PartialDescriptors[i].u.Port.Start.LowPart; adapter->IoRangeLength = resourceList->PartialDescriptors[i].u.Port.Length; NDIS_DbgPrint(MID_TRACE, ("I/O port range is %p to %p\n", adapter->IoRangeStart, adapter->IoRangeStart + adapter->IoRangeLength)); break; case CmResourceTypeInterrupt: ASSERT(adapter->InterruptVector == 0); ASSERT(adapter->InterruptLevel == 0); adapter->InterruptVector = resourceList->PartialDescriptors[i].u.Interrupt.Vector; adapter->InterruptLevel = resourceList->PartialDescriptors[i].u.Interrupt.Level; adapter->InterruptShared = (resourceList->PartialDescriptors[i].ShareDisposition == CmResourceShareShared); adapter->InterruptFlags = resourceList->PartialDescriptors[i].Flags; NDIS_DbgPrint(MID_TRACE, ("IRQ vector is %d\n", adapter->InterruptVector)); break; default: NDIS_DbgPrint(MIN_TRACE, ("Unrecognized resource type: 0x%x\n", resourceList->PartialDescriptors[i].Type)); break; } } NdisFreeMemory(resourceList, resourceListSize, 0); resourceList = NULL; if (adapter->IoRangeStart == 0 || adapter->InterruptVector == 0) { NDIS_DbgPrint(MIN_TRACE, ("Adapter didn't receive enough resources\n")); goto Cleanup; } // // Allocate the DMA resources // status = NdisMInitializeScatterGatherDma(MiniportAdapterHandle, FALSE, // RTL8139 only supports 32-bit addresses MAXIMUM_FRAME_SIZE); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to configure DMA\n")); goto Cleanup; } adapter->ReceiveBufferLength = FULL_RECEIVE_BUFFER_SIZE; NdisMAllocateSharedMemory(MiniportAdapterHandle, adapter->ReceiveBufferLength, FALSE, (PVOID*)&adapter->ReceiveBuffer, &adapter->ReceiveBufferPa); if (adapter->ReceiveBuffer == NULL) { NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive buffer\n")); status = NDIS_STATUS_RESOURCES; goto Cleanup; } NdisMAllocateSharedMemory(MiniportAdapterHandle, MINIMUM_FRAME_SIZE * TX_DESC_COUNT, FALSE, (PVOID*)&adapter->RuntTxBuffers, &adapter->RuntTxBuffersPa); if (adapter->RuntTxBuffers == NULL) { NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate runt TX buffer\n")); status = NDIS_STATUS_RESOURCES; goto Cleanup; } // // Register the I/O port range and configure the NIC // status = NdisMRegisterIoPortRange((PVOID*)&adapter->IoBase, MiniportAdapterHandle, adapter->IoRangeStart, adapter->IoRangeLength); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to register IO port range (0x%x)\n", status)); goto Cleanup; } // // Adapter setup // status = NICPowerOn(adapter); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to power on NIC (0x%x)\n", status)); goto Cleanup; } status = NICSoftReset(adapter); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to reset the NIC (0x%x)\n", status)); goto Cleanup; } status = NICGetPermanentMacAddress(adapter, adapter->PermanentMacAddress); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to get the fixed MAC address (0x%x)\n", status)); goto Cleanup; } RtlCopyMemory(adapter->CurrentMacAddress, adapter->PermanentMacAddress, IEEE_802_ADDR_LENGTH); // // Update link state and speed // NICUpdateLinkStatus(adapter); status = NICRegisterReceiveBuffer(adapter); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to setup receive buffer (0x%x)\n", status)); goto Cleanup; } // // We're ready to handle interrupts now // status = NdisMRegisterInterrupt(&adapter->Interrupt, MiniportAdapterHandle, adapter->InterruptVector, adapter->InterruptLevel, TRUE, // We always want ISR calls adapter->InterruptShared, (adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ? NdisInterruptLatched : NdisInterruptLevelSensitive); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to register interrupt (0x%x)\n", status)); goto Cleanup; } adapter->InterruptRegistered = TRUE; // // Enable interrupts on the NIC // adapter->InterruptMask = DEFAULT_INTERRUPT_MASK; status = NICApplyInterruptMask(adapter); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to apply interrupt mask (0x%x)\n", status)); goto Cleanup; } // // Turn on TX and RX now // status = NICEnableTxRx(adapter); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Unable to enable TX and RX (0x%x)\n", status)); goto Cleanup; } return NDIS_STATUS_SUCCESS; Cleanup: if (resourceList != NULL) { NdisFreeMemory(resourceList, resourceListSize, 0); } if (adapter != NULL) { MiniportHalt(adapter); } return status; }
/* * @implemented */ VOID EXPORT NdisRegisterProtocol( OUT PNDIS_STATUS Status, OUT PNDIS_HANDLE NdisProtocolHandle, IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics, IN UINT CharacteristicsLength) /* * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points * ARGUMENTS: * Status = Address of buffer for status information * NdisProtocolHandle = Address of buffer for handle used to identify the driver * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets * NOTES: * - you *must* set NdisProtocolHandle before doing anything that could wind up * getting BindAdapterHandler, as it will probably call OpenAdapter with this handle * - the above implies that the initialization of the protocol block must be complete * by then * TODO: * - break this function up - probably do a 'ndisRefreshProtocolBindings' function * - make this thing able to handle >1 protocol */ { PPROTOCOL_BINDING Protocol; NTSTATUS NtStatus; UINT MinSize; PNET_PNP_EVENT PnPEvent; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); *NdisProtocolHandle = NULL; /* first validate the PROTOCOL_CHARACTERISTICS */ switch (ProtocolCharacteristics->MajorNdisVersion) { case 0x03: /* we don't really want to support ndis3 drivers - so we complain for now */ NDIS_DbgPrint(MID_TRACE, ("NDIS 3 protocol attempting to register\n")); MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS); break; case 0x04: MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS); break; case 0x05: MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS); break; default: *Status = NDIS_STATUS_BAD_VERSION; NDIS_DbgPrint(MIN_TRACE, ("Incorrect characteristics size\n")); return; } if (CharacteristicsLength < MinSize) { NDIS_DbgPrint(MIN_TRACE, ("Bad protocol characteristics.\n")); *Status = NDIS_STATUS_BAD_CHARACTERISTICS; return; } /* set up the protocol block */ Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING)); if (!Protocol) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); *Status = NDIS_STATUS_RESOURCES; return; } RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING)); RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize); NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name, &ProtocolCharacteristics->Name, TRUE); if (!NT_SUCCESS(NtStatus)) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); ExFreePool(Protocol); *Status = NDIS_STATUS_RESOURCES; return; } KeInitializeSpinLock(&Protocol->Lock); InitializeListHead(&Protocol->AdapterListHead); /* We must set this before the call to ndisBindMiniportsToProtocol because the protocol's * BindAdapter handler might need it */ *NdisProtocolHandle = Protocol; ndisBindMiniportsToProtocol(Status, Protocol); /* Should we only send this if ndisBindMiniportsToProtocol succeeds? */ PnPEvent = ProSetupPnPEvent(NetEventBindsComplete, NULL, 0); if (PnPEvent) { if (Protocol->Chars.PnPEventHandler) { /* We call this with a NULL binding context because it affects all bindings */ NtStatus = (*Protocol->Chars.PnPEventHandler)(NULL, PnPEvent); /* FIXME: We don't support this yet */ ASSERT(NtStatus != NDIS_STATUS_PENDING); } ExFreePool(PnPEvent); } if (*Status == NDIS_STATUS_SUCCESS) { ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock); } else { NDIS_DbgPrint(MIN_TRACE, ("Binding failed (%x)\n", *Status)); ExFreePool(Protocol); *NdisProtocolHandle = NULL; } }
/* * @implemented */ NDIS_STATUS EXPORT NdisMRegisterInterrupt( OUT PNDIS_MINIPORT_INTERRUPT Interrupt, IN NDIS_HANDLE MiniportAdapterHandle, IN UINT InterruptVector, IN UINT InterruptLevel, IN BOOLEAN RequestIsr, IN BOOLEAN SharedInterrupt, IN NDIS_INTERRUPT_MODE InterruptMode) /* * FUNCTION: Claims access to an interrupt vector * ARGUMENTS: * Interrupt = Address of interrupt object to initialize * MiniportAdapterHandle = Specifies handle input to MiniportInitialize * InterruptVector = Specifies bus-relative vector to register * InterruptLevel = Specifies bus-relative DIRQL vector for interrupt * RequestIsr = TRUE if MiniportISR should always be called * SharedInterrupt = TRUE if other devices may use the same interrupt * InterruptMode = Specifies type of interrupt * RETURNS: * Status of operation */ { NTSTATUS Status; ULONG MappedIRQ; KIRQL DIrql; KAFFINITY Affinity; PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle; NDIS_DbgPrint(MAX_TRACE, ("Called. InterruptVector (0x%X) InterruptLevel (0x%X) " "SharedInterrupt (%d) InterruptMode (0x%X)\n", InterruptVector, InterruptLevel, SharedInterrupt, InterruptMode)); RtlZeroMemory(Interrupt, sizeof(NDIS_MINIPORT_INTERRUPT)); KeInitializeSpinLock(&Interrupt->DpcCountLock); KeInitializeDpc(&Interrupt->InterruptDpc, HandleDeferredProcessing, Adapter); KeInitializeEvent(&Interrupt->DpcsCompletedEvent, NotificationEvent, FALSE); Interrupt->SharedInterrupt = SharedInterrupt; Interrupt->IsrRequested = RequestIsr; Interrupt->Miniport = &Adapter->NdisMiniportBlock; MappedIRQ = HalGetInterruptVector(Adapter->NdisMiniportBlock.BusType, Adapter->NdisMiniportBlock.BusNumber, InterruptLevel, InterruptVector, &DIrql, &Affinity); NDIS_DbgPrint(MAX_TRACE, ("Connecting to interrupt vector (0x%X) Affinity (0x%X).\n", MappedIRQ, Affinity)); Status = IoConnectInterrupt(&Interrupt->InterruptObject, ServiceRoutine, Interrupt, &Interrupt->DpcCountLock, MappedIRQ, DIrql, DIrql, InterruptMode, SharedInterrupt, Affinity, FALSE); NDIS_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X).\n", Status)); if (NT_SUCCESS(Status)) { Adapter->NdisMiniportBlock.Interrupt = Interrupt; Adapter->NdisMiniportBlock.RegisteredInterrupts++; return NDIS_STATUS_SUCCESS; } if (Status == STATUS_INSUFFICIENT_RESOURCES) { /* FIXME: Log error */ NDIS_DbgPrint(MIN_TRACE, ("Resource conflict!\n")); return NDIS_STATUS_RESOURCE_CONFLICT; } NDIS_DbgPrint(MIN_TRACE, ("Function failed. Status (0x%X).\n", Status)); return NDIS_STATUS_FAILURE; }
NDIS_STATUS NTAPI MiniportSend ( IN NDIS_HANDLE MiniportAdapterContext, IN PNDIS_PACKET Packet, IN UINT Flags ) { PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext; NDIS_STATUS status; PSCATTER_GATHER_LIST sgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo); ULONG transmitLength; ULONG transmitBuffer; PNDIS_BUFFER firstBuffer; PVOID firstBufferVa; UINT firstBufferLength, totalBufferLength; PUCHAR runtBuffer; ASSERT(sgList != NULL); ASSERT(sgList->NumberOfElements == 1); ASSERT(sgList->Elements[0].Address.HighPart == 0); ASSERT((sgList->Elements[0].Address.LowPart & 3) == 0); ASSERT(sgList->Elements[0].Length <= MAXIMUM_FRAME_SIZE); NDIS_DbgPrint(MAX_TRACE, ("Sending %d byte packet\n", sgList->Elements[0].Length)); NdisAcquireSpinLock(&adapter->Lock); if (adapter->TxFull) { NDIS_DbgPrint(MIN_TRACE, ("All TX descriptors are full\n")); NdisReleaseSpinLock(&adapter->Lock); return NDIS_STATUS_RESOURCES; } NDIS_DbgPrint(MAX_TRACE, ("Sending packet on TX desc %d\n", adapter->CurrentTxDesc)); // // If this is a runt, we need to pad it manually for the RTL8139 // if (sgList->Elements[0].Length < MINIMUM_FRAME_SIZE) { transmitLength = MINIMUM_FRAME_SIZE; transmitBuffer = adapter->RuntTxBuffersPa.LowPart + (MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc); NdisGetFirstBufferFromPacketSafe(Packet, &firstBuffer, &firstBufferVa, &firstBufferLength, &totalBufferLength, NormalPagePriority); if (firstBufferVa == NULL) { NDIS_DbgPrint(MIN_TRACE, ("Unable to get buffer from packet\n")); NdisReleaseSpinLock(&adapter->Lock); return NDIS_STATUS_RESOURCES; } ASSERT(firstBufferLength == totalBufferLength); runtBuffer = adapter->RuntTxBuffers + (MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc); RtlCopyMemory(runtBuffer, firstBufferVa, firstBufferLength); RtlFillMemory(runtBuffer + firstBufferLength, MINIMUM_FRAME_SIZE - firstBufferLength, 0x00); } else { transmitLength = sgList->Elements[0].Length; transmitBuffer = sgList->Elements[0].Address.LowPart; } status = NICTransmitPacket(adapter, adapter->CurrentTxDesc, transmitBuffer, transmitLength); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Transmit packet failed\n")); NdisReleaseSpinLock(&adapter->Lock); return status; } adapter->CurrentTxDesc++; adapter->CurrentTxDesc %= TX_DESC_COUNT; if (adapter->CurrentTxDesc == adapter->DirtyTxDesc) { NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n")); adapter->TxFull = TRUE; } NdisReleaseSpinLock(&adapter->Lock); return NDIS_STATUS_SUCCESS; }
VOID NTAPI MiniportHandleInterrupt ( IN NDIS_HANDLE MiniportAdapterContext ) { PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext; ULONG txStatus; UCHAR command; PPACKET_HEADER nicHeader; PETH_HEADER ethHeader; NdisDprAcquireSpinLock(&adapter->Lock); NDIS_DbgPrint(MAX_TRACE, ("Interrupts pending: 0x%x\n", adapter->InterruptPending)); // // Handle a link change // if (adapter->LinkChange) { NdisDprReleaseSpinLock(&adapter->Lock); NdisMIndicateStatus(adapter->MiniportAdapterHandle, adapter->MediaState == NdisMediaStateConnected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0); NdisMIndicateStatusComplete(adapter->MiniportAdapterHandle); NdisDprAcquireSpinLock(&adapter->Lock); adapter->LinkChange = FALSE; } // // Handle a TX interrupt // if (adapter->InterruptPending & (R_I_TXOK | R_I_TXERR)) { while (adapter->TxFull || adapter->DirtyTxDesc != adapter->CurrentTxDesc) { NdisRawReadPortUlong(adapter->IoBase + R_TXSTS0 + (adapter->DirtyTxDesc * sizeof(ULONG)), &txStatus); if (!(txStatus & (R_TXS_STATOK | R_TXS_UNDERRUN | R_TXS_ABORTED))) { // // Not sent yet // break; } NDIS_DbgPrint(MAX_TRACE, ("Transmission for desc %d complete: 0x%x\n", adapter->DirtyTxDesc, txStatus)); if (txStatus & R_TXS_STATOK) { adapter->TransmitOk++; } else { adapter->TransmitError++; } adapter->DirtyTxDesc++; adapter->DirtyTxDesc %= TX_DESC_COUNT; adapter->InterruptPending &= ~(R_I_TXOK | R_I_TXERR); adapter->TxFull = FALSE; } } // // Handle a good RX interrupt // if (adapter->InterruptPending & (R_I_RXOK | R_I_RXERR)) { for (;;) { NdisRawReadPortUchar(adapter->IoBase + R_CMD, &command); if (command & R_CMD_RXEMPTY) { // // The buffer is empty // adapter->InterruptPending &= ~(R_I_RXOK | R_I_RXERR); break; } adapter->ReceiveOffset %= RECEIVE_BUFFER_SIZE; NDIS_DbgPrint(MAX_TRACE, ("Looking for a packet at offset 0x%x\n", adapter->ReceiveOffset)); nicHeader = (PPACKET_HEADER)(adapter->ReceiveBuffer + adapter->ReceiveOffset); if (!(nicHeader->Status & RSR_ROK)) { // // Receive failed // NDIS_DbgPrint(MIN_TRACE, ("Receive failed: 0x%x\n", nicHeader->Status)); if (nicHeader->Status & RSR_FAE) { adapter->ReceiveAlignmentError++; } else if (nicHeader->Status & RSR_CRC) { adapter->ReceiveCrcError++; } adapter->ReceiveError++; goto NextPacket; } NDIS_DbgPrint(MAX_TRACE, ("Indicating %d byte packet to NDIS\n", nicHeader->PacketLength - RECV_CRC_LENGTH)); ethHeader = (PETH_HEADER)(nicHeader + 1); NdisMEthIndicateReceive(adapter->MiniportAdapterHandle, NULL, (PVOID)(ethHeader), sizeof(ETH_HEADER), (PVOID)(ethHeader + 1), nicHeader->PacketLength - sizeof(ETH_HEADER) - RECV_CRC_LENGTH, nicHeader->PacketLength - sizeof(ETH_HEADER) - RECV_CRC_LENGTH); adapter->ReceiveOk++; NextPacket: adapter->ReceiveOffset += nicHeader->PacketLength + sizeof(PACKET_HEADER); adapter->ReceiveOffset = (adapter->ReceiveOffset + 3) & ~3; NdisRawWritePortUshort(adapter->IoBase + R_CAPR, adapter->ReceiveOffset - 0x10); if (adapter->InterruptPending & (R_I_RXOVRFLW | R_I_FIFOOVR)) { // // We can only clear these interrupts once CAPR has been reset // NdisRawWritePortUshort(adapter->IoBase + R_IS, R_I_RXOVRFLW | R_I_FIFOOVR); adapter->InterruptPending &= ~(R_I_RXOVRFLW | R_I_FIFOOVR); } } NdisMEthIndicateReceiveComplete(adapter->MiniportAdapterHandle); } NdisDprReleaseSpinLock(&adapter->Lock); }