📄 ipw2200.c
字号:
}static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, show_net_stats, store_net_stats);static void notify_wx_assoc_event(struct ipw_priv *priv){ union iwreq_data wrqu; wrqu.ap_addr.sa_family = ARPHRD_ETHER; if (priv->status & STATUS_ASSOCIATED) memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); else memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);}static void ipw_irq_tasklet(struct ipw_priv *priv){ u32 inta, inta_mask, handled = 0; unsigned long flags; int rc = 0; spin_lock_irqsave(&priv->irq_lock, flags); inta = ipw_read32(priv, IPW_INTA_RW); inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); inta &= (IPW_INTA_MASK_ALL & inta_mask); /* Add any cached INTA values that need to be handled */ inta |= priv->isr_inta; spin_unlock_irqrestore(&priv->irq_lock, flags); spin_lock_irqsave(&priv->lock, flags); /* handle all the justifications for the interrupt */ if (inta & IPW_INTA_BIT_RX_TRANSFER) { ipw_rx(priv); handled |= IPW_INTA_BIT_RX_TRANSFER; } if (inta & IPW_INTA_BIT_TX_CMD_QUEUE) { IPW_DEBUG_HC("Command completed.\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1); priv->status &= ~STATUS_HCMD_ACTIVE; wake_up_interruptible(&priv->wait_command_queue); handled |= IPW_INTA_BIT_TX_CMD_QUEUE; } if (inta & IPW_INTA_BIT_TX_QUEUE_1) { IPW_DEBUG_TX("TX_QUEUE_1\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq[0], 0); handled |= IPW_INTA_BIT_TX_QUEUE_1; } if (inta & IPW_INTA_BIT_TX_QUEUE_2) { IPW_DEBUG_TX("TX_QUEUE_2\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq[1], 1); handled |= IPW_INTA_BIT_TX_QUEUE_2; } if (inta & IPW_INTA_BIT_TX_QUEUE_3) { IPW_DEBUG_TX("TX_QUEUE_3\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq[2], 2); handled |= IPW_INTA_BIT_TX_QUEUE_3; } if (inta & IPW_INTA_BIT_TX_QUEUE_4) { IPW_DEBUG_TX("TX_QUEUE_4\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq[3], 3); handled |= IPW_INTA_BIT_TX_QUEUE_4; } if (inta & IPW_INTA_BIT_STATUS_CHANGE) { IPW_WARNING("STATUS_CHANGE\n"); handled |= IPW_INTA_BIT_STATUS_CHANGE; } if (inta & IPW_INTA_BIT_BEACON_PERIOD_EXPIRED) { IPW_WARNING("TX_PERIOD_EXPIRED\n"); handled |= IPW_INTA_BIT_BEACON_PERIOD_EXPIRED; } if (inta & IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) { IPW_WARNING("HOST_CMD_DONE\n"); handled |= IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE; } if (inta & IPW_INTA_BIT_FW_INITIALIZATION_DONE) { IPW_WARNING("FW_INITIALIZATION_DONE\n"); handled |= IPW_INTA_BIT_FW_INITIALIZATION_DONE; } if (inta & IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) { IPW_WARNING("PHY_OFF_DONE\n"); handled |= IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE; } if (inta & IPW_INTA_BIT_RF_KILL_DONE) { IPW_DEBUG_RF_KILL("RF_KILL_DONE\n"); priv->status |= STATUS_RF_KILL_HW; wake_up_interruptible(&priv->wait_command_queue); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); cancel_delayed_work(&priv->request_scan); schedule_work(&priv->link_down); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); handled |= IPW_INTA_BIT_RF_KILL_DONE; } if (inta & IPW_INTA_BIT_FATAL_ERROR) { IPW_WARNING("Firmware error detected. Restarting.\n"); if (priv->error) { IPW_DEBUG_FW("Sysfs 'error' log already exists.\n"); if (ipw_debug_level & IPW_DL_FW_ERRORS) { struct ipw_fw_error *error = ipw_alloc_error_log(priv); ipw_dump_error_log(priv, error); kfree(error); } } else { priv->error = ipw_alloc_error_log(priv); if (priv->error) IPW_DEBUG_FW("Sysfs 'error' log captured.\n"); else IPW_DEBUG_FW("Error allocating sysfs 'error' " "log.\n"); if (ipw_debug_level & IPW_DL_FW_ERRORS) ipw_dump_error_log(priv, priv->error); } /* XXX: If hardware encryption is for WPA/WPA2, * we have to notify the supplicant. */ if (priv->ieee->sec.encrypt) { priv->status &= ~STATUS_ASSOCIATED; notify_wx_assoc_event(priv); } /* Keep the restart process from trying to send host * commands by clearing the INIT status bit */ priv->status &= ~STATUS_INIT; /* Cancel currently queued command. */ priv->status &= ~STATUS_HCMD_ACTIVE; wake_up_interruptible(&priv->wait_command_queue); queue_work(priv->workqueue, &priv->adapter_restart); handled |= IPW_INTA_BIT_FATAL_ERROR; } if (inta & IPW_INTA_BIT_PARITY_ERROR) { IPW_ERROR("Parity error\n"); handled |= IPW_INTA_BIT_PARITY_ERROR; } if (handled != inta) { IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); } spin_unlock_irqrestore(&priv->lock, flags); /* enable all interrupts */ ipw_enable_interrupts(priv);}#define IPW_CMD(x) case IPW_CMD_ ## x : return #xstatic char *get_cmd_string(u8 cmd){ switch (cmd) { IPW_CMD(HOST_COMPLETE); IPW_CMD(POWER_DOWN); IPW_CMD(SYSTEM_CONFIG); IPW_CMD(MULTICAST_ADDRESS); IPW_CMD(SSID); IPW_CMD(ADAPTER_ADDRESS); IPW_CMD(PORT_TYPE); IPW_CMD(RTS_THRESHOLD); IPW_CMD(FRAG_THRESHOLD); IPW_CMD(POWER_MODE); IPW_CMD(WEP_KEY); IPW_CMD(TGI_TX_KEY); IPW_CMD(SCAN_REQUEST); IPW_CMD(SCAN_REQUEST_EXT); IPW_CMD(ASSOCIATE); IPW_CMD(SUPPORTED_RATES); IPW_CMD(SCAN_ABORT); IPW_CMD(TX_FLUSH); IPW_CMD(QOS_PARAMETERS); IPW_CMD(DINO_CONFIG); IPW_CMD(RSN_CAPABILITIES); IPW_CMD(RX_KEY); IPW_CMD(CARD_DISABLE); IPW_CMD(SEED_NUMBER); IPW_CMD(TX_POWER); IPW_CMD(COUNTRY_INFO); IPW_CMD(AIRONET_INFO); IPW_CMD(AP_TX_POWER); IPW_CMD(CCKM_INFO); IPW_CMD(CCX_VER_INFO); IPW_CMD(SET_CALIBRATION); IPW_CMD(SENSITIVITY_CALIB); IPW_CMD(RETRY_LIMIT); IPW_CMD(IPW_PRE_POWER_DOWN); IPW_CMD(VAP_BEACON_TEMPLATE); IPW_CMD(VAP_DTIM_PERIOD); IPW_CMD(EXT_SUPPORTED_RATES); IPW_CMD(VAP_LOCAL_TX_PWR_CONSTRAINT); IPW_CMD(VAP_QUIET_INTERVALS); IPW_CMD(VAP_CHANNEL_SWITCH); IPW_CMD(VAP_MANDATORY_CHANNELS); IPW_CMD(VAP_CELL_PWR_LIMIT); IPW_CMD(VAP_CF_PARAM_SET); IPW_CMD(VAP_SET_BEACONING_STATE); IPW_CMD(MEASUREMENT); IPW_CMD(POWER_CAPABILITY); IPW_CMD(SUPPORTED_CHANNELS); IPW_CMD(TPC_REPORT); IPW_CMD(WME_INFO); IPW_CMD(PRODUCTION_COMMAND); default: return "UNKNOWN"; }}#define HOST_COMPLETE_TIMEOUT HZstatic int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd){ int rc = 0; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_HCMD_ACTIVE) { IPW_ERROR("Failed to send %s: Already sending a command.\n", get_cmd_string(cmd->cmd)); spin_unlock_irqrestore(&priv->lock, flags); return -EAGAIN; } priv->status |= STATUS_HCMD_ACTIVE; if (priv->cmdlog) { priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies; priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd; priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len; memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param, cmd->len); priv->cmdlog[priv->cmdlog_pos].retcode = -1; } IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n", get_cmd_string(cmd->cmd), cmd->cmd, cmd->len, priv->status);#ifndef DEBUG_CMD_WEP_KEY if (cmd->cmd == IPW_CMD_WEP_KEY) IPW_DEBUG_HC("WEP_KEY command masked out for secure.\n"); else#endif printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0); if (rc) { priv->status &= ~STATUS_HCMD_ACTIVE; IPW_ERROR("Failed to send %s: Reason %d\n", get_cmd_string(cmd->cmd), rc); spin_unlock_irqrestore(&priv->lock, flags); goto exit; } spin_unlock_irqrestore(&priv->lock, flags); rc = wait_event_interruptible_timeout(priv->wait_command_queue, !(priv-> status & STATUS_HCMD_ACTIVE), HOST_COMPLETE_TIMEOUT); if (rc == 0) { spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_HCMD_ACTIVE) { IPW_ERROR("Failed to send %s: Command timed out.\n", get_cmd_string(cmd->cmd)); priv->status &= ~STATUS_HCMD_ACTIVE; spin_unlock_irqrestore(&priv->lock, flags); rc = -EIO; goto exit; } spin_unlock_irqrestore(&priv->lock, flags); } else rc = 0; if (priv->status & STATUS_RF_KILL_HW) { IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n", get_cmd_string(cmd->cmd)); rc = -EIO; goto exit; } exit: if (priv->cmdlog) { priv->cmdlog[priv->cmdlog_pos++].retcode = rc; priv->cmdlog_pos %= priv->cmdlog_len; } return rc;}static int ipw_send_cmd_simple(struct ipw_priv *priv, u8 command){ struct host_cmd cmd = { .cmd = command, }; return __ipw_send_cmd(priv, &cmd);}static int ipw_send_cmd_pdu(struct ipw_priv *priv, u8 command, u8 len, void *data){ struct host_cmd cmd = { .cmd = command, .len = len, .param = data, }; return __ipw_send_cmd(priv, &cmd);}static int ipw_send_host_complete(struct ipw_priv *priv){ if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE);}static int ipw_send_system_config(struct ipw_priv *priv){ return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, sizeof(priv->sys_config), &priv->sys_config);}static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len){ if (!priv || !ssid) { IPW_ERROR("Invalid args\n"); return -1; } return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE), ssid);}static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac){ if (!priv || !mac) { IPW_ERROR("Invalid args\n"); return -1; } IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(mac)); return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);}/* * NOTE: This must be executed from our workqueue as it results in udelay * being called which may corrupt the keyboard if executed on default * workqueue */static void ipw_adapter_restart(void *adapter){ struct ipw_priv *priv = adapter; if (priv->status & STATUS_RF_KILL_MASK) return; ipw_down(priv); if (priv->assoc_network && (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS)) ipw_remove_current_network(priv); if (ipw_up(priv)) { IPW_ERROR("Failed to up device\n"); return; }}static void ipw_bg_adapter_restart(void *data){ struct ipw_priv *priv = data; mutex_lock(&priv->mutex); ipw_adapter_restart(data); mutex_unlock(&priv->mutex);}#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)static void ipw_scan_check(void *data){ struct ipw_priv *priv = data; if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { IPW_DEBUG_SCAN("Scan completion watchdog resetting " "adapter after (%dms).\n", jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG)); queue_work(priv->workqueue, &priv->adapter_restart); }}static void ipw_bg_scan_check(void *data){ struct ipw_priv *priv = data; mutex_lock(&priv->mutex); ipw_scan_check(data); mutex_unlock(&priv->mutex);}static int ipw_send_scan_request_ext(struct ipw_priv *priv, struct ipw_scan_request_ext *request){ return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT, sizeof(*request), request);}static int ipw_send_scan_abort(struct ipw_priv *priv){ if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } return ipw_send_cmd_simple(priv, IPW_CMD_SCAN_ABORT);}static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens){ struct ipw_sensitivity_calib calib = { .beacon_rssi_raw = cpu_to_le16(sens), }; return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib), &calib);}static int ipw_send_associate(struct ipw_priv *priv, struct ipw_associate *associate){ struct ipw_associate tmp_associate; if (!priv || !associate) { IPW_ERROR("Invalid args\n"); return -1; } memcpy(&tmp_associate, associate, sizeof(*associate)); tmp_associate.policy_support = cpu_to_le16(tmp_associate.policy_support); tmp_associate.assoc_tsf_msw = cpu_to_le32(tmp_associate.assoc_tsf_msw); tmp_associate.assoc_tsf_lsw = cpu_to_le32(tmp_associate.assoc_tsf_lsw); tmp_associate.capability = cpu_to_le16(tmp_associate.capability); tmp_associate.listen_interval = cpu_to_le16(tmp_associate.listen_interval); tmp_associate.beacon_interval = cpu_to_le16(tmp_associate.beacon_interval); tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window); return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(tmp_associate), &tmp_associate);}static int ipw_send_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *rates){ if (!priv || !rates) { IPW_ERROR("Invalid args\n"); return -1; } return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates), rates);}static int ipw_set_r
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -