Beispiel #1
0
static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
{
	struct rt2x00_dev *rt2x00dev = data;
	int retval = 0;

	if (unlikely(!rt2x00dev))
		return 0;

	/*
	 * Only continue if there are enabled interfaces.
	 */
	if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
		return 0;

	if (state == RFKILL_STATE_UNBLOCKED) {
		INFO(rt2x00dev, "RFKILL event: enabling radio.\n");
		clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags);
		retval = rt2x00lib_enable_radio(rt2x00dev);
	} else if (state == RFKILL_STATE_SOFT_BLOCKED) {
		INFO(rt2x00dev, "RFKILL event: disabling radio.\n");
		set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags);
		rt2x00lib_disable_radio(rt2x00dev);
	} else {
		WARNING(rt2x00dev, "RFKILL event: unknown state %d.\n", state);
	}

	return retval;
}
Beispiel #2
0
int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
{
	struct rt2x00_dev *rt2x00dev = hw->priv;

	/*
	 * Mac80211 might be calling this function while we are trying
	 * to remove the device or perhaps suspending it.
	 */
	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
		return 0;

	/*
	 * Check if we need to disable the radio,
	 * if this is not the case, at least the RX must be disabled.
	 */
	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
		if (!conf->radio_enabled)
			rt2x00lib_disable_radio(rt2x00dev);
		else
			rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
	}

	rt2x00lib_config(rt2x00dev, conf, 0);

	/*
	 * Reenable RX only if the radio should be on.
	 */
	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
	else if (conf->radio_enabled)
		return rt2x00lib_enable_radio(rt2x00dev);

	return 0;
}
Beispiel #3
0
void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
{
	clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);

	/*
	 * Disable radio.
	 */
	rt2x00lib_disable_radio(rt2x00dev);

	/*
	 * Stop all work.
	 */
	cancel_work_sync(&rt2x00dev->intf_work);
	cancel_work_sync(&rt2x00dev->rxdone_work);
	cancel_work_sync(&rt2x00dev->txdone_work);

	/*
	 * Free the tx status fifo.
	 */
	kfifo_free(&rt2x00dev->txstatus_fifo);

	/*
	 * Kill the tx status tasklet.
	 */
	tasklet_kill(&rt2x00dev->txstatus_tasklet);

	/*
	 * Uninitialize device.
	 */
	rt2x00lib_uninitialize(rt2x00dev);

	/*
	 * Free extra components
	 */
	rt2x00debug_deregister(rt2x00dev);
	rt2x00leds_unregister(rt2x00dev);

	/*
	 * Free ieee80211_hw memory.
	 */
	rt2x00lib_remove_hw(rt2x00dev);

	/*
	 * Free firmware image.
	 */
	rt2x00lib_free_firmware(rt2x00dev);

	/*
	 * Free queue structures.
	 */
	rt2x00queue_free(rt2x00dev);
}
void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
{
	if (!test_and_clear_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
		return;

	/*
	 * Perhaps we can add something smarter here,
	 * but for now just disabling the radio should do.
	 */
	rt2x00lib_disable_radio(rt2x00dev);

	rt2x00dev->intf_ap_count = 0;
	rt2x00dev->intf_sta_count = 0;
	rt2x00dev->intf_associated = 0;
}
Beispiel #5
0
void rt2x00mac_stop(struct ieee80211_hw *hw)
{
	struct rt2x00_dev *rt2x00dev = hw->priv;

	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
		return;

	/*
	 * Perhaps we can add something smarter here,
	 * but for now just disabling the radio should do.
	 */
	rt2x00lib_disable_radio(rt2x00dev);

	__clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
}
int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
{
	struct rt2x00_dev *rt2x00dev = hw->priv;
	int force_reconfig;

	/*
	 * Mac80211 might be calling this function while we are trying
	 * to remove the device or perhaps suspending it.
	 */
	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
		return 0;

	/*
	 * Check if we need to disable the radio,
	 * if this is not the case, at least the RX must be disabled.
	 */
	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
		if (!conf->radio_enabled)
			rt2x00lib_disable_radio(rt2x00dev);
		else
			rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
	}

	/*
	 * When the DEVICE_DIRTY_CONFIG flag is set, the device has recently
	 * been started and the configuration must be forced upon the hardware.
	 * Otherwise registers will not be intialized correctly and could
	 * result in non-working hardware because essential registers aren't
	 * initialized.
	 */
	force_reconfig =
	    __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags);

	rt2x00lib_config(rt2x00dev, conf, force_reconfig);

	/*
	 * Reenable RX only if the radio should be on.
	 */
	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
	else if (conf->radio_enabled)
		return rt2x00lib_enable_radio(rt2x00dev);

	return 0;
}
void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
{
	__clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);

	/*
	 * Disable radio.
	 */
	rt2x00lib_disable_radio(rt2x00dev);

	/*
	 * Uninitialize device.
	 */
	rt2x00lib_uninitialize(rt2x00dev);

	/*
	 * Free extra components
	 */
	rt2x00debug_deregister(rt2x00dev);
	rt2x00rfkill_free(rt2x00dev);
	rt2x00leds_unregister(rt2x00dev);

	/*
	 * Free ieee80211_hw memory.
	 */
	rt2x00lib_remove_hw(rt2x00dev);

	/*
	 * Free firmware image.
	 */
	rt2x00lib_free_firmware(rt2x00dev);

	/*
	 * Free queue structures.
	 */
	rt2x00queue_free(rt2x00dev);
}
void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
{
	clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);

	/*
	 * Disable radio.
	 */
	rt2x00lib_disable_radio(rt2x00dev);

	/*
	 * Stop all work.
	 */
	cancel_work_sync(&rt2x00dev->intf_work);
	cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
	cancel_work_sync(&rt2x00dev->sleep_work);
	if (rt2x00_is_usb(rt2x00dev)) {
		hrtimer_cancel(&rt2x00dev->txstatus_timer);
		cancel_work_sync(&rt2x00dev->rxdone_work);
		cancel_work_sync(&rt2x00dev->txdone_work);
	}
	if (rt2x00dev->workqueue)
		destroy_workqueue(rt2x00dev->workqueue);

	/*
	 * Free the tx status fifo.
	 */
	kfifo_free(&rt2x00dev->txstatus_fifo);

	/*
	 * Kill the tx status tasklet.
	 */
	tasklet_kill(&rt2x00dev->txstatus_tasklet);
	tasklet_kill(&rt2x00dev->pretbtt_tasklet);
	tasklet_kill(&rt2x00dev->tbtt_tasklet);
	tasklet_kill(&rt2x00dev->rxdone_tasklet);
	tasklet_kill(&rt2x00dev->autowake_tasklet);

	/*
	 * Uninitialize device.
	 */
	rt2x00lib_uninitialize(rt2x00dev);

	/*
	 * Free extra components
	 */
	rt2x00debug_deregister(rt2x00dev);
	rt2x00leds_unregister(rt2x00dev);

	/*
	 * Free ieee80211_hw memory.
	 */
	rt2x00lib_remove_hw(rt2x00dev);

	/*
	 * Free firmware image.
	 */
	rt2x00lib_free_firmware(rt2x00dev);

	/*
	 * Free queue structures.
	 */
	rt2x00queue_free(rt2x00dev);

	/*
	 * Free the driver data.
	 */
	if (rt2x00dev->drv_data)
		kfree(rt2x00dev->drv_data);
}
int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
{
	int retval;

	NOTICE(rt2x00dev, "Waking up.\n");

	/*
	 * Restore/enable extra components.
	 */
	rt2x00debug_register(rt2x00dev);
	rt2x00leds_resume(rt2x00dev);

	/*
	 * Only continue if mac80211 had open interfaces.
	 */
	if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags))
		return 0;

	/*
	 * Reinitialize device and all active interfaces.
	 */
	retval = rt2x00lib_start(rt2x00dev);
	if (retval)
		goto exit;

	/*
	 * Reconfigure device.
	 */
	retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf);
	if (retval)
		goto exit;

	/*
	 * Iterator over each active interface to
	 * reconfigure the hardware.
	 */
	ieee80211_iterate_active_interfaces(rt2x00dev->hw,
					    rt2x00lib_resume_intf, rt2x00dev);

	/*
	 * We are ready again to receive requests from mac80211.
	 */
	__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);

	/*
	 * It is possible that during that mac80211 has attempted
	 * to send frames while we were suspending or resuming.
	 * In that case we have disabled the TX queue and should
	 * now enable it again
	 */
	ieee80211_wake_queues(rt2x00dev->hw);

	/*
	 * During interface iteration we might have changed the
	 * delayed_flags, time to handles the event by calling
	 * the work handler directly.
	 */
	rt2x00lib_intf_scheduled(&rt2x00dev->intf_work);

	return 0;

exit:
	rt2x00lib_disable_radio(rt2x00dev);
	rt2x00lib_uninitialize(rt2x00dev);
	rt2x00debug_deregister(rt2x00dev);

	return retval;
}