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; }
/** This routine returns the current interrupt status and/or the transmitted buffer addresses. If the current interrupt status is returned, pending interrupts will be acknowledged by this command. Transmitted buffer addresses that are written to the DB are removed from the transmit buffer queue. Normally, this command would be polled with interrupts disabled. The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries]. The interrupt status is returned in CdbPtr->StatFlags. @param CdbPtr Pointer to the command descriptor block. @param AdapterInfo Pointer to the NIC data structure information which the UNDI driver is layering on.. @return None **/ VOID UNDI_Status ( IN PXE_CDB *CdbPtr, IN NIC_DATA_INSTANCE *AdapterInfo ) { PXE_DB_GET_STATUS *DbPtr; PXE_DB_GET_STATUS TmpGetStatus; UINT16 Index; UINT16 Status; UINT16 NumEntries; RxFD *RxPtr; // // Fill in temporary GetStatus storage. // RxPtr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind]; if ((RxPtr->cb_header.status & RX_COMPLETE) != 0) { TmpGetStatus.RxFrameLen = RxPtr->ActualCount & 0x3fff; } else { TmpGetStatus.RxFrameLen = 0; } TmpGetStatus.reserved = 0; // // Fill in size of next available receive packet and // reserved field in caller's DB storage. // DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr; if (CdbPtr->DBsize > 0 && CdbPtr->DBsize < sizeof (UINT32) * 2) { CopyMem (DbPtr, &TmpGetStatus, CdbPtr->DBsize); } else { CopyMem (DbPtr, &TmpGetStatus, sizeof (UINT32) * 2); } // // // if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) { // // DBsize of zero is invalid if Tx buffers are requested. // if (CdbPtr->DBsize == 0) { CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; CdbPtr->StatCode = PXE_STATCODE_INVALID_CDB; return ; } // // remember this b4 we overwrite // NumEntries = (UINT16) (CdbPtr->DBsize - sizeof (UINT64)); // // We already filled in 2 UINT32s. // CdbPtr->DBsize = sizeof (UINT32) * 2; // // will claim any hanging free CBs // CheckCBList (AdapterInfo); if (AdapterInfo->xmit_done_head == AdapterInfo->xmit_done_tail) { CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY; } else { for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) { if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) { DbPtr->TxBuffer[Index] = AdapterInfo->xmit_done[AdapterInfo->xmit_done_head]; AdapterInfo->xmit_done_head = next (AdapterInfo->xmit_done_head); CdbPtr->DBsize += sizeof (UINT64); } else { break; } } } if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) { CdbPtr->StatFlags |= PXE_STATFLAGS_DB_WRITE_TRUNCATED; } // // check for a receive buffer and give it's size in db // } // // // if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) { Status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus); AdapterInfo->Int_Status = (UINT16) (AdapterInfo->Int_Status | Status); // // acknoledge the interrupts // OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus)); // // report all the outstanding interrupts // Status = AdapterInfo->Int_Status; if ((Status & SCB_STATUS_FR) != 0) { CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE; } if ((Status & SCB_STATUS_SWI) != 0) { CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE; } } // // Return current media status // if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) { AdapterInfo->PhyAddress = 0xFF; AdapterInfo->CableDetect = 1; if (!PhyDetect (AdapterInfo)) { CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA; } } return ; }