static int iwl_generic_cmd_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl_rx_packet *pkt = NULL; if (!skb) { IWL_ERROR("Error: Response NULL in %s.\n", get_cmd_string(cmd->hdr.cmd)); return 1; } pkt = (struct iwl_rx_packet *)skb->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); return 1; } #ifdef CONFIG_IWLWIFI_DEBUG switch (cmd->hdr.cmd) { case REPLY_TX_LINK_QUALITY_CMD: case SENSITIVITY_CMD: IWL_DEBUG_HC_DUMP("back from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); break; default: IWL_DEBUG_HC("back from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); } #endif /* Let iwl_tx_complete free the response skb */ return 1; }
void iwl_dump_nic_event_log(struct iwl_priv *priv) { int ret; u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); else base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERROR("Invalid event log pointer 0x%08X\n", base); return; } ret = iwl_grab_nic_access(priv); if (ret) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } /* event log header */ capacity = iwl_read_targ_mem(priv, base); mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); size = num_wraps ? capacity : next_entry; /* bail out if nothing in log */ if (size == 0) { IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); iwl_release_nic_access(priv); return; } IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n", size, num_wraps); /* if uCode has wrapped back to top of log, start at the oldest entry, * i.e the next one that uCode would fill. */ if (num_wraps) iwl_print_event_log(priv, next_entry, capacity - next_entry, mode); /* (then/else) start at top of log */ iwl_print_event_log(priv, 0, next_entry, mode); iwl_release_nic_access(priv); }
/* * Register led class with the system */ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led, enum led_type type, u8 set_led, char *trigger) { struct device *device = wiphy_dev(priv->hw->wiphy); int ret; led->led_dev.name = led->name; led->led_dev.brightness_set = iwl_led_brightness_set; led->led_dev.default_trigger = trigger; led->priv = priv; led->type = type; ret = led_classdev_register(device, &led->led_dev); if (ret) { IWL_ERROR("Error: failed to register led handler.\n"); return ret; } led->registered = 1; if (set_led && led->led_on) led->led_on(priv, IWL_LED_LINK); return 0; }
/** * iwl_print_event_log - Dump error event log to syslog * * NOTE: Must be called with iwl_grab_nic_access() already obtained! */ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 num_events, u32 mode) { u32 i; u32 base; /* SRAM byte address of event log header */ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ u32 ptr; /* SRAM byte address of log data */ u32 ev, time, data; /* event log data */ if (num_events == 0) return; if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); else base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (mode == 0) event_size = 2 * sizeof(u32); else event_size = 3 * sizeof(u32); ptr = base + EVENT_START_OFFSET + (start_idx * event_size); /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { ev = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); time = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); if (mode == 0) { /* data, ev */ IWL_ERROR("EVT_LOG:0x%08x:%04u\n", time, ev); } else { data = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); IWL_ERROR("EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); } } }
static ssize_t iwl_dbgfs_eeprom_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { ssize_t ret; struct iwl_priv *priv = (struct iwl_priv *)file->private_data; int pos = 0, ofs = 0, buf_size = 0; const u8 *ptr; char *buf; size_t eeprom_len = priv->cfg->eeprom_size; buf_size = 4 * eeprom_len + 256; if (eeprom_len % 16) { IWL_ERROR("EEPROM size is not multiple of 16.\n"); return -ENODATA; } /* 4 characters for byte 0xYY */ buf = kzalloc(buf_size, GFP_KERNEL); if (!buf) { IWL_ERROR("Can not allocate Buffer\n"); return -ENOMEM; } ptr = priv->eeprom; for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, buf_size - pos, 0); pos += strlen(buf); if (buf_size - pos > 0) buf[pos++] = '\n'; } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; }
static int iwl_generic_cmd_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl4965_rx_packet *pkt = NULL; if (!skb) { IWL_ERROR("Error: Response NULL in %s.\n", get_cmd_string(cmd->hdr.cmd)); return 1; } pkt = (struct iwl4965_rx_packet *)skb->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); return 1; } IWL_DEBUG_HC("back from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); /* Let iwl_tx_complete free the response skb */ return 1; }
void iwl_dump_nic_error_log(struct iwl_priv *priv) { u32 data2, line; u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; int ret; if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); else base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERROR("Not valid error log pointer 0x%08X\n", base); return; } ret = iwl_grab_nic_access(priv); if (ret) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } count = iwl_read_targ_mem(priv, base); if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERROR("Start IWL Error Log Dump:\n"); IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); } desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); IWL_ERROR("Desc Time " "data1 data2 line\n"); IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", desc_lookup(desc), desc, time, data1, data2, line); IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, ilink1, ilink2); iwl_release_nic_access(priv); }
int iwl_hw_nic_init(struct iwl_priv *priv) { unsigned long flags; struct iwl_rx_queue *rxq = &priv->rxq; int ret; /* nic_init */ spin_lock_irqsave(&priv->lock, flags); priv->cfg->ops->lib->apm_ops.init(priv); iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); spin_unlock_irqrestore(&priv->lock, flags); ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); priv->cfg->ops->lib->apm_ops.config(priv); /* Allocate the RX queue, or reset if it is already allocated */ if (!rxq->bd) { ret = iwl_rx_queue_alloc(priv); if (ret) { IWL_ERROR("Unable to initialize Rx queue\n"); return -ENOMEM; } } else iwl_rx_queue_reset(priv, rxq); iwl_rx_replenish(priv); iwl_rx_init(priv, rxq); spin_lock_irqsave(&priv->lock, flags); rxq->need_update = 1; iwl_rx_queue_update_write_ptr(priv, rxq); spin_unlock_irqrestore(&priv->lock, flags); /* Allocate and init all Tx and Command queues */ ret = iwl_txq_ctx_reset(priv); if (ret) return ret; set_bit(STATUS_INIT, &priv->status); return 0; }
/** * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ int iwl_verify_ucode(struct iwl_priv *priv) { __le32 *image; u32 len; int ret; /* Try bootstrap */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; ret = iwlcore_verify_inst_sparse(priv, image, len); if (!ret) { IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); return 0; } /* Try initialize */ image = (__le32 *)priv->ucode_init.v_addr; len = priv->ucode_init.len; ret = iwlcore_verify_inst_sparse(priv, image, len); if (!ret) { IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); return 0; } /* Try runtime/protocol */ image = (__le32 *)priv->ucode_code.v_addr; len = priv->ucode_code.len; ret = iwlcore_verify_inst_sparse(priv, image, len); if (!ret) { IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); return 0; } IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); /* Since nothing seems to match, show first several data entries in * instruction SRAM, so maybe visual inspection will give a clue. * Selection of bootstrap image (vs. other images) is arbitrary. */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; ret = iwl_verify_inst_full(priv, image, len); return ret; }
/** * iwl_clear_stations_table - Clear the driver's station table * * NOTE: This does not clear or otherwise alter the device's station table. */ void iwl_clear_stations_table(struct iwl_priv *priv) { unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); if (iwl_is_alive(priv) && !test_bit(STATUS_EXIT_PENDING, &priv->status) && iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) IWL_ERROR("Couldn't clear the station table\n"); priv->num_stations = 0; memset(priv->stations, 0, sizeof(priv->stations)); /* clean ucode key table bit map */ priv->ucode_key_table = 0; spin_unlock_irqrestore(&priv->sta_lock, flags); }
/* This function both allocates and initializes hw and priv. */ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops) { struct iwl_priv *priv; /* mac80211 allocates memory for this device instance, including * space for this driver's private structure */ struct ieee80211_hw *hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops); if (hw == NULL) { IWL_ERROR("Can not allocate network device\n"); goto out; } priv = hw->priv; priv->hw = hw; out: return hw; }
/** * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, * looking at all data. */ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 len) { u32 val; u32 save_len = len; int ret = 0; u32 errcnt; IWL_DEBUG_INFO("ucode inst image size is %u\n", len); ret = iwl_grab_nic_access(priv); if (ret) return ret; iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); errcnt = 0; for (; len > 0; len -= sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { IWL_ERROR("uCode INST section is invalid at " "offset 0x%x, is 0x%x, s/b 0x%x\n", save_len - len, val, le32_to_cpu(*image)); ret = -EIO; errcnt++; if (errcnt >= 20) break; } } iwl_release_nic_access(priv); if (!errcnt) IWL_DEBUG_INFO ("ucode image in INSTRUCTION memory is good\n"); return ret; }
/* * Create the debugfs files and directories * */ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) { struct iwl_debugfs *dbgfs; struct dentry *phyd = priv->hw->wiphy->debugfsdir; int ret = 0; dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); if (!dbgfs) { ret = -ENOMEM; goto err; } priv->dbgfs = dbgfs; dbgfs->name = name; dbgfs->dir_drv = debugfs_create_dir(name, phyd); if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)) { ret = -ENOENT; goto err; } DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); DEBUGFS_ADD_FILE(eeprom, data); DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(log_event, data); DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data); DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal); return 0; err: IWL_ERROR("Can't open the debugfs directory\n"); iwl_dbgfs_unregister(priv); return ret; }
int iwl_setup_mac(struct iwl_priv *priv) { int ret; struct ieee80211_hw *hw = priv->hw; hw->rate_control_algorithm = "iwl-agn-rs"; /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; /* queues to support 11n aggregation */ if (priv->cfg->sku & IWL_SKU_N) hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues; hw->conf.beacon_int = 100; hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->bands[IEEE80211_BAND_2GHZ]; if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; ret = ieee80211_register_hw(priv->hw); if (ret) { IWL_ERROR("Failed to register hw (error %d)\n", ret); return ret; } priv->mac80211_registered = 1; return 0; }
void iwl_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl_ct_kill_config cmd; unsigned long flags; int ret = 0; spin_lock_irqsave(&priv->lock, flags); iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); cmd.critical_temperature_R = cpu_to_le32(priv->hw_params.ct_kill_threshold); ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); if (ret) IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); else IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded, " "critical temperature is %d\n", cmd.critical_temperature_R); }
static 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); /* Assign a generic callback if one is not provided */ if (!cmd->meta.u.callback) cmd->meta.u.callback = iwl_generic_cmd_callback; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EBUSY; ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); if (ret < 0) { IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); return ret; } return 0; }
static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) { int idle_cnt; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); /* # Rx chains when idling and maybe trying to save power */ switch (priv->current_ht_config.sm_ps) { case WLAN_HT_CAP_SM_PS_STATIC: case WLAN_HT_CAP_SM_PS_DYNAMIC: idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : IWL_NUM_IDLE_CHAINS_SINGLE; break; case WLAN_HT_CAP_SM_PS_DISABLED: idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; break; case WLAN_HT_CAP_SM_PS_INVALID: default: IWL_ERROR("invalide mimo ps mode %d\n", priv->current_ht_config.sm_ps); WARN_ON(1); idle_cnt = -1; break; } return idle_cnt; }
int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { int cmd_idx; int ret; BUG_ON(cmd->meta.flags & CMD_ASYNC); /* A synchronous command can not have a callback set. */ BUG_ON(cmd->meta.u.callback != NULL); if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) { IWL_ERROR("Error sending %s: Already sending a host command\n", get_cmd_string(cmd->id)); ret = -EBUSY; goto out; } set_bit(STATUS_HCMD_ACTIVE, &priv->status); if (cmd->meta.flags & CMD_WANT_SKB) cmd->meta.source = &cmd->meta; cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; IWL_ERROR("Error sending %s: 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: clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); return ret; }
static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; struct ieee80211_channel *channels = NULL; const struct ieee80211_supported_band *supp_band = NULL; int pos = 0, i, bufsz = PAGE_SIZE; char *buf; ssize_t ret; if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERROR("Can not allocate Buffer\n"); return -ENOMEM; } supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); channels = supp_band->channels; pos += scnprintf(buf + pos, bufsz - pos, "Displaying %d channels in 2.4GHz band 802.11bg):\n", supp_band->n_channels); for (i = 0; i < supp_band->n_channels; i++) pos += scnprintf(buf + pos, bufsz - pos, "%d: %ddBm: BSS%s%s, %s.\n", ieee80211_frequency_to_channel( channels[i].center_freq), channels[i].max_power, channels[i].flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) || (channels[i].flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN ? "passive only" : "active/passive"); supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); channels = supp_band->channels; pos += scnprintf(buf + pos, bufsz - pos, "Displaying %d channels in 5.2GHz band (802.11a)\n", supp_band->n_channels); for (i = 0; i < supp_band->n_channels; i++) pos += scnprintf(buf + pos, bufsz - pos, "%d: %ddBm: BSS%s%s, %s.\n", ieee80211_frequency_to_channel( channels[i].center_freq), channels[i].max_power, channels[i].flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) || (channels[i].flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN ? "passive only" : "active/passive"); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; }
int iwl_init_drv(struct iwl_priv *priv) { int ret; priv->retry_rate = 1; priv->ibss_beacon = NULL; spin_lock_init(&priv->lock); spin_lock_init(&priv->power_data.lock); spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ iwl_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; priv->ieee_rates = NULL; priv->band = IEEE80211_BAND_2GHZ; priv->iw_mode = NL80211_IFTYPE_STATION; priv->use_ant_b_for_management_frame = 1; /* start with ant B */ priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ iwl_set_rxon_chain(priv); iwl_init_scan_params(priv); if (priv->cfg->mod_params->enable_qos) priv->qos_data.qos_enable = 1; iwl_reset_qos(priv); priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; priv->rates_mask = IWL_RATES_MASK; /* If power management is turned on, default to AC mode */ priv->power_mode = IWL_POWER_AC; priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; ret = iwl_init_channel_map(priv); if (ret) { IWL_ERROR("initializing regulatory failed: %d\n", ret); goto err; } ret = iwlcore_init_geos(priv); if (ret) { IWL_ERROR("initializing geos failed: %d\n", ret); goto err_free_channel_map; } return 0; err_free_channel_map: iwl_free_channel_map(priv); err: return ret; }
/* Send led command */ static int iwl_send_led_cmd(struct iwl3945_priv *priv, struct iwl3945_led_cmd *led_cmd) { struct iwl3945_host_cmd cmd = { .id = REPLY_LEDS_CMD, .len = sizeof(struct iwl3945_led_cmd), .data = led_cmd, .meta.flags = CMD_ASYNC, .meta.u.callback = iwl3945_led_cmd_callback, }; return iwl3945_send_cmd(priv, &cmd); } /* Set led on command */ static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id, unsigned int idx) { struct iwl3945_led_cmd led_cmd = { .id = led_id, .interval = IWL_DEF_LED_INTRVL }; BUG_ON(idx > IWL_MAX_BLINK_TBL); led_cmd.on = blink_tbl[idx].on_time; led_cmd.off = blink_tbl[idx].off_time; return iwl_send_led_cmd(priv, &led_cmd); } #if 1 /* Set led on command */ static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id) { struct iwl3945_led_cmd led_cmd = { .id = led_id, .on = IWL_LED_SOLID, .off = 0, .interval = IWL_DEF_LED_INTRVL }; return iwl_send_led_cmd(priv, &led_cmd); } /* Set led off command */ static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id) { struct iwl3945_led_cmd led_cmd = { .id = led_id, .on = 0, .off = 0, .interval = IWL_DEF_LED_INTRVL }; IWL_DEBUG_LED("led off %d\n", led_id); return iwl_send_led_cmd(priv, &led_cmd); } #endif /* * brightness call back function for Tx/Rx LED */ static int iwl3945_led_associated(struct iwl3945_priv *priv, int led_id) { if (test_bit(STATUS_EXIT_PENDING, &priv->status) || !test_bit(STATUS_READY, &priv->status)) return 0; /* start counting Tx/Rx bytes */ if (!priv->last_blink_time && priv->allow_blinking) priv->last_blink_time = jiffies; return 0; } /* * brightness call back for association and radio */ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { struct iwl3945_led *led = container_of(led_cdev, struct iwl3945_led, led_dev); struct iwl3945_priv *priv = led->priv; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; switch (brightness) { case LED_FULL: if (led->type == IWL_LED_TRG_ASSOC) { priv->allow_blinking = 1; IWL_DEBUG_LED("MAC is associated\n"); } if (led->led_on) led->led_on(priv, IWL_LED_LINK); break; case LED_OFF: if (led->type == IWL_LED_TRG_ASSOC) { priv->allow_blinking = 0; IWL_DEBUG_LED("MAC is disassociated\n"); } if (led->led_off) led->led_off(priv, IWL_LED_LINK); break; default: if (led->led_pattern) { int idx = iwl3945_brightness_to_idx(brightness); led->led_pattern(priv, IWL_LED_LINK, idx); } break; } } /* * Register led class with the system */ static int iwl3945_led_register_led(struct iwl3945_priv *priv, struct iwl3945_led *led, enum led_type type, u8 set_led, char *trigger) { struct device *device = wiphy_dev(priv->hw->wiphy); int ret; led->led_dev.name = led->name; led->led_dev.brightness_set = iwl3945_led_brightness_set; led->led_dev.default_trigger = trigger; led->priv = priv; led->type = type; ret = led_classdev_register(device, &led->led_dev); if (ret) { IWL_ERROR("Error: failed to register led handler.\n"); return ret; } led->registered = 1; if (set_led && led->led_on) led->led_on(priv, IWL_LED_LINK); return 0; } /* * calculate blink rate according to last 2 sec Tx/Rx activities */ static inline u8 get_blink_rate(struct iwl3945_priv *priv) { int index; u64 current_tpt = priv->rxtxpackets; s64 tpt = current_tpt - priv->led_tpt; if (tpt < 0) tpt = -tpt; priv->led_tpt = current_tpt; if (!priv->allow_blinking) index = IWL_MAX_BLINK_TBL; else for (index = 0; index < IWL_MAX_BLINK_TBL; index++) if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE)) break; return index; } static inline int is_rf_kill(struct iwl3945_priv *priv) { return test_bit(STATUS_RF_KILL_HW, &priv->status) || test_bit(STATUS_RF_KILL_SW, &priv->status); } /* * this function called from handler. Since setting Led command can * happen very frequent we postpone led command to be called from * REPLY handler so we know ucode is up */ void iwl3945_led_background(struct iwl3945_priv *priv) { u8 blink_idx; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { priv->last_blink_time = 0; return; } if (is_rf_kill(priv)) { priv->last_blink_time = 0; return; } if (!priv->allow_blinking) { priv->last_blink_time = 0; if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { priv->last_blink_rate = IWL_SOLID_BLINK_IDX; iwl3945_led_pattern(priv, IWL_LED_LINK, IWL_SOLID_BLINK_IDX); } return; } if (!priv->last_blink_time || !time_after(jiffies, priv->last_blink_time + msecs_to_jiffies(1000))) return; blink_idx = get_blink_rate(priv); /* call only if blink rate change */ if (blink_idx != priv->last_blink_rate) iwl3945_led_pattern(priv, IWL_LED_LINK, blink_idx); priv->last_blink_time = jiffies; priv->last_blink_rate = blink_idx; priv->rxtxpackets = 0; } /* Register all led handler */ int iwl3945_led_register(struct iwl3945_priv *priv) { char *trigger; int ret; priv->last_blink_rate = 0; priv->rxtxpackets = 0; priv->led_tpt = 0; priv->last_blink_time = 0; priv->allow_blinking = 0; trigger = ieee80211_get_radio_led_name(priv->hw); snprintf(priv->led[IWL_LED_TRG_RADIO].name, sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s:radio", wiphy_name(priv->hw->wiphy)); priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on; priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off; priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; ret = iwl3945_led_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], IWL_LED_TRG_RADIO, 1, trigger); if (ret) goto exit_fail; trigger = ieee80211_get_assoc_led_name(priv->hw); snprintf(priv->led[IWL_LED_TRG_ASSOC].name, sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s:assoc", wiphy_name(priv->hw->wiphy)); ret = iwl3945_led_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC], IWL_LED_TRG_ASSOC, 0, trigger); /* for assoc always turn led on */ priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on; priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on; priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; if (ret) goto exit_fail; trigger = ieee80211_get_rx_led_name(priv->hw); snprintf(priv->led[IWL_LED_TRG_RX].name, sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s:RX", wiphy_name(priv->hw->wiphy)); ret = iwl3945_led_register_led(priv, &priv->led[IWL_LED_TRG_RX], IWL_LED_TRG_RX, 0, trigger); priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated; priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated; priv->led[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern; if (ret) goto exit_fail; trigger = ieee80211_get_tx_led_name(priv->hw); snprintf(priv->led[IWL_LED_TRG_TX].name, sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy)); ret = iwl3945_led_register_led(priv, &priv->led[IWL_LED_TRG_TX], IWL_LED_TRG_TX, 0, trigger); priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated; priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated; priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern; if (ret) goto exit_fail; return 0; exit_fail: iwl3945_led_unregister(priv); return ret; }