Beispiel #1
0
NTSTATUS
NICStartSend(
    __in  PFDO_DATA  FdoData,
    __in  PMP_TCB    pMpTcb
    )
/*++
Routine Description:

    Issue a send command to the NIC
    Assumption: Send spinlock has been acquired

Arguments:

    FdoData     Pointer to our FdoData
    pMpTcb      Pointer to MP_TCB

Return Value:

    NTSTATUS code

--*/
{
    NTSTATUS     status;

    DebugPrint(TRACE, DBG_WRITE, "--> NICStartSend\n");

    //
    // If the transmit unit is idle (very first transmit) then we must
    // setup the general pointer and issue a full CU-start
    //
    if (FdoData->TransmitIdle)
    {

        DebugPrint(TRACE, DBG_WRITE, "CU is idle -- First TCB added to Active List\n");

        //
        // Wait for the SCB to clear before we set the general pointer
        //
        if (!WaitScb(FdoData))
        {
            DebugPrint(ERROR, DBG_WRITE, "NICStartSend -- WaitScb returned error\n");
            status = STATUS_DEVICE_DATA_ERROR;
            goto exit;
        }

        //
        // Don't try to start the transmitter if the command unit is not
        // idle ((not idle) == (Cu-Suspended or Cu-Active)).
        //
        if ((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_IDLE)
        {
            DebugPrint(ERROR, DBG_WRITE, "FdoData = %p, CU Not IDLE\n", FdoData);
            MP_SET_HARDWARE_ERROR(FdoData);
            KeStallExecutionProcessor(25);
        }

        FdoData->CSRAddress->ScbGeneralPointer = pMpTcb->HwTcbPhys;

        status = D100IssueScbCommand(FdoData, SCB_CUC_START, FALSE);

        FdoData->TransmitIdle = FALSE;
        FdoData->ResumeWait = TRUE;
    }
    else
    {
        //
        // If the command unit has already been started, then append this
        // TCB onto the end of the transmit chain, and issue a CU-Resume.
        //
        DebugPrint(LOUD, DBG_WRITE, "adding TCB to Active chain\n");

        //
        // Clear the suspend bit on the previous packet.
        //
        pMpTcb->PrevHwTcb->TxCbHeader.CbCommand &= ~CB_S_BIT;

        //
        // Issue a CU-Resume command to the device.  We only need to do a
        // WaitScb if the last command was NOT a RESUME.
        //
        status = D100IssueScbCommand(FdoData, SCB_CUC_RESUME, FdoData->ResumeWait);
    }

    exit:

    DebugPrint(TRACE, DBG_WRITE, "<-- NICStartSend\n");

    return status;
}
Beispiel #2
0
NTSTATUS
NICSetMulticastList(
    PFDO_DATA  FdoData
    )
/*++
Routine Description:

    This routine will set up the FdoData for a specified multicast address list

Arguments:

    FdoData     Pointer to our FdoData

Return Value:


--*/
{
    NTSTATUS        status;
    PUCHAR          McAddress;
    UINT            i, j;
    BOOLEAN         bResult;

    DebugPrint(TRACE, DBG_IOCTLS, "--> NICSetMulticastList\n");

    //
    // Setup the command block for the multicast command.
    //
    for (i = 0; i < FdoData->MCAddressCount; i++)
    {
        DebugPrint(TRACE, DBG_IOCTLS, "MC(%d) = %02x-%02x-%02x-%02x-%02x-%02x\n",
            i,
            FdoData->MCList[i][0],
            FdoData->MCList[i][1],
            FdoData->MCList[i][2],
            FdoData->MCList[i][3],
            FdoData->MCList[i][4],
            FdoData->MCList[i][5]);

        McAddress = &FdoData->NonTxCmdBlock->NonTxCb.Multicast.McAddress[i*ETHERNET_ADDRESS_LENGTH];

        for (j = 0; j < ETH_LENGTH_OF_ADDRESS; j++)
            *(McAddress++) = FdoData->MCList[i][j];
    }

    FdoData->NonTxCmdBlock->NonTxCb.Multicast.McCount =
        (USHORT)(FdoData->MCAddressCount * ETH_LENGTH_OF_ADDRESS);
    ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus = 0;
    ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbCommand = CB_MULTICAST;

    //
    // Wait for the SCB to clear before we check the CU status.
    //
    if (!WaitScb(FdoData))
    {
        status = STATUS_DEVICE_DATA_ERROR;
        MP_EXIT;
    }

    //
    // If we have issued any transmits, then the CU will either be active, or
    // in the suspended state.  If the CU is active, then we wait for it to be
    // suspended.
    //
    if (FdoData->TransmitIdle == FALSE)
    {
        //
        // Wait for suspended state
        //
        MP_STALL_AND_WAIT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult);
        if (!bResult)
        {
            MP_SET_HARDWARE_ERROR(FdoData);
            status = STATUS_DEVICE_DATA_ERROR;
        }

        //
        // Restore the transmit software flags.  After the multicast command is
        // issued, the command unit will be idle, because the EL bit will be
        // set in the multicast commmand block.
        //
        FdoData->TransmitIdle = TRUE;
        FdoData->ResumeWait = TRUE;
    }

    //
    // Update the command list pointer.
    //
    FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys;

    //
    // Submit the multicast command to the FdoData and wait for it to complete.
    //
    status = D100SubmitCommandBlockAndWait(FdoData);
    if (status != STATUS_SUCCESS)
    {
        status = STATUS_DEVICE_NOT_READY;
    }

    exit:

    DebugPrint(TRACE, DBG_IOCTLS, "<-- NICSetMulticastList, status=%x\n", status);

    return(status);

}
Beispiel #3
0
NTSTATUS NICSetPacketFilter(
    __in PFDO_DATA    FdoData,
    __in ULONG        PacketFilter
    )
