Beispiel #1
0
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;
}
Beispiel #2
0
/*
 * @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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
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
}
Beispiel #5
0
/*
 * @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);
}
Beispiel #6
0
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;
    }
}
Beispiel #7
0
/*
 * @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;
}
Beispiel #8
0
/*
 * @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;
}
Beispiel #9
0
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);
    }
}
Beispiel #10
0
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
}
Beispiel #11
0
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);
    }
}
Beispiel #12
0
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;
}
Beispiel #13
0
/*
 * @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;
}
Beispiel #14
0
/*
 * @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;
}
Beispiel #15
0
/*
 * @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;
}
Beispiel #16
0
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;
}
Beispiel #17
0
/*
 * @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;
  }
}
Beispiel #18
0
/*
 * @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;
}
Beispiel #19
0
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;
}
Beispiel #20
0
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);
}