int iwl_scan_initiate(struct iwl_priv *priv)
{
	if (!iwl_is_ready_rf(priv)) {
		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
		return -EIO;
	}

	if (test_bit(STATUS_SCANNING, &priv->status)) {
		IWL_DEBUG_SCAN("Scan already in progress.\n");
		return -EAGAIN;
	}

	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
		IWL_DEBUG_SCAN("Scan request while abort pending\n");
		return -EAGAIN;
	}

	IWL_DEBUG_INFO("Starting scan...\n");
	if (priv->cfg->sku & IWL_SKU_G)
		priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
	if (priv->cfg->sku & IWL_SKU_A)
		priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
	set_bit(STATUS_SCANNING, &priv->status);
	priv->scan_start = jiffies;
	priv->scan_pass_start = priv->scan_start;

	queue_work(priv->workqueue, &priv->request_scan);

	return 0;
}
Esempio n. 2
0
File: rxon.c Progetto: 19Dan01/linux
static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
{
	int ret;
	s8 prev_tx_power;
	bool defer;
	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];

	if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED)
		return 0;

	lockdep_assert_held(&priv->mutex);

	if (priv->tx_power_user_lmt == tx_power && !force)
		return 0;

	if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
		IWL_WARN(priv,
			 "Requested user TXPOWER %d below lower limit %d.\n",
			 tx_power,
			 IWLAGN_TX_POWER_TARGET_POWER_MIN);
		return -EINVAL;
	}

	if (tx_power > DIV_ROUND_UP(priv->nvm_data->max_tx_pwr_half_dbm, 2)) {
		IWL_WARN(priv,
			"Requested user TXPOWER %d above upper limit %d.\n",
			 tx_power, priv->nvm_data->max_tx_pwr_half_dbm);
		return -EINVAL;
	}

	if (!iwl_is_ready_rf(priv))
		return -EIO;

	/* scan complete and commit_rxon use tx_power_next value,
	 * it always need to be updated for newest request */
	priv->tx_power_next = tx_power;

	/* do not set tx power when scanning or channel changing */
	defer = test_bit(STATUS_SCANNING, &priv->status) ||
		memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
	if (defer && !force) {
		IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
		return 0;
	}

	prev_tx_power = priv->tx_power_user_lmt;
	priv->tx_power_user_lmt = tx_power;

	ret = iwlagn_send_tx_power(priv);

	/* if fail to set tx_power, restore the orig. tx power */
	if (ret) {
		priv->tx_power_user_lmt = prev_tx_power;
		priv->tx_power_next = prev_tx_power;
	}
	return ret;
}
Esempio n. 3
0
int iwl_mac_hw_scan(struct ieee80211_hw *hw,
		    struct ieee80211_vif *vif,
		    struct cfg80211_scan_request *req)
{
	struct iwl_priv *priv = hw->priv;
	int ret;

	IWL_DEBUG_MAC80211(priv, "enter\n");

	if (req->n_channels == 0)
		return -EINVAL;

	mutex_lock(&priv->mutex);

	if (!iwl_is_ready_rf(priv)) {
		ret = -EIO;
		IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n");
		goto out_unlock;
	}

	if (test_bit(STATUS_SCANNING, &priv->status) &&
	    !priv->is_internal_short_scan) {
		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
		ret = -EAGAIN;
		goto out_unlock;
	}

	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
		ret = -EAGAIN;
		goto out_unlock;
	}

	/* mac80211 will only ask for one band at a time */
	priv->scan_band = req->channels[0]->band;
	priv->scan_request = req;
	priv->scan_vif = vif;

	/*
	 * If an internal scan is in progress, just set
	 * up the scan_request as per above.
	 */
	if (priv->is_internal_short_scan)
		ret = 0;
	else
		ret = iwl_scan_initiate(priv, vif);

	IWL_DEBUG_MAC80211(priv, "leave\n");

out_unlock:
	mutex_unlock(&priv->mutex);

	return ret;
}
Esempio n. 4
0
static void iwl_process_scan_complete(struct iwl_priv *priv)
{
    bool aborted;

    lockdep_assert_held(&priv->mutex);

    if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status))
        return;

    IWL_DEBUG_SCAN(priv, "Completed scan.\n");

    cancel_delayed_work(&priv->scan_check);

    aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
    if (aborted)
        IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");

    if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
        IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
        goto out_settings;
    }

    if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
        int err;

        /* Check if mac80211 requested scan during our internal scan */
        if (priv->scan_request == NULL)
            goto out_complete;

        /* If so request a new scan */
        err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
                                priv->scan_request->channels[0]->band);
        if (err) {
            IWL_DEBUG_SCAN(priv,
                           "failed to initiate pending scan: %d\n", err);
            aborted = true;
            goto out_complete;
        }

        return;
    }