/*++
Routine Description:

    This routine will set up the FdoData so that it accepts packets
    that match the specified packet filter.  The only filter bits
    that can truly be toggled are for broadcast and promiscuous

Arguments:

    FdoData         Pointer to our FdoData
    PacketFilter    The new packet filter

Return Value:


--*/
{
    NTSTATUS        status = STATUS_SUCCESS;
    UCHAR           NewParameterField;
    UINT            i;
    BOOLEAN         bResult;

    DebugPrint(TRACE, DBG_IOCTLS, "--> NICSetPacketFilter, PacketFilter=%08x\n", PacketFilter);

    //
    // Need to enable or disable broadcast and promiscuous support depending
    // on the new filter
    //
    NewParameterField = CB_557_CFIG_DEFAULT_PARM15;

    if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
    {
        NewParameterField &= ~CB_CFIG_BROADCAST_DIS;
    }
    else
    {
        NewParameterField |= CB_CFIG_BROADCAST_DIS;
    }

    if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
    {
        NewParameterField |= CB_CFIG_PROMISCUOUS;
    }
    else
    {
        NewParameterField &= ~CB_CFIG_PROMISCUOUS;
    }

    do
    {
        if ((FdoData->OldParameterField == NewParameterField ) &&
            !(PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST))
        {
            break;
        }

        //
        // Only need to do something to the HW if the filter bits have changed.
        //
        FdoData->OldParameterField = NewParameterField;
        ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbCommand = CB_CONFIGURE;
        ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus = 0;
        ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbLinkPointer = DRIVER_NULL;

        //
        // First fill in the static (end user can't change) config bytes
        //
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[0] = CB_557_CFIG_DEFAULT_PARM0;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[2] = CB_557_CFIG_DEFAULT_PARM2;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] = CB_557_CFIG_DEFAULT_PARM3;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[6] = CB_557_CFIG_DEFAULT_PARM6;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[9] = CB_557_CFIG_DEFAULT_PARM9;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[10] = CB_557_CFIG_DEFAULT_PARM10;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[11] = CB_557_CFIG_DEFAULT_PARM11;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[12] = CB_557_CFIG_DEFAULT_PARM12;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[13] = CB_557_CFIG_DEFAULT_PARM13;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[14] = CB_557_CFIG_DEFAULT_PARM14;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[16] = CB_557_CFIG_DEFAULT_PARM16;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[17] = CB_557_CFIG_DEFAULT_PARM17;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[18] = CB_557_CFIG_DEFAULT_PARM18;
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[20] = CB_557_CFIG_DEFAULT_PARM20;

        //
        // Set the Tx underrun retries
        //
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[7] =
            (UCHAR) (CB_557_CFIG_DEFAULT_PARM7 | (FdoData->AiUnderrunRetry << 1));

        //
        // Set the Tx and Rx Fifo limits
        //
        FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[1] =
            (UCHAR) ((FdoData->AiTxFifo << 4) | FdoData->AiRxFifo);

        //
        // set the MWI enable bit if needed
        //
        if (FdoData->MWIEnable)
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] |= CB_CFIG_B3_MWI_ENABLE;

        //
        // Set the Tx and Rx DMA maximum byte count fields.
        //
        if ((FdoData->AiRxDmaCount) || (FdoData->AiTxDmaCount))
        {
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] =
                FdoData->AiRxDmaCount;
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] =
                (UCHAR) (FdoData->AiTxDmaCount | CB_CFIG_DMBC_EN);
        }
        else
        {
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] =
                CB_557_CFIG_DEFAULT_PARM4;
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] =
                CB_557_CFIG_DEFAULT_PARM5;
        }

        //
        // Setup for MII or 503 operation.  The CRS+CDT bit should only be
        // set when operating in 503 mode.
        //
        if (FdoData->PhyAddress == 32)
        {
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] =
                (CB_557_CFIG_DEFAULT_PARM8 & (~CB_CFIG_503_MII));
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] =
                (UCHAR) (NewParameterField | CB_CFIG_CRS_OR_CDT);
        }
        else
        {
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] =
                (CB_557_CFIG_DEFAULT_PARM8 | CB_CFIG_503_MII);
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] =
                (UCHAR) (NewParameterField & (~CB_CFIG_CRS_OR_CDT));
        }

        //
        // Setup Full duplex stuff
        //

        //
        // If forced to half duplex
        //
        if (FdoData->AiForceDpx == 1)
        {
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
                (CB_557_CFIG_DEFAULT_PARM19 &
                (~(CB_CFIG_FORCE_FDX| CB_CFIG_FDX_ENABLE)));
        }
        //
        // If forced to full duplex
        //
        else if (FdoData->AiForceDpx == 2)
        {
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
                (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX);
        }
        //
        // If auto-duplex
        //
        else
        {
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
                                                CB_557_CFIG_DEFAULT_PARM19;
        }

        //
        // if multicast all is being turned on, set the bit
        //
        if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
        {
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] =
                                 (CB_557_CFIG_DEFAULT_PARM21 | CB_CFIG_MULTICAST_ALL);
        }
        else
        {
            FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] =
                                                CB_557_CFIG_DEFAULT_PARM21;
        }


        //
        // Wait for the SCB to clear before we check the CU status.
        //
        if (!WaitScb(FdoData))
        {
            status = STATUS_DEVICE_DATA_ERROR;
            break;
        }

        //
        // If we have issued any transmits, then the CU will either be active,
        // or in the suspended state.  If the CU is active, then we wait for
        // it to be suspended.
        //
        if (FdoData->TransmitIdle == FALSE)
        {
            //
            // Wait for suspended state
            //
            MP_STALL_AND_WAIT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult);
            if (!bResult)
            {
                MP_SET_HARDWARE_ERROR(FdoData);
                status = STATUS_DEVICE_DATA_ERROR;
                break;
            }

            //
            // Check the current status of the receive unit
            //
            if ((FdoData->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE)
            {
                // Issue an RU abort.  Since an interrupt will be issued, the
                // RU will be started by the DPC.
                status = D100IssueScbCommand(FdoData, SCB_RUC_ABORT, TRUE);
                if (status != STATUS_SUCCESS)
                {
                    break;
                }
            }

            if (!WaitScb(FdoData))
            {
                status = STATUS_DEVICE_DATA_ERROR;
                break;
            }

            //
            // Restore the transmit software flags.  After the multicast
            // command is issued, the command unit will be idle, because the
            // EL bit will be set in the multicast commmand block.
            //
            FdoData->TransmitIdle = TRUE;
            FdoData->ResumeWait = TRUE;
        }

        //
        // Display config info
        //
        DebugPrint(TRACE, DBG_IOCTLS, "Re-Issuing Configure command for filter change\n");
        DebugPrint(TRACE, DBG_IOCTLS, "Config Block at virt addr %p, phys address %x\n",
            &((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus, FdoData->NonTxCmdBlockPhys);

        for (i = 0; i < CB_CFIG_BYTE_COUNT; i++)
            DebugPrint(LOUD, DBG_IOCTLS, "  Config byte %x = %.2x\n", i, FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[i]);

        //
        // Submit the configure command to the chip, and wait for it to complete.
        //
        FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys;
        status = D100SubmitCommandBlockAndWait(FdoData);
        if (status != STATUS_SUCCESS)
        {
            status = STATUS_DEVICE_NOT_READY;
        }

    } while (FALSE);

    DebugPrint(TRACE, DBG_IOCTLS, "<-- NICSetPacketFilter, Status=%x\n", status);

    return(status);
}
Beispiel #4
0
NTSTATUS
NICLinkDetection(
    PFDO_DATA         FdoData
    )
/*++

Routine Description:

    Timer function for postponed link negotiation. Called from
    the NICWatchDogEvtTimerFunc. After the link detection is over
    we will complete any pending ioctl or send IRPs.

Arguments:

    FdoData     Pointer to our FdoData

Return Value:

    NT status

--*/
{
    NTSTATUS                status = STATUS_SUCCESS;
    MEDIA_STATE             CurrMediaState;
    PNDISPROT_QUERY_OID     pQuery = NULL;
    PNDISPROT_SET_OID       pSet = NULL;
    PVOID                   DataBuffer;
    ULONG                   BytesWritten;
    NDIS_OID                Oid;
    PVOID                   InformationBuffer;
    size_t               bufSize;
    WDFREQUEST              request;

    //
    // Handle the link negotiation.
    //
    if (FdoData->bLinkDetectionWait)
    {
        status = ScanAndSetupPhy(FdoData);
    }
    else
    {
        status = PhyDetect(FdoData);
    }

    if (status == STATUS_PENDING)
    {
        return status;
    }

    //
    // Reset some variables for link detection
    //
    FdoData->bLinkDetectionWait = FALSE;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "NICLinkDetection - negotiation done\n");


    WdfSpinLockAcquire(FdoData->Lock);
    MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION);

    WdfSpinLockRelease(FdoData->Lock);

    //
    // Any OID query request pending?
    //

    status = NICGetIoctlRequest(FdoData->PendingIoctlQueue,
                                IOCTL_NDISPROT_QUERY_OID_VALUE,
                                &request);

    if(NT_SUCCESS(status)) {
        status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_QUERY_OID), &DataBuffer, &bufSize);
        if(NT_SUCCESS(status)) {

            pQuery = (PNDISPROT_QUERY_OID)DataBuffer;
            Oid = pQuery->Oid;
            InformationBuffer = &pQuery->Data[0];
            switch(Oid)
            {
                case OID_GEN_LINK_SPEED:
                    *((PULONG)InformationBuffer) = FdoData->usLinkSpeed * 10000;
                    BytesWritten = sizeof(ULONG);

                    break;

                case OID_GEN_MEDIA_CONNECT_STATUS:
                default:
                    ASSERT(Oid == OID_GEN_MEDIA_CONNECT_STATUS);

                    CurrMediaState = NICIndicateMediaState(FdoData);

                    RtlMoveMemory(InformationBuffer,
                                  &CurrMediaState,
                                  sizeof(NDIS_MEDIA_STATE));

                    BytesWritten = sizeof(NDIS_MEDIA_STATE);
            }

            WdfRequestCompleteWithInformation(request, status, BytesWritten);
        }
    }

    //
    // Any OID set request pending?
    //
    status = NICGetIoctlRequest(FdoData->PendingIoctlQueue,
                            IOCTL_NDISPROT_SET_OID_VALUE,
                             &request);

    if(NT_SUCCESS(status)) {
        ULONG    PacketFilter;

        status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_SET_OID), &DataBuffer, &bufSize);
        if(NT_SUCCESS(status)) {

            pSet = (PNDISPROT_SET_OID)DataBuffer;
            Oid = pSet->Oid;
            InformationBuffer = &pSet->Data[0];
            if (Oid == OID_GEN_CURRENT_PACKET_FILTER)
            {

                RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG));


                WdfSpinLockAcquire(FdoData->Lock);

                status = NICSetPacketFilter(
                             FdoData,
                             PacketFilter);


                WdfSpinLockRelease(FdoData->Lock);

                if (status == STATUS_SUCCESS)
                {
                    FdoData->PacketFilter = PacketFilter;
                }

                WdfRequestCompleteWithInformation(request, status, 0);
            }
        }
    }

    //
    // Any read pending?
    //

    WdfSpinLockAcquire(FdoData->RcvLock);

    //
    // Start the NIC receive unit
    //
    status = NICStartRecv(FdoData);
    if (status != STATUS_SUCCESS)
    {
        MP_SET_HARDWARE_ERROR(FdoData);
    }


    WdfSpinLockRelease(FdoData->RcvLock);

    //
    // Send packets which have been queued while link detection was going on.
    //
    NICCheckForQueuedSends(FdoData);

    return status;
}