📄 ipw2200.c
字号:
else reg = 0; return sprintf(buf, "0x%02x\n", reg);}static ssize_t store_indirect_byte(struct device *d, struct device_attribute *attr, const char *buf, size_t count){ struct ipw_priv *priv = d->driver_data; sscanf(buf, "%x", &priv->indirect_byte); priv->status |= STATUS_INDIRECT_BYTE; return strnlen(buf, count);}static DEVICE_ATTR(indirect_byte, S_IWUSR | S_IRUGO, show_indirect_byte, store_indirect_byte);static ssize_t show_direct_dword(struct device *d, struct device_attribute *attr, char *buf){ u32 reg = 0; struct ipw_priv *priv = d->driver_data; if (priv->status & STATUS_DIRECT_DWORD) reg = ipw_read32(priv, priv->direct_dword); else reg = 0; return sprintf(buf, "0x%08x\n", reg);}static ssize_t store_direct_dword(struct device *d, struct device_attribute *attr, const char *buf, size_t count){ struct ipw_priv *priv = d->driver_data; sscanf(buf, "%x", &priv->direct_dword); priv->status |= STATUS_DIRECT_DWORD; return strnlen(buf, count);}static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO, show_direct_dword, store_direct_dword);static inline int rf_kill_active(struct ipw_priv *priv){ if (0 == (ipw_read32(priv, 0x30) & 0x10000)) priv->status |= STATUS_RF_KILL_HW; else priv->status &= ~STATUS_RF_KILL_HW; return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0;}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 baed RF kill active */ struct ipw_priv *priv = d->driver_data; int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | (rf_kill_active(priv) ? 0x2 : 0x0); return sprintf(buf, "%i\n", val);}static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio){ if ((disable_radio ? 1 : 0) == ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0)) return 0; IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", disable_radio ? "OFF" : "ON"); if (disable_radio) { priv->status |= STATUS_RF_KILL_SW; if (priv->workqueue) cancel_delayed_work(&priv->request_scan); queue_work(priv->workqueue, &priv->down); } else { priv->status &= ~STATUS_RF_KILL_SW; if (rf_kill_active(priv)) { IPW_DEBUG_RF_KILL("Can not turn radio back on - " "disabled by HW switch\n"); /* Make sure the RF_KILL check timer is running */ cancel_delayed_work(&priv->rf_kill); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); } else queue_work(priv->workqueue, &priv->up); } return 1;}static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, const char *buf, size_t count){ struct ipw_priv *priv = d->driver_data; ipw_radio_kill_sw(priv, buf[0] == '1'); return count;}static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr, char *buf){ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; int pos = 0, len = 0; if (priv->config & CFG_SPEED_SCAN) { while (priv->speed_scan[pos] != 0) len += sprintf(&buf[len], "%d ", priv->speed_scan[pos++]); return len + sprintf(&buf[len], "\n"); } return sprintf(buf, "0\n");}static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, const char *buf, size_t count){ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; int channel, pos = 0; const char *p = buf; /* list of space separated channels to scan, optionally ending with 0 */ while ((channel = simple_strtol(p, NULL, 0))) { if (pos == MAX_SPEED_SCAN - 1) { priv->speed_scan[pos] = 0; break; } if (ipw_is_valid_channel(priv->ieee, channel)) priv->speed_scan[pos++] = channel; else IPW_WARNING("Skipping invalid channel request: %d\n", channel); p = strchr(p, ' '); if (!p) break; while (*p == ' ' || *p == '\t') p++; } if (pos == 0) priv->config &= ~CFG_SPEED_SCAN; else { priv->speed_scan_pos = 0; priv->config |= CFG_SPEED_SCAN; } return count;}static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan, store_speed_scan);static ssize_t show_net_stats(struct device *d, struct device_attribute *attr, char *buf){ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0');}static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, const char *buf, size_t count){ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; if (buf[0] == '1') priv->config |= CFG_NET_STATS; else priv->config &= ~CFG_NET_STATS; return count;}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->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; /* 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_ERROR("Firmware error detected. Restarting.\n"); if (priv->error) { IPW_ERROR("Sysfs 'error' log already exists.\n");#ifdef CONFIG_IPW_DEBUG if (ipw_debug_level & IPW_DL_FW_ERRORS) { struct ipw_fw_error *error = ipw_alloc_error_log(priv); ipw_dump_error_log(priv, error); if (error) ipw_free_error_log(error); }#endif } else { priv->error = ipw_alloc_error_log(priv); if (priv->error) IPW_ERROR("Sysfs 'error' log captured.\n"); else IPW_ERROR("Error allocating sysfs 'error' " "log.\n");#ifdef CONFIG_IPW_DEBUG if (ipw_debug_level & IPW_DL_FW_ERRORS) ipw_dump_error_log(priv, priv->error);#endif } /* 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); } /* enable all interrupts */ ipw_enable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags);}#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); 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_host_complete(struct ipw_priv *priv){ struct host_cmd cmd = { .cmd = IPW_CMD_HOST_COMPLETE, .len = 0 }; if (!priv) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -