/* * This function handles the user application commands for driver. * * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the * handlers respectively. * * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned * value of the actual command execution is replied to the user application. * * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP * is used for carry the message while IWL_TM_ATTR_COMMAND must set to * IWL_TM_CMD_DEV2APP_SYNC_RSP. * * @hw: ieee80211_hw object that represents the device * @tb: gnl message fields from the user space */ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) { struct iwl_priv *priv = hw->priv; struct iwl_trans *trans = trans(priv); struct sk_buff *skb; unsigned char *rsp_data_ptr = NULL; int status = 0, rsp_data_len = 0; u32 devid; switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: rsp_data_ptr = (unsigned char *)cfg(priv)->name; rsp_data_len = strlen(cfg(priv)->name); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, rsp_data_len + 20); if (!skb) { IWL_DEBUG_INFO(priv, "Error allocating memory\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_SYNC_RSP); NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP, rsp_data_len, rsp_data_ptr); status = cfg80211_testmode_reply(skb); if (status < 0) IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT); if (status) IWL_DEBUG_INFO(priv, "Error loading init ucode: %d\n", status); break; case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: iwl_testmode_cfg_init_calib(priv); iwl_trans_stop_device(trans); break; case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR); if (status) { IWL_DEBUG_INFO(priv, "Error loading runtime ucode: %d\n", status); break; } status = iwl_alive_start(priv); if (status) IWL_DEBUG_INFO(priv, "Error starting the device: %d\n", status); break; case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: iwl_scan_cancel_timeout(priv, 200); iwl_trans_stop_device(trans); status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN); if (status) { IWL_DEBUG_INFO(priv, "Error loading WOWLAN ucode: %d\n", status); break; } status = iwl_alive_start(priv); if (status) IWL_DEBUG_INFO(priv, "Error starting the device: %d\n", status); break; case IWL_TM_CMD_APP2DEV_GET_EEPROM: if (priv->shrd->eeprom) { skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, cfg(priv)->base_params->eeprom_size + 20); if (!skb) { IWL_DEBUG_INFO(priv, "Error allocating memory\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_EEPROM_RSP); NLA_PUT(skb, IWL_TM_ATTR_EEPROM, cfg(priv)->base_params->eeprom_size, priv->shrd->eeprom); status = cfg80211_testmode_reply(skb); if (status < 0) IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", status); } else return -EFAULT; break; case IWL_TM_CMD_APP2DEV_FIXRATE_REQ: if (!tb[IWL_TM_ATTR_FIXRATE]) { IWL_DEBUG_INFO(priv, "Error finding fixrate setting\n"); return -ENOMSG; } priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]); break; case IWL_TM_CMD_APP2DEV_GET_FW_VERSION: IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { IWL_DEBUG_INFO(priv, "Error allocating memory\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver); status = cfg80211_testmode_reply(skb); if (status < 0) IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: devid = bus_get_hw_id(bus(priv)); IWL_INFO(priv, "hw version: 0x%x\n", devid); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); if (!skb) { IWL_DEBUG_INFO(priv, "Error allocating memory\n"); return -ENOMEM; } NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid); status = cfg80211_testmode_reply(skb); if (status < 0) IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", status); break; default: IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); return -ENOSYS; } return status; nla_put_failure: kfree_skb(skb); return -EMSGSIZE; }
/** * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom */ int iwl_init_geos(struct iwl_priv *priv) { struct iwl_channel_info *ch; struct ieee80211_supported_band *sband; struct ieee80211_channel *channels; struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN; if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n"); set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status); return 0; } channels = kcalloc(priv->channel_count, sizeof(struct ieee80211_channel), GFP_KERNEL); if (!channels) return -ENOMEM; rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate), GFP_KERNEL); if (!rates) { kfree(channels); return -ENOMEM; } /* 5.2GHz channels start after the 2.4GHz channels */ sband = &priv->bands[IEEE80211_BAND_5GHZ]; sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; /* just OFDM */ sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE; if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) iwl_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_5GHZ); sband = &priv->bands[IEEE80211_BAND_2GHZ]; sband->channels = channels; /* OFDM & CCK */ sband->bitrates = rates; sband->n_bitrates = IWL_RATE_COUNT_LEGACY; if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) iwl_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_2GHZ); priv->ieee_channels = channels; priv->ieee_rates = rates; for (i = 0; i < priv->channel_count; i++) { ch = &priv->channel_info[i]; /* FIXME: might be removed if scan is OK */ if (!is_channel_valid(ch)) continue; sband = &priv->bands[ch->band]; geo_ch = &sband->channels[sband->n_channels++]; geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel, ch->band); geo_ch->max_power = ch->max_power_avg; geo_ch->max_antenna_gain = 0xff; geo_ch->hw_value = ch->channel; if (is_channel_valid(ch)) { if (!(ch->flags & EEPROM_CHANNEL_IBSS)) geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; if (ch->flags & EEPROM_CHANNEL_RADAR) geo_ch->flags |= IEEE80211_CHAN_RADAR; geo_ch->flags |= ch->ht40_extension_channel; if (ch->max_power_avg > max_tx_power) max_tx_power = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n", ch->channel, geo_ch->center_freq, is_channel_a_band(ch) ? "5.2" : "2.4", geo_ch->flags & IEEE80211_CHAN_DISABLED ? "restricted" : "valid", geo_ch->flags); } priv->tx_power_device_lmt = max_tx_power; priv->tx_power_user_lmt = max_tx_power; priv->tx_power_next = max_tx_power; if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->cfg->sku & EEPROM_SKU_CAP_BAND_52GHZ) { char buf[32]; bus_get_hw_id(bus(priv), buf, sizeof(buf)); IWL_INFO(priv, "Incorrectly detected BG card as ABG. " "Please send your %s to maintainer.\n", buf); priv->cfg->sku &= ~EEPROM_SKU_CAP_BAND_52GHZ; } IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n", priv->bands[IEEE80211_BAND_2GHZ].n_channels, priv->bands[IEEE80211_BAND_5GHZ].n_channels); set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status); return 0; }