* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
- __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
* Check if the BBP tuning should be enabled.
/*
* This device requires the beacon ring
*/
- __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
/*
* Set the rssi offset.
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
- __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
* Check if the BBP tuning should be enabled.
/*
* This device requires the beacon ring
*/
- __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
/*
* Set the rssi offset.
/*
* This device requires the beacon ring
*/
- __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
/*
* Set the rssi offset.
* of the device capabilities are stored.
*/
unsigned long flags;
-#define DEVICE_ENABLED_RADIO 1
-#define DEVICE_ENABLED_RADIO_HW 2
+#define DEVICE_PRESENT 1
+#define DEVICE_REGISTERED_HW 2
#define DEVICE_INITIALIZED 3
-#define DEVICE_INITIALIZED_HW 4
-#define REQUIRE_FIRMWARE 5
-/* Hole: Add new Flag here */
-#define INTERFACE_RESUME 8
-#define INTERFACE_ENABLED 9
-/* Hole: Add new Flag here */
-#define REQUIRE_BEACON_RING 11
-#define DEVICE_SUPPORT_HW_BUTTON 12
-#define CONFIG_FRAME_TYPE 13
-#define CONFIG_RF_SEQUENCE 14
-/* Hole: Add new Flag here */
-#define CONFIG_EXTERNAL_LNA_A 16
-#define CONFIG_EXTERNAL_LNA_BG 17
-#define CONFIG_DOUBLE_ANTENNA 18
-#define CONFIG_DISABLE_LINK_TUNING 19
+#define DEVICE_STARTED 4
+#define DEVICE_ENABLED_RADIO 5
+#define DEVICE_ENABLED_RADIO_HW 6
+#define DRIVER_REQUIRE_FIRMWARE 7
+#define DRIVER_REQUIRE_BEACON_RING 8
+#define CONFIG_SUPPORT_HW_BUTTON 9
+#define CONFIG_FRAME_TYPE 10
+#define CONFIG_RF_SEQUENCE 11
+#define CONFIG_EXTERNAL_LNA_A 12
+#define CONFIG_EXTERNAL_LNA_BG 13
+#define CONFIG_DOUBLE_ANTENNA 14
+#define CONFIG_DISABLE_LINK_TUNING 15
/*
* Chipset identification.
void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type)
{
- struct interface *intf = &rt2x00dev->interface;
-
- if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) &&
- (!!test_bit(INTERFACE_ENABLED, &rt2x00dev->flags) ==
- !!is_interface_present(intf)))
- return;
-
- rt2x00dev->ops->lib->config_type(rt2x00dev, type);
-
- /*
- * Update the configuration flags.
- */
- if (is_interface_present(intf))
- __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags);
- else
- __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags);
+ if (type != INVALID_INTERFACE)
+ rt2x00dev->ops->lib->config_type(rt2x00dev, type);
}
-void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf)
+void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf, const int force_config)
{
int flags = 0;
/*
- * If we are in RESUME state we should
- * force all configuration options.
+ * In some situations we want to force all configurations
+ * to be reloaded (When resuming for instance).
*/
- if (test_bit(INTERFACE_RESUME, &rt2x00dev->flags)) {
+ if (force_config) {
flags = CONFIG_UPDATE_ALL;
goto config;
}
struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
const unsigned int queue)
{
- int beacon = test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags);
+ int beacon = test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
/*
* Check if we are requesting a reqular TX ring,
* And check if the hardware button has been disabled.
*/
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
- (test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags) &&
+ (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) &&
!test_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags)))
return 0;
{
enum dev_state state = enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF;
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
/*
* When we are disabling the RX, we should also stop the link tuner.
*/
static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev)
{
- if (test_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags))
+ if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags))
ieee80211_unregister_hw(rt2x00dev->hw);
if (likely(rt2x00dev->hwmodes)) {
return status;
}
- __set_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags);
+ __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags);
return 0;
}
return -ENOMEM;
}
- if (!test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags))
+ if (!test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
return 0;
/*
* Atim: 1 (if required)
*/
rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues +
- (2 * test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags));
+ (2 * test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags));
ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL);
if (!ring) {
*/
rt2x00dev->rx = ring;
rt2x00dev->tx = &rt2x00dev->rx[1];
- if (test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags))
+ if (test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues];
/*
*/
rt2x00debug_register(rt2x00dev);
+ __set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
return 0;
exit:
void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
{
+ __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
/*
* Disable radio.
*/
int retval;
NOTICE(rt2x00dev, "Going to sleep.\n");
+ __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+ /*
+ * Only continue if mac80211 has open interfaces.
+ */
+ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ goto exit;
/*
* Disable radio and unitialize all items
rt2x00lib_uninitialize(rt2x00dev);
rt2x00debug_deregister(rt2x00dev);
+exit:
/*
* Set device mode to sleep for power management.
*/
int retval;
NOTICE(rt2x00dev, "Waking up.\n");
- __set_bit(INTERFACE_RESUME, &rt2x00dev->flags);
+ __set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
/*
* Open the debugfs entry.
*/
rt2x00debug_register(rt2x00dev);
+ /*
+ * Only continue if mac80211 has open interfaces.
+ */
+ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ return 0;
+
/*
* Reinitialize device and all active interfaces.
*/
/*
* Reconfigure device.
*/
- retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf);
- if (retval)
- goto exit;
+ rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1);
+ if (!rt2x00dev->hw->conf.radio_enabled)
+ rt2x00lib_disable_radio(rt2x00dev);
rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
rt2x00lib_config_type(rt2x00dev, intf->type);
+ /*
+ * 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_start_queues(rt2x00dev->hw);
+
/*
* When in Master or Ad-hoc mode,
* restart Beacon transmitting by faking a beacondone event.
intf->type == IEEE80211_IF_TYPE_IBSS)
rt2x00lib_beacondone(rt2x00dev);
- __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags);
-
return 0;
exit:
rt2x00lib_uninitialize(rt2x00dev);
rt2x00debug_deregister(rt2x00dev);
- __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags);
-
return retval;
}
EXPORT_SYMBOL_GPL(rt2x00lib_resume);
void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac);
void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid);
void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type);
-void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf);
+void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf, const int force_config);
/*
* Firmware handlers.
struct data_ring *ring;
u16 frame_control;
+ /*
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ * Note that we can only stop the TX queues inside the TX path
+ * due to possible race conditions in mac80211.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
+ ieee80211_stop_queues(hw);
+ return 0;
+ }
+
/*
* Determine which ring to put packet on.
*/
struct rt2x00_dev *rt2x00dev = hw->priv;
int status;
- if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ test_bit(DEVICE_STARTED, &rt2x00dev->flags))
return 0;
/*
* If this is the first interface which is added,
* we should load the firmware now.
*/
- if (test_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
+ if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
status = rt2x00lib_load_firmware(rt2x00dev);
if (status)
return status;
return status;
}
+ __set_bit(DEVICE_STARTED, &rt2x00dev->flags);
+
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_start);
{
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);
}
EXPORT_SYMBOL_GPL(rt2x00mac_stop);
struct interface *intf = &rt2x00dev->interface;
/*
- * We only support 1 non-monitor interface.
+ * Don't allow interfaces to be added while
+ * either the device has disappeared or when
+ * another interface is already present.
*/
- if (is_interface_present(intf))
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ is_interface_present(intf))
return -ENOBUFS;
intf->id = conf->if_id;
struct interface *intf = &rt2x00dev->interface;
/*
- * We only support 1 non-monitor interface.
+ * Don't allow interfaces to be remove while
+ * either the device has disappeared or when
+ * no interface is present.
*/
- if (!is_interface_present(intf))
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ !is_interface_present(intf))
return;
intf->id = 0;
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
- * If the device is not initialized we shouldn't accept
- * any configuration changes. Mac80211 might be calling
- * this function while we are trying to remove the device
- * or perhaps suspending it.
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
*/
- if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
return 0;
/*
rt2x00lib_toggle_rx(rt2x00dev, 0);
}
- rt2x00lib_config(rt2x00dev, conf);
+ rt2x00lib_config(rt2x00dev, conf, 0);
/*
* Reenable RX only if the radio should be on.
int status;
/*
- * If the device is not initialized we shouldn't accept
- * any configuration changes. Mac80211 might be calling
- * this function while we are trying to remove the device
- * or perhaps suspending it.
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
*/
- if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
return 0;
/*
return 0;
/*
- * Only continue if we have an active interface.
+ * Only continue if there are enabled interfaces.
*/
- if (!is_interface_present(&rt2x00dev->interface))
+ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
return 0;
if (state == RFKILL_STATE_ON) {
{
int retval;
- if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
return 0;
retval = rfkill_register(rt2x00dev->rfkill);
void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
{
- if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
return;
input_unregister_polled_device(rt2x00dev->poll_dev);
{
struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
- if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
return 0;
rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
{
- if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
return;
input_free_polled_device(rt2x00dev->poll_dev);
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
- __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
* Read frequency offset and RF programming sequence.
/*
* This device requires firmware
*/
- __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
/*
* Set the rssi offset.
/*
* This device requires firmware
*/
- __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
/*
* Set the rssi offset.