X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fiwlwifi%2Fiwl3945-base.c;h=43cb8ff979395f853f932f9caac0767b0e898e73;hb=ebef2008082f579d8a40cc92e868fe8bf1296a60;hp=a740a1817d16fef0360fae2a458b25c85ae719a4;hpb=e039fa4a4195ac4ee895e6f3d1334beed63256fe;p=linux-2.6 diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a740a1817d..43cb8ff979 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -970,7 +970,7 @@ static int iwl3945_full_rxon_required(struct iwl3945_priv *priv) { /* These items are only settable from the full RXON command */ - if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || + if (!(iwl3945_is_associated(priv)) || compare_ether_addr(priv->staging_rxon.bssid_addr, priv->active_rxon.bssid_addr) || compare_ether_addr(priv->staging_rxon.node_addr, @@ -2217,7 +2217,10 @@ static int iwl3945_scan_initiate(struct iwl3945_priv *priv) } IWL_DEBUG_INFO("Starting scan...\n"); - priv->scan_bands = 2; + 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; @@ -2431,15 +2434,15 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) { - u16 fc = le16_to_cpu(hdr->frame_control); + __le16 fc = hdr->frame_control; __le32 tx_flags = cmd->cmd.tx.tx_flags; cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { tx_flags |= TX_CMD_FLG_ACK_MSK; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + if (ieee80211_is_mgmt(fc)) tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; - if (ieee80211_is_probe_response(fc) && + if (ieee80211_is_probe_resp(fc) && !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) tx_flags |= TX_CMD_FLG_TSF_MSK; } else { @@ -2448,11 +2451,11 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, } cmd->cmd.tx.sta_id = std_id; - if (ieee80211_get_morefrag(hdr)) + if (ieee80211_has_morefrags(fc)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; - if (ieee80211_is_qos_data(fc)) { - u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc)); + if (ieee80211_is_data_qos(fc)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); cmd->cmd.tx.tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } else { @@ -2471,9 +2474,8 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + if (ieee80211_is_mgmt(fc)) { + if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); else cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); @@ -2552,7 +2554,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl3945_tfd_frame *tfd; u32 *control_flags; - int txq_id = info->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl3945_tx_queue *txq = NULL; struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; @@ -2564,7 +2566,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) u8 sta_id; u8 tid = 0; u16 seq_number = 0; - u16 fc; + __le16 fc; u8 wait_write_ptr = 0; u8 *qc = NULL; unsigned long flags; @@ -2589,28 +2591,28 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) unicast = !is_multicast_ether_addr(hdr->addr1); id = 0; - fc = le16_to_cpu(hdr->frame_control); + fc = hdr->frame_control; #ifdef CONFIG_IWL3945_DEBUG if (ieee80211_is_auth(fc)) IWL_DEBUG_TX("Sending AUTH frame\n"); - else if (ieee80211_is_assoc_request(fc)) + else if (ieee80211_is_assoc_req(fc)) IWL_DEBUG_TX("Sending ASSOC frame\n"); - else if (ieee80211_is_reassoc_request(fc)) + else if (ieee80211_is_reassoc_req(fc)) IWL_DEBUG_TX("Sending REASSOC frame\n"); #endif /* drop all data frame if we are not associated */ if ((!iwl3945_is_associated(priv) || ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id)) && - ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { + ieee80211_is_data(fc)) { IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n"); goto drop_unlock; } spin_unlock_irqrestore(&priv->lock, flags); - hdr_len = ieee80211_get_hdrlen(fc); + hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc)); /* Find (or create) index into station table for destination station */ sta_id = iwl3945_get_sta_id(priv, hdr); @@ -2624,8 +2626,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) IWL_DEBUG_RATE("station Id %d\n", sta_id); - if (ieee80211_is_qos_data(fc)) { - qc = ieee80211_get_qos_ctrl(hdr, hdr_len); + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; @@ -2732,7 +2734,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; - if (!ieee80211_get_morefrag(hdr)) { + if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; if (qc) { priv->stations[sta_id].tid[tid].seq_number = seq_number; @@ -2746,7 +2748,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) sizeof(out_cmd->cmd.tx)); iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, - ieee80211_get_hdrlen(fc)); + ieee80211_get_hdrlen(le16_to_cpu(fc))); /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); @@ -2765,7 +2767,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, info->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; @@ -2875,7 +2877,8 @@ static void iwl3945_radio_kill_sw(struct iwl3945_priv *priv, int disable_radio) return; } - queue_work(priv->workqueue, &priv->restart); + if (priv->is_open) + queue_work(priv->workqueue, &priv->restart); return; } @@ -3342,13 +3345,18 @@ static void iwl3945_rx_scan_complete_notif(struct iwl3945_priv *priv, cancel_delayed_work(&priv->scan_check); IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", - (priv->scan_bands == 2) ? "2.4" : "5.2", + (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ? + "2.4" : "5.2", jiffies_to_msecs(elapsed_jiffies (priv->scan_pass_start, jiffies))); - /* Remove this scanned band from the list - * of pending bands to scan */ - priv->scan_bands--; + /* Remove this scanned band from the list of pending + * bands to scan, band G precedes A in order of scanning + * as seen in iwl3945_bg_request_scan */ + if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) + priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ); + else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) + priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ); /* If a request to abort was given, or the scan did not succeed * then we reset the scan state machine and terminate, @@ -4961,7 +4969,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel); if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", + IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n", scan_ch->channel); continue; } @@ -5847,9 +5855,6 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) /* Configure the adapter for unassociated operation */ iwl3945_commit_rxon(priv); - /* At this point, the NIC is initialized and operational */ - priv->notif_missed_beacons = 0; - iwl3945_reg_txpower_periodic(priv); iwl3945_led_register(priv); @@ -5916,7 +5921,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv) test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND; + STATUS_IN_SUSPEND | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; goto exit; } @@ -5931,7 +5938,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv) test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << - STATUS_FW_ERROR; + STATUS_FW_ERROR | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; spin_lock_irqsave(&priv->lock, flags); iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -6003,11 +6012,12 @@ static int __iwl3945_up(struct iwl3945_priv *priv) else { set_bit(STATUS_RF_KILL_HW, &priv->status); if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { + iwl3945_rfkill_set_hw_state(priv); IWL_WARNING("Radio disabled by HW RF Kill switch\n"); return -ENODEV; } } - + iwl3945_rfkill_set_hw_state(priv); iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF); rc = iwl3945_hw_nic_init(priv); @@ -6063,6 +6073,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv) set_bit(STATUS_EXIT_PENDING, &priv->status); __iwl3945_down(priv); + clear_bit(STATUS_EXIT_PENDING, &priv->status); /* tried to restart and config the device for as long as our * patience could withstand */ @@ -6130,6 +6141,8 @@ static void iwl3945_bg_rf_kill(struct work_struct *work) "Kill switch must be turned off for " "wireless networking to work.\n"); } + + iwl3945_rfkill_set_hw_state(priv); mutex_unlock(&priv->mutex); } @@ -6319,21 +6332,16 @@ static void iwl3945_bg_request_scan(struct work_struct *data) /* flags + rate selection */ - switch (priv->scan_bands) { - case 2: + if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; scan->tx_cmd.rate = IWL_RATE_1M_PLCP; scan->good_CRC_th = 0; band = IEEE80211_BAND_2GHZ; - break; - - case 1: + } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { scan->tx_cmd.rate = IWL_RATE_6M_PLCP; scan->good_CRC_th = IWL_GOOD_CRC_TH; band = IEEE80211_BAND_5GHZ; - break; - - default: + } else { IWL_WARNING("Invalid scan band count\n"); goto done; } @@ -6773,7 +6781,7 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co ch_info = iwl3945_get_channel_info(priv, conf->channel->band, conf->channel->hw_value); if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", + IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this band.\n", conf->channel->hw_value, conf->channel->band); IWL_DEBUG_MAC80211("leave - invalid channel\n"); spin_unlock_irqrestore(&priv->lock, flags); @@ -6836,7 +6844,7 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) return; /* The following should be done only at AP bring up */ - if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) { + if (!(iwl3945_is_associated(priv))) { /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; @@ -7412,37 +7420,6 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, #endif /* CONFIG_IWL3945_DEBUG */ -static ssize_t show_rf_kill(struct device *d, - struct device_attribute *attr, char *buf) -{ - /* - * 0 - RF kill not enabled - * 1 - SW based RF kill active (sysfs) - * 2 - HW based RF kill active - * 3 - Both HW and SW based RF kill active - */ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | - (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); - - return sprintf(buf, "%i\n", val); -} - -static ssize_t store_rf_kill(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - - mutex_lock(&priv->mutex); - iwl3945_radio_kill_sw(priv, buf[0] == '1'); - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); - static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { @@ -7928,7 +7905,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { #endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, - &dev_attr_rf_kill.attr, &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, @@ -8169,6 +8145,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_save_state(pdev); pci_disable_device(pdev); + err = iwl3945_rfkill_init(priv); + if (err) + IWL_ERROR("Unable to initialize RFKILL system. " + "Ignoring error: %d\n", err); + return 0; out_free_geos: @@ -8231,6 +8212,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); + iwl3945_rfkill_unregister(priv); iwl3945_dealloc_ucode_pci(priv); if (priv->rxq.bd) @@ -8260,7 +8242,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_free_channel_map(priv); iwl3945_free_geos(priv); - + kfree(priv->scan); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -8299,6 +8281,140 @@ static int iwl3945_pci_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ +/*************** RFKILL FUNCTIONS **********/ +#ifdef CONFIG_IWLWIFI_RFKILL +/* software rf-kill from user */ +static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state) +{ + struct iwl3945_priv *priv = data; + int err = 0; + + if (!priv->rfkill_mngr.rfkill) + return 0; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return 0; + + IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + mutex_lock(&priv->mutex); + + switch (state) { + case RFKILL_STATE_ON: + iwl3945_radio_kill_sw(priv, 0); + /* if HW rf-kill is set dont allow ON state */ + if (iwl3945_is_rfkill(priv)) + err = -EBUSY; + break; + case RFKILL_STATE_OFF: + iwl3945_radio_kill_sw(priv, 1); + if (!iwl3945_is_rfkill(priv)) + err = -EBUSY; + break; + } + mutex_unlock(&priv->mutex); + + return err; +} + +int iwl3945_rfkill_init(struct iwl3945_priv *priv) +{ + struct device *device = wiphy_dev(priv->hw->wiphy); + int ret = 0; + + BUG_ON(device == NULL); + + IWL_DEBUG_RF_KILL("Initializing RFKILL.\n"); + priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + if (!priv->rfkill_mngr.rfkill) { + IWL_ERROR("Unable to allocate rfkill device.\n"); + ret = -ENOMEM; + goto error; + } + + priv->rfkill_mngr.rfkill->name = priv->cfg->name; + priv->rfkill_mngr.rfkill->data = priv; + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; + priv->rfkill_mngr.rfkill->toggle_radio = iwl3945_rfkill_soft_rf_kill; + priv->rfkill_mngr.rfkill->user_claim_unsupported = 1; + + priv->rfkill_mngr.rfkill->dev.class->suspend = NULL; + priv->rfkill_mngr.rfkill->dev.class->resume = NULL; + + priv->rfkill_mngr.input_dev = input_allocate_device(); + if (!priv->rfkill_mngr.input_dev) { + IWL_ERROR("Unable to allocate rfkill input device.\n"); + ret = -ENOMEM; + goto freed_rfkill; + } + + priv->rfkill_mngr.input_dev->name = priv->cfg->name; + priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy); + priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST; + priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor; + priv->rfkill_mngr.input_dev->dev.parent = device; + priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY); + set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit); + + ret = rfkill_register(priv->rfkill_mngr.rfkill); + if (ret) { + IWL_ERROR("Unable to register rfkill: %d\n", ret); + goto free_input_dev; + } + + ret = input_register_device(priv->rfkill_mngr.input_dev); + if (ret) { + IWL_ERROR("Unable to register rfkill input device: %d\n", ret); + goto unregister_rfkill; + } + + IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); + return ret; + +unregister_rfkill: + rfkill_unregister(priv->rfkill_mngr.rfkill); + priv->rfkill_mngr.rfkill = NULL; + +free_input_dev: + input_free_device(priv->rfkill_mngr.input_dev); + priv->rfkill_mngr.input_dev = NULL; + +freed_rfkill: + if (priv->rfkill_mngr.rfkill != NULL) + rfkill_free(priv->rfkill_mngr.rfkill); + priv->rfkill_mngr.rfkill = NULL; + +error: + IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); + return ret; +} + +void iwl3945_rfkill_unregister(struct iwl3945_priv *priv) +{ + + if (priv->rfkill_mngr.input_dev) + input_unregister_device(priv->rfkill_mngr.input_dev); + + if (priv->rfkill_mngr.rfkill) + rfkill_unregister(priv->rfkill_mngr.rfkill); + + priv->rfkill_mngr.input_dev = NULL; + priv->rfkill_mngr.rfkill = NULL; +} + +/* set rf-kill to the right state. */ +void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv) +{ + + if (!priv->rfkill_mngr.rfkill) + return; + + if (!iwl3945_is_rfkill(priv)) + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; + else + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF; +} +#endif + /***************************************************************************** * * driver and module entry point