📄 iwl4965-base.c
字号:
/* These twh conditions has the same outcome but keep them separate since they have different meaning */ if (unlikely(index == IWL_INVALID_STATION)) { spin_unlock_irqrestore(&priv->sta_lock, flags_spin); return index; } if (priv->stations[index].used && !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { spin_unlock_irqrestore(&priv->sta_lock, flags_spin); return index; } IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); station = &priv->stations[index]; station->used = 1; priv->num_stations++; memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); memcpy(station->sta.sta.addr, addr, ETH_ALEN); station->sta.mode = 0; station->sta.sta.sta_id = index; station->sta.station_flags = 0;#ifdef CONFIG_IWLWIFI_HT /* BCAST station and IBSS stations do not work in HT mode */ if (index != priv->hw_setting.bcast_sta_id && priv->iw_mode != IEEE80211_IF_TYPE_IBSS) iwl4965_set_ht_add_station(priv, index);#endif /*CONFIG_IWLWIFI_HT*/ spin_unlock_irqrestore(&priv->sta_lock, flags_spin); iwl_send_add_station(priv, &station->sta, flags); return index;}/*************** DRIVER STATUS FUNCTIONS *****/static inline int iwl_is_ready(struct iwl_priv *priv){ /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are * set but EXIT_PENDING is not */ return test_bit(STATUS_READY, &priv->status) && test_bit(STATUS_GEO_CONFIGURED, &priv->status) && !test_bit(STATUS_EXIT_PENDING, &priv->status);}static inline int iwl_is_alive(struct iwl_priv *priv){ return test_bit(STATUS_ALIVE, &priv->status);}static inline int iwl_is_init(struct iwl_priv *priv){ return test_bit(STATUS_INIT, &priv->status);}static inline int iwl_is_rfkill(struct iwl_priv *priv){ return test_bit(STATUS_RF_KILL_HW, &priv->status) || test_bit(STATUS_RF_KILL_SW, &priv->status);}static inline int iwl_is_ready_rf(struct iwl_priv *priv){ if (iwl_is_rfkill(priv)) return 0; return iwl_is_ready(priv);}/*************** HOST COMMAND QUEUE FUNCTIONS *****/#define IWL_CMD(x) case x : return #xstatic const char *get_cmd_string(u8 cmd){ switch (cmd) { IWL_CMD(REPLY_ALIVE); IWL_CMD(REPLY_ERROR); IWL_CMD(REPLY_RXON); IWL_CMD(REPLY_RXON_ASSOC); IWL_CMD(REPLY_QOS_PARAM); IWL_CMD(REPLY_RXON_TIMING); IWL_CMD(REPLY_ADD_STA); IWL_CMD(REPLY_REMOVE_STA); IWL_CMD(REPLY_REMOVE_ALL_STA); IWL_CMD(REPLY_TX); IWL_CMD(REPLY_RATE_SCALE); IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); IWL_CMD(RADAR_NOTIFICATION); IWL_CMD(REPLY_QUIET_CMD); IWL_CMD(REPLY_CHANNEL_SWITCH); IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); IWL_CMD(POWER_TABLE_CMD); IWL_CMD(PM_SLEEP_NOTIFICATION); IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); IWL_CMD(REPLY_SCAN_CMD); IWL_CMD(REPLY_SCAN_ABORT_CMD); IWL_CMD(SCAN_START_NOTIFICATION); IWL_CMD(SCAN_RESULTS_NOTIFICATION); IWL_CMD(SCAN_COMPLETE_NOTIFICATION); IWL_CMD(BEACON_NOTIFICATION); IWL_CMD(REPLY_TX_BEACON); IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); IWL_CMD(QUIET_NOTIFICATION); IWL_CMD(REPLY_TX_PWR_TABLE_CMD); IWL_CMD(MEASURE_ABORT_NOTIFICATION); IWL_CMD(REPLY_BT_CONFIG); IWL_CMD(REPLY_STATISTICS_CMD); IWL_CMD(STATISTICS_NOTIFICATION); IWL_CMD(REPLY_CARD_STATE_CMD); IWL_CMD(CARD_STATE_NOTIFICATION); IWL_CMD(MISSED_BEACONS_NOTIFICATION); IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); IWL_CMD(SENSITIVITY_CMD); IWL_CMD(REPLY_PHY_CALIBRATION_CMD); IWL_CMD(REPLY_RX_PHY_CMD); IWL_CMD(REPLY_RX_MPDU_CMD); IWL_CMD(REPLY_4965_RX); IWL_CMD(REPLY_COMPRESSED_BA); default: return "UNKNOWN"; }}#define HOST_COMPLETE_TIMEOUT (HZ / 2)/** * iwl_enqueue_hcmd - enqueue a uCode command * @priv: device private data point * @cmd: a point to the ucode command structure * * The function returns < 0 values to indicate the operation is * failed. On success, it turns the index (> 0) of command in the * command queue. */static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd){ struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; struct iwl_tfd_frame *tfd; u32 *control_flags; struct iwl_cmd *out_cmd; u32 idx; u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); dma_addr_t phys_addr; int ret; unsigned long flags; /* If any of the command structures end up being larger than * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then * we will need to increase the size of the TFD entries */ BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->meta.flags & CMD_SIZE_HUGE)); if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERROR("No space for Tx\n"); return -ENOSPC; } spin_lock_irqsave(&priv->hcmd_lock, flags); tfd = &txq->bd[q->first_empty]; memset(tfd, 0, sizeof(*tfd)); control_flags = (u32 *) tfd; idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE); out_cmd = &txq->cmd[idx]; out_cmd->hdr.cmd = cmd->id; memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); /* At this point, the out_cmd now has all of the incoming cmd * information */ out_cmd->hdr.flags = 0; out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | INDEX_TO_SEQ(q->first_empty)); if (out_cmd->meta.flags & CMD_SIZE_HUGE) out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + offsetof(struct iwl_cmd, hdr); iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " "%d bytes at %d[%d]:%d\n", get_cmd_string(out_cmd->hdr.cmd), out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM); txq->need_update = 1; ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0); q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); iwl_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); return ret ? ret : idx;}int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd){ int ret; BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); /* An asynchronous command can not expect an SKB to be set. */ BUG_ON(cmd->meta.flags & CMD_WANT_SKB); /* An asynchronous command MUST have a callback. */ BUG_ON(!cmd->meta.u.callback); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EBUSY; ret = iwl_enqueue_hcmd(priv, cmd); if (ret < 0) { IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); return ret; } return 0;}int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd){ int cmd_idx; int ret; static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ BUG_ON(cmd->meta.flags & CMD_ASYNC); /* A synchronous command can not have a callback set. */ BUG_ON(cmd->meta.u.callback != NULL); if (atomic_xchg(&entry, 1)) { IWL_ERROR("Error sending %s: Already sending a host command\n", get_cmd_string(cmd->id)); return -EBUSY; } set_bit(STATUS_HCMD_ACTIVE, &priv->status); if (cmd->meta.flags & CMD_WANT_SKB) cmd->meta.source = &cmd->meta; cmd_idx = iwl_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); goto out; } ret = wait_event_interruptible_timeout(priv->wait_command_queue, !test_bit(STATUS_HCMD_ACTIVE, &priv->status), HOST_COMPLETE_TIMEOUT); if (!ret) { if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { IWL_ERROR("Error sending %s: time out after %dms.\n", get_cmd_string(cmd->id), jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); clear_bit(STATUS_HCMD_ACTIVE, &priv->status); ret = -ETIMEDOUT; goto cancel; } } if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", get_cmd_string(cmd->id)); ret = -ECANCELED; goto fail; } if (test_bit(STATUS_FW_ERROR, &priv->status)) { IWL_DEBUG_INFO("Command %s failed: FW Error\n", get_cmd_string(cmd->id)); ret = -EIO; goto fail; } if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { IWL_ERROR("Error: Response NULL in '%s'\n", get_cmd_string(cmd->id)); ret = -EIO; goto out; } ret = 0; goto out;cancel: if (cmd->meta.flags & CMD_WANT_SKB) { struct iwl_cmd *qcmd; /* Cancel the CMD_WANT_SKB flag for the cmd in the * TX cmd queue. Otherwise in case the cmd comes * in later, it will possibly set an invalid * address (cmd->meta.source). */ qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; qcmd->meta.flags &= ~CMD_WANT_SKB; }fail: if (cmd->meta.u.skb) { dev_kfree_skb_any(cmd->meta.u.skb); cmd->meta.u.skb = NULL; }out: atomic_set(&entry, 0); return ret;}int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd){ /* A command can not be asynchronous AND expect an SKB to be set. */ BUG_ON((cmd->meta.flags & CMD_ASYNC) && (cmd->meta.flags & CMD_WANT_SKB)); if (cmd->meta.flags & CMD_ASYNC) return iwl_send_cmd_async(priv, cmd); return iwl_send_cmd_sync(priv, cmd);}int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data){ struct iwl_host_cmd cmd = { .id = id, .len = len, .data = data, }; return iwl_send_cmd_sync(priv, &cmd);}static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val){ struct iwl_host_cmd cmd = { .id = id, .len = sizeof(val), .data = &val, }; return iwl_send_cmd_sync(priv, &cmd);}int iwl_send_statistics_request(struct iwl_priv *priv){ return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);}/** * iwl_rxon_add_station - add station into station table. * * there is only one AP station with id= IWL_AP_ID * NOTE: mutex must be held before calling the this fnction*/static int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap){ u8 sta_id; sta_id = iwl_add_station(priv, addr, is_ap, 0); iwl4965_add_station(priv, addr, is_ap); return sta_id;}/** * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz * @channel: Any channel valid for the requested phymode * In addition to setting the staging RXON, priv->phymode is also set. * * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the phymode */static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel){ if (!iwl_get_channel_info(priv, phymode, channel)) { IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", channel, phymode); return -EINVAL; } if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && (priv->phymode == phymode)) return 0; priv->staging_rxon.channel = cpu_to_le16(channel); if (phymode == MODE_IEEE80211A) priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; else priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; priv->phymode = phymode; IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); return 0;}/** * iwl_check_rxon_cmd - validate RXON structure is valid * * NOTE: This is really only useful during development and can eventually * be #ifdef'd out once the driver is stable and folks aren't actively * making changes */static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon){ int error = 0; int counter = 1; if (rxon->flags & RXON_FLG_BAND_24G_MSK) { error |= le32_to_cpu(rxon->flags & (RXON_FLG_TGJ_NARROW_BAND_MSK | RXON_FLG_RADAR_DETECT_MSK)); if (error) IWL_WARNING("check 24G fields %d | %d\n", counter++, error); } else { error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); if (error) IWL_WARNING("check 52 fields %d | %d\n", counter++, error); error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); if (error) IWL_WARNING("check 52 CCK %d | %d\n", counter++, error); } error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; if (error) IWL_WARNING("check mac addr %d | %d\n", counter++, error); /* make sure basic rates 6Mbps and 1Mbps are supported */ error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); if (error) IWL_WARNING("check basic rate %d | %d\n", counter++, error); error |= (le16_to_cpu(rxon->assoc_id) > 2007); if (error) IWL_WARNING("check assoc id %d | %d\n", counter++, error); error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); if (error) IWL_WARNING("check CCK and short slot %d | %d\n", counter++, error); error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); if (error) IWL_WARNING("check CCK & auto detect %d | %d\n", counter++, error); error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); if (error) IWL_WARNING("check TGG and auto detect %d | %d\n", counter++, error); if (error) IWL_WARNING("Tuning to channel %d\n", le16_to_cpu(rxon->channel)); if (error) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -