// Called at PASSIVE, DISPATCH & DIRQL // Returns TRUE if at the end of the call, the new state of the RF is the requested // state, returns FALSE otherwise BOOLEAN HwSetRFState( _In_ PHW Hw, _In_ UCHAR NewRFState ) { BOOLEAN result = TRUE; do { if (InterlockedIncrement(&Hw->PhyState.RadioAccessRef) == 1) { if (Hw->PhyState.RadioStateChangeInProgress) { // Radio state is being changed, dont proceed result = FALSE; break; } if ((NewRFState == RF_ON) || (NewRFState == RF_SLEEP)) { if (Hw->PhyState.SoftwareRadioOff == TRUE) { // Radio is OFF, dont change RF state result = FALSE; break; } } HalSetRFPowerState(Hw->Hal, NewRFState); } else { // Another thread is changing RF/Radio state, // dont modify. We bail out and the caller can decide if it wants to // reattempt (we dont wait since we may be called at high IRQL, etc) MpTrace(COMP_POWER, DBG_LOUD, ("Unable to set RF/Radio state as something else is updating it\n")); result = FALSE; } }while (FALSE); InterlockedDecrement(&Hw->PhyState.RadioAccessRef); return result; }
NDIS_STATUS HwSetNicPowerState( _In_ PHW Hw, _In_ ULONG PhyId, _In_ BOOLEAN PowerOn ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; HW_HAL_RESET_PARAMETERS resetParams; // // Our RF cannot be selectively turned on/off. We turn on or turn off all the phys // anytime this OID is set // UNREFERENCED_PARAMETER(PhyId); // // Check if we are already in the specified state. // if (Hw->PhyState.SoftwareRadioOff == !PowerOn) { // No need to take status indications if we are // already in the correct state return NDIS_STATUS_SUCCESS; } if (!PowerOn) { // // Going to power save. Get everything into a stable state // // // If a scan is in progress, cancel scan // if (Hw->ScanContext.ScanInProgress) { HwCancelScan(Hw); } // // Before we turn off the radio, we reset the h/w. // This is to ensure that there isnt any pending operation sitting // on the hardware // NdisZeroMemory(&resetParams, sizeof(HW_HAL_RESET_PARAMETERS)); HwResetHAL(Hw, &resetParams, FALSE); // // Disable the interrupt // HwDisableInterruptWithSync(Hw, HW_ISR_TRACKING_RADIO_STATE); HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_RADIO_OFF); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); } // // Update Radio state // // Set flag so other threads (power save, scan timer, etc) wont change // state behind us Hw->PhyState.RadioStateChangeInProgress = TRUE; // We wait for ever for other threads to not reach this state while (Hw->PhyState.RadioAccessRef != 0); // // Set the Radio state // if (PowerOn) { Hw->PhyState.Debug_SoftwareRadioOff = FALSE; HalSetRFPowerState(Hw->Hal, RF_ON); Hw->PhyState.SoftwareRadioOff = FALSE; } else { Hw->PhyState.SoftwareRadioOff = TRUE; HalSetRFPowerState(Hw->Hal, RF_SHUT_DOWN); Hw->PhyState.Debug_SoftwareRadioOff = TRUE; } Hw->PhyState.RadioStateChangeInProgress = FALSE; if (PowerOn) { // Clear the radio off bit HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_CLEAR_ADAPTER_STATUS(Hw, HW_ADAPTER_RADIO_OFF); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); // Re-reset the H/W to get it into a good state NdisZeroMemory(&resetParams, sizeof(HW_HAL_RESET_PARAMETERS)); resetParams.FullReset = TRUE; HwResetHAL(Hw, &resetParams, FALSE); // // Reenable the interrupt // HwEnableInterruptWithSync(Hw, HW_ISR_TRACKING_RADIO_STATE); } // // Save the new radio state in the registry // ndisStatus = HwPersistRadioPowerState(Hw, Hw->PhyState.SoftwareRadioOff); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_OID, DBG_SERIOUS, ("Unable to persist new radio state in the registry\n")); return ndisStatus; } // // Report the new power state to the OS // HwIndicatePhyPowerState( Hw, DOT11_PHY_ID_ANY ); return ndisStatus; }
NDIS_STATUS Hw11Start( __in PHW Hw, __out NDIS_ERROR_CODE* ErrorCode, __out PULONG ErrorValue ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; BOOLEAN interruptRegistered = FALSE, hardwareStarted = FALSE; // // Disable interrupts // We should disable interrupts before the are registered. // They will be enabled right at the end of Initialize // HwDisableInterrupt(Hw, HW_ISR_TRACKING_HWSTART); do { // // Register interrupt with NDIS // ndisStatus = HwRegisterInterrupt( Hw, ErrorCode, ErrorValue ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to register interrupt with NDIS\n")); break; } interruptRegistered = TRUE; Hw->PhyState.Debug_SoftwareRadioOff = Hw->PhyState.SoftwareRadioOff; if (Hw->PhyState.SoftwareRadioOff) { HalSetRFPowerState(Hw->Hal, RF_SHUT_DOWN); } else { HalSetRFPowerState(Hw->Hal, RF_ON); } // // Start the HAL. If anything fails after this point, // we must issue a Halt to the HAL before returning // from initialize // ndisStatus = HalStart(Hw->Hal, FALSE); if(ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_INIT_PNP, DBG_SERIOUS, ("Failed to start HAL successfully.\n")); break; } hardwareStarted = TRUE; // Enable the interrupts on the hardware HwEnableInterrupt(Hw, HW_ISR_TRACKING_HWSTART); }while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Disable interrupts and deregister them first HwDisableInterrupt(Hw, HW_ISR_TRACKING_HWSTART); if (interruptRegistered) HwDeregisterInterrupt(Hw); if (hardwareStarted) { HalStop(Hw->Hal); HalHaltNic(Hw->Hal); } } return ndisStatus; }