out_complete:
    iwl_complete_scan(priv, aborted);

out_settings:
    /* Can we still talk to firmware ? */
    if (!iwl_is_ready_rf(priv))
        return;

    iwlagn_post_scan(priv);
}
void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw)
{
	struct iwl_priv *priv = hw->priv;
	unsigned long flags;
	/* IBSS can only be the IWL_RXON_CTX_BSS context */
	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];

	if (WARN_ON(!priv->cfg->ops->legacy))
		return;

	mutex_lock(&priv->mutex);
	IWL_DEBUG_MAC80211(priv, "enter\n");

	spin_lock_irqsave(&priv->lock, flags);
	memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config));
	spin_unlock_irqrestore(&priv->lock, flags);

	spin_lock_irqsave(&priv->lock, flags);

	/* new association get rid of ibss beacon skb */
	if (priv->beacon_skb)
		dev_kfree_skb(priv->beacon_skb);

	priv->beacon_skb = NULL;

	priv->timestamp = 0;

	spin_unlock_irqrestore(&priv->lock, flags);

	iwl_scan_cancel_timeout(priv, 100);
	if (!iwl_is_ready_rf(priv)) {
		IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
		mutex_unlock(&priv->mutex);
		return;
	}

	/* we are restarting association process
	 * clear RXON_FILTER_ASSOC_MSK bit
	 */
	ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
	iwlcore_commit_rxon(priv, ctx);

	iwl_set_rate(priv);

	mutex_unlock(&priv->mutex);

	IWL_DEBUG_MAC80211(priv, "leave\n");
}
Esempio n. 6
0
int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
		       bool force)
{
	int ret;
	bool update_chains;

	lockdep_assert_held(&priv->mutex);

	/* Don't update the RX chain when chain noise calibration is running */
	update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
			priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;

	if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
		return 0;

	if (!iwl_is_ready_rf(priv))
		return -EIO;

	/* scan complete use sleep_power_next, need to be updated */
	memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
	if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
		IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
		return 0;
	}

	if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
		set_bit(STATUS_POWER_PMI, &priv->status);

	ret = iwl_set_power(priv, cmd);
	if (!ret) {
		if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
			clear_bit(STATUS_POWER_PMI, &priv->status);

		if (priv->cfg->ops->lib->update_chain_flags && update_chains)
			priv->cfg->ops->lib->update_chain_flags(priv);
		else if (priv->cfg->ops->lib->update_chain_flags)
			IWL_DEBUG_POWER(priv,
					"Cannot update the power, chain noise "
					"calibration running: %d\n",
					priv->chain_noise_data.state);

		memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
	} else
		IWL_ERR(priv, "set power fail, ret = %d", ret);

	return ret;
}
Esempio n. 7
0
/*
 * compute the final power mode index
 */
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
{
    struct iwl_power_mgr *setting = &(priv->power_data);
    int ret = 0;
    u16 uninitialized_var(final_mode);
    bool update_chains;

    /* Don't update the RX chain when chain noise calibration is running */
    update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
                    priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;

    final_mode = priv->power_data.user_power_setting;

    if (setting->power_disabled)
        final_mode = IWL_POWER_MODE_CAM;

    if (iwl_is_ready_rf(priv) &&
            ((setting->power_mode != final_mode) || force)) {
        struct iwl_powertable_cmd cmd;

        if (final_mode != IWL_POWER_MODE_CAM)
            set_bit(STATUS_POWER_PMI, &priv->status);

        iwl_update_power_cmd(priv, &cmd, final_mode);
        cmd.keep_alive_beacons = 0;

        if (final_mode == IWL_POWER_INDEX_5)
            cmd.flags |= IWL_POWER_FAST_PD;

        ret = iwl_set_power(priv, &cmd);

        if (final_mode == IWL_POWER_MODE_CAM)
            clear_bit(STATUS_POWER_PMI, &priv->status);

        if (priv->cfg->ops->lib->update_chain_flags && update_chains)
            priv->cfg->ops->lib->update_chain_flags(priv);
        else
            IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise "
                            "calibration running: %d\n",
                            priv->chain_noise_data.state);
        if (!ret)
            setting->power_mode = final_mode;
    }

    return ret;
}
void iwl_bg_start_internal_scan(struct work_struct *work)
{
	struct iwl_priv *priv =
		container_of(work, struct iwl_priv, start_internal_scan);

	mutex_lock(&priv->mutex);

	if (priv->is_internal_short_scan == true) {
		IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
		goto unlock;
	}

	if (!iwl_is_ready_rf(priv)) {
		IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
		goto unlock;
	}

	if (test_bit(STATUS_SCANNING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
		goto unlock;
	}

	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
		goto unlock;
	}

	priv->scan_band = priv->band;

	IWL_DEBUG_SCAN(priv, "Start internal short scan...\n");
	set_bit(STATUS_SCANNING, &priv->status);
	priv->is_internal_short_scan = true;

	if (WARN_ON(!priv->cfg->ops->utils->request_scan))
		goto unlock;

	priv->cfg->ops->utils->request_scan(priv, NULL);
 unlock:
	mutex_unlock(&priv->mutex);
}
Esempio n. 9
0
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
{
	int ret = 0;
	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
	bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) &&
			(priv->hw->conf.flags & IEEE80211_CONF_PS);
	bool update_chains;
	struct iwl_powertable_cmd cmd;
	int dtimper;

	/* Don't update the RX chain when chain noise calibration is running */
	update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
			priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;

	if (priv->vif)
		dtimper = priv->vif->bss_conf.dtim_period;
	else
		dtimper = 1;

	if (priv->cfg->broken_powersave)
		iwl_power_sleep_cam_cmd(priv, &cmd);
	else if (priv->cfg->supports_idle &&
		 priv->hw->conf.flags & IEEE80211_CONF_IDLE)
		iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
	else if (tt->state >= IWL_TI_1)
		iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
	else if (!enabled)
		iwl_power_sleep_cam_cmd(priv, &cmd);
	else if (priv->power_data.debug_sleep_level_override >= 0)
		iwl_static_sleep_cmd(priv, &cmd,
				     priv->power_data.debug_sleep_level_override,
				     dtimper);
	else if (no_sleep_autoadjust)
		iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper);
	else
		iwl_power_fill_sleep_cmd(priv, &cmd,
					 priv->hw->conf.dynamic_ps_timeout,
					 priv->hw->conf.max_sleep_period);

	if (iwl_is_ready_rf(priv) &&
	    (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) {
		if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
			set_bit(STATUS_POWER_PMI, &priv->status);

		ret = iwl_set_power(priv, &cmd);
		if (!ret) {
			if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
				clear_bit(STATUS_POWER_PMI, &priv->status);

			if (priv->cfg->ops->lib->update_chain_flags &&
			    update_chains)
				priv->cfg->ops->lib->update_chain_flags(priv);
			else if (priv->cfg->ops->lib->update_chain_flags)
				IWL_DEBUG_POWER(priv,
					"Cannot update the power, chain noise "
					"calibration running: %d\n",
					priv->chain_noise_data.state);
			memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd));
		} else
			IWL_ERR(priv, "set power fail, ret = %d", ret);
	}

	return ret;
}
Esempio n. 10
0
static int iwl_send_scan_abort(struct iwl_priv *priv)
{
	int ret;
	struct iwl_host_cmd cmd = {
		.id = REPLY_SCAN_ABORT_CMD,
		.flags = CMD_SYNC | CMD_WANT_SKB,
	};
	__le32 *status;

	/* Exit instantly with error when device is not ready
	 * to receive scan abort command or it does not perform
	 * hardware scan currently */
	if (!test_bit(STATUS_READY, &priv->status) ||
	    !test_bit(STATUS_SCAN_HW, &priv->status) ||
	    test_bit(STATUS_FW_ERROR, &priv->status))
		return -EIO;

	ret = iwl_dvm_send_cmd(priv, &cmd);
	if (ret)
		return ret;

	status = (void *)cmd.resp_pkt->data;
	if (*status != CAN_ABORT_STATUS) {
		/* The scan abort will return 1 for success or
		 * 2 for "failure".  A failure condition can be
		 * due to simply not being in an active scan which
		 * can occur if we send the scan abort before we
		 * the microcode has notified us that a scan is
		 * completed. */
		IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n",
			       le32_to_cpu(*status));
		ret = -EIO;
	}

	iwl_free_resp(&cmd);
	return ret;
}

static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
{
	/* check if scan was requested from mac80211 */
	if (priv->scan_request) {
		IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
		ieee80211_scan_completed(priv->hw, aborted);
	}

	priv->scan_type = IWL_SCAN_NORMAL;
	priv->scan_vif = NULL;
	priv->scan_request = NULL;
}

static void iwl_process_scan_complete(struct iwl_priv *priv)
{
	bool aborted;

	lockdep_assert_held(&priv->mutex);

	if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status))
		return;

	IWL_DEBUG_SCAN(priv, "Completed scan.\n");

	cancel_delayed_work(&priv->scan_check);

	aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
	if (aborted)
		IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");

	if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
		goto out_settings;
	}

	if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
		int err;

		/* Check if mac80211 requested scan during our internal scan */
		if (priv->scan_request == NULL)
			goto out_complete;

		/* If so request a new scan */
		err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
					priv->scan_request->channels[0]->band);
		if (err) {
			IWL_DEBUG_SCAN(priv,
				"failed to initiate pending scan: %d\n", err);
			aborted = true;
			goto out_complete;
		}

		return;
	}

out_complete:
	iwl_complete_scan(priv, aborted);

out_settings:
	/* Can we still talk to firmware ? */
	if (!iwl_is_ready_rf(priv))
		return;

	iwlagn_post_scan(priv);
}
Esempio n. 11
0
int iwl_mac_hw_scan(struct ieee80211_hw *hw,
		     struct cfg80211_scan_request *req)
{
	unsigned long flags;
	struct iwl_priv *priv = hw->priv;
	int ret;
	u8 *ssid = NULL;
	size_t ssid_len = 0;

	if (req->n_ssids) {
		ssid = req->ssids[0].ssid;
		ssid_len = req->ssids[0].ssid_len;
	}

	IWL_DEBUG_MAC80211(priv, "enter\n");

	mutex_lock(&priv->mutex);
	spin_lock_irqsave(&priv->lock, flags);

	if (!iwl_is_ready_rf(priv)) {
		ret = -EIO;
		IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n");
		goto out_unlock;
	}

	/* We don't schedule scan within next_scan_jiffies period.
	 * Avoid scanning during possible EAPOL exchange, return
	 * success immediately.
	 */
	if (priv->next_scan_jiffies &&
	    time_after(priv->next_scan_jiffies, jiffies)) {
		IWL_DEBUG_SCAN(priv, "scan rejected: within next scan period\n");
		queue_work(priv->workqueue, &priv->scan_completed);
		ret = 0;
		goto out_unlock;
	}

	/* if we just finished scan ask for delay */
	if (iwl_is_associated(priv) && priv->last_scan_jiffies &&
	    time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) {
		IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n");
		queue_work(priv->workqueue, &priv->scan_completed);
		ret = 0;
		goto out_unlock;
	}

	if (ssid_len) {
		priv->one_direct_scan = 1;
		priv->direct_ssid_len =  ssid_len;
		memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
	} else {
		priv->one_direct_scan = 0;
	}

	ret = iwl_scan_initiate(priv);

	IWL_DEBUG_MAC80211(priv, "leave\n");

out_unlock:
	spin_unlock_irqrestore(&priv->lock, flags);
	mutex_unlock(&priv->mutex);

	return ret;
}
static int iwl_send_scan_abort(struct iwl_priv *priv)
{
	int ret;
	struct iwl_host_cmd cmd = {
		.id = REPLY_SCAN_ABORT_CMD,
		.flags = CMD_SYNC | CMD_WANT_SKB,
	};
	__le32 *status;

	if (!test_bit(STATUS_READY, &priv->status) ||
	    !test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
	    !test_bit(STATUS_SCAN_HW, &priv->status) ||
	    test_bit(STATUS_FW_ERROR, &priv->shrd->status))
		return -EIO;

	ret = iwl_dvm_send_cmd(priv, &cmd);
	if (ret)
		return ret;

	status = (void *)cmd.resp_pkt->data;
	if (*status != CAN_ABORT_STATUS) {
		IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n",
			       le32_to_cpu(*status));
		ret = -EIO;
	}

	iwl_free_resp(&cmd);
	return ret;
}

static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
{
	
	if (priv->scan_request) {
		IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
		ieee80211_scan_completed(priv->hw, aborted);
	}

	if (priv->scan_type == IWL_SCAN_ROC) {
		ieee80211_remain_on_channel_expired(priv->hw);
		priv->hw_roc_channel = NULL;
		schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
	}

	priv->scan_type = IWL_SCAN_NORMAL;
	priv->scan_vif = NULL;
	priv->scan_request = NULL;
}

static void iwl_process_scan_complete(struct iwl_priv *priv)
{
	bool aborted;

	lockdep_assert_held(&priv->mutex);

	if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status))
		return;

	IWL_DEBUG_SCAN(priv, "Completed scan.\n");

	cancel_delayed_work(&priv->scan_check);

	aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
	if (aborted)
		IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");

	if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
		goto out_settings;
	}

	if (priv->scan_type == IWL_SCAN_ROC) {
		ieee80211_remain_on_channel_expired(priv->hw);
		priv->hw_roc_channel = NULL;
		schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
	}

	if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
		int err;

		
		if (priv->scan_request == NULL)
			goto out_complete;

		
		err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
					priv->scan_request->channels[0]->band);
		if (err) {
			IWL_DEBUG_SCAN(priv,
				"failed to initiate pending scan: %d\n", err);
			aborted = true;
			goto out_complete;
		}

		return;
	}

out_complete:
	iwl_complete_scan(priv, aborted);

out_settings:
	
	if (!iwl_is_ready_rf(priv))
		return;

	iwlagn_post_scan(priv);
}