📄 ipw2100.c
字号:
__LINE__); return; } len = sizeof(u32); ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len); if (ret) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", __LINE__); return; } len = sizeof(u32); ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len); if (ret) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", __LINE__); return; } len = ETH_ALEN; ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len); if (ret) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", __LINE__); return; } memcpy(priv->ieee->bssid, bssid, ETH_ALEN); switch (txrate) { case TX_RATE_1_MBIT: txratename = "1Mbps"; break; case TX_RATE_2_MBIT: txratename = "2Mbsp"; break; case TX_RATE_5_5_MBIT: txratename = "5.5Mbps"; break; case TX_RATE_11_MBIT: txratename = "11Mbps"; break; default: IPW_DEBUG_INFO("Unknown rate: %d\n", txrate); txratename = "unknown rate"; break; } IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=" MAC_FMT ")\n", priv->net_dev->name, escape_essid(essid, essid_len), txratename, chan, MAC_ARG(bssid)); /* now we copy read ssid into dev */ if (!(priv->config & CFG_STATIC_ESSID)) { priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE); memcpy(priv->essid, essid, priv->essid_len); } priv->channel = chan; memcpy(priv->bssid, bssid, ETH_ALEN); priv->status |= STATUS_ASSOCIATING; priv->connect_start = get_seconds(); queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10);}static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, int length, int batch_mode){ int ssid_len = min(length, IW_ESSID_MAX_SIZE); struct host_command cmd = { .host_command = SSID, .host_command_sequence = 0, .host_command_length = ssid_len }; int err; IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len)); if (ssid_len) memcpy(cmd.host_command_parameters, essid, ssid_len); if (!batch_mode) { err = ipw2100_disable_adapter(priv); if (err) return err; } /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to * disable auto association -- so we cheat by setting a bogus SSID */ if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) { int i; u8 *bogus = (u8 *) cmd.host_command_parameters; for (i = 0; i < IW_ESSID_MAX_SIZE; i++) bogus[i] = 0x18 + i; cmd.host_command_length = IW_ESSID_MAX_SIZE; } /* NOTE: We always send the SSID command even if the provided ESSID is * the same as what we currently think is set. */ err = ipw2100_hw_send_command(priv, &cmd); if (!err) { memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len); memcpy(priv->essid, essid, ssid_len); priv->essid_len = ssid_len; } if (!batch_mode) { if (ipw2100_enable_adapter(priv)) err = -EIO; } return err;}static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status){ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "disassociated: '%s' " MAC_FMT " \n", escape_essid(priv->essid, priv->essid_len), MAC_ARG(priv->bssid)); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); if (priv->status & STATUS_STOPPING) { IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n"); return; } memset(priv->bssid, 0, ETH_ALEN); memset(priv->ieee->bssid, 0, ETH_ALEN); netif_carrier_off(priv->net_dev); netif_stop_queue(priv->net_dev); if (!(priv->status & STATUS_RUNNING)) return; if (priv->status & STATUS_SECURITY_UPDATED) queue_work(priv->workqueue, &priv->security_work); queue_work(priv->workqueue, &priv->wx_event_work);}static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status){ IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n", priv->net_dev->name); /* RF_KILL is now enabled (else we wouldn't be here) */ priv->status |= STATUS_RF_KILL_HW;#ifdef ACPI_CSTATE_LIMIT_DEFINED if (priv->config & CFG_C3_DISABLED) { IPW_DEBUG_INFO(": Resetting C3 transitions.\n"); acpi_set_cstate_limit(priv->cstate_limit); priv->config &= ~CFG_C3_DISABLED; }#endif /* Make sure the RF Kill check timer is running */ priv->stop_rf_kill = 0; cancel_delayed_work(&priv->rf_kill); queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);}static void isr_scan_complete(struct ipw2100_priv *priv, u32 status){ IPW_DEBUG_SCAN("scan complete\n"); /* Age the scan results... */ priv->ieee->scans++; priv->status &= ~STATUS_SCANNING;}#ifdef CONFIG_IPW_DEBUG#define IPW2100_HANDLER(v, f) { v, f, # v }struct ipw2100_status_indicator { int status; void (*cb) (struct ipw2100_priv * priv, u32 status); char *name;};#else#define IPW2100_HANDLER(v, f) { v, f }struct ipw2100_status_indicator { int status; void (*cb) (struct ipw2100_priv * priv, u32 status);};#endif /* CONFIG_IPW_DEBUG */static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status){ IPW_DEBUG_SCAN("Scanning...\n"); priv->status |= STATUS_SCANNING;}static const struct ipw2100_status_indicator status_handlers[] = { IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL), IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL), IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated), IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost), IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL), IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete), IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL), IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL), IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill), IPW2100_HANDLER(IPW_STATE_DISABLED, NULL), IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL), IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning), IPW2100_HANDLER(-1, NULL)};static void isr_status_change(struct ipw2100_priv *priv, int status){ int i; if (status == IPW_STATE_SCANNING && priv->status & STATUS_ASSOCIATED && !(priv->status & STATUS_SCANNING)) { IPW_DEBUG_INFO("Scan detected while associated, with " "no scan request. Restarting firmware.\n"); /* Wake up any sleeping jobs */ schedule_reset(priv); } for (i = 0; status_handlers[i].status != -1; i++) { if (status == status_handlers[i].status) { IPW_DEBUG_NOTIF("Status change: %s\n", status_handlers[i].name); if (status_handlers[i].cb) status_handlers[i].cb(priv, status); priv->wstats.status = status; return; } } IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);}static void isr_rx_complete_command(struct ipw2100_priv *priv, struct ipw2100_cmd_header *cmd){#ifdef CONFIG_IPW_DEBUG if (cmd->host_command_reg < ARRAY_SIZE(command_types)) { IPW_DEBUG_HC("Command completed '%s (%d)'\n", command_types[cmd->host_command_reg], cmd->host_command_reg); }#endif if (cmd->host_command_reg == HOST_COMPLETE) priv->status |= STATUS_ENABLED; if (cmd->host_command_reg == CARD_DISABLE) priv->status &= ~STATUS_ENABLED; priv->status &= ~STATUS_CMD_ACTIVE; wake_up_interruptible(&priv->wait_command_queue);}#ifdef CONFIG_IPW_DEBUGstatic const char *frame_types[] = { "COMMAND_STATUS_VAL", "STATUS_CHANGE_VAL", "P80211_DATA_VAL", "P8023_DATA_VAL", "HOST_NOTIFICATION_VAL"};#endifstatic inline int ipw2100_alloc_skb(struct ipw2100_priv *priv, struct ipw2100_rx_packet *packet){ packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx)); if (!packet->skb) return -ENOMEM; packet->rxp = (struct ipw2100_rx *)packet->skb->data; packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data, sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); /* NOTE: pci_map_single does not return an error code, and 0 is a valid * dma_addr */ return 0;}#define SEARCH_ERROR 0xffffffff#define SEARCH_FAIL 0xfffffffe#define SEARCH_SUCCESS 0xfffffff0#define SEARCH_DISCARD 0#define SEARCH_SNAPSHOT 1#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))static inline int ipw2100_snapshot_alloc(struct ipw2100_priv *priv){ int i; if (priv->snapshot[0]) return 1; for (i = 0; i < 0x30; i++) { priv->snapshot[i] = (u8 *) kmalloc(0x1000, GFP_ATOMIC); if (!priv->snapshot[i]) { IPW_DEBUG_INFO("%s: Error allocating snapshot " "buffer %d\n", priv->net_dev->name, i); while (i > 0) kfree(priv->snapshot[--i]); priv->snapshot[0] = NULL; return 0; } } return 1;}static inline void ipw2100_snapshot_free(struct ipw2100_priv *priv){ int i; if (!priv->snapshot[0]) return; for (i = 0; i < 0x30; i++) kfree(priv->snapshot[i]); priv->snapshot[0] = NULL;}static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf, size_t len, int mode){ u32 i, j; u32 tmp; u8 *s, *d; u32 ret; s = in_buf; if (mode == SEARCH_SNAPSHOT) { if (!ipw2100_snapshot_alloc(priv)) mode = SEARCH_DISCARD; } for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) { read_nic_dword(priv->net_dev, i, &tmp); if (mode == SEARCH_SNAPSHOT) *(u32 *) SNAPSHOT_ADDR(i) = tmp; if (ret == SEARCH_FAIL) { d = (u8 *) & tmp; for (j = 0; j < 4; j++) { if (*s != *d) { s = in_buf; continue; } s++; d++; if ((s - in_buf) == len) ret = (i + j) - len + 1; } } else if (mode == SEARCH_DISCARD) return ret; } return ret;}/* * * 0) Disconnect the SKB from the firmware (just unmap) * 1) Pack the ETH header into the SKB * 2) Pass the SKB to the network stack * * When packet is provided by the firmware, it contains the following: * * . ieee80211_hdr * . ieee80211_snap_hdr * * The size of the constructed ethernet * */#ifdef CONFIG_IPW2100_RX_DEBUGstatic u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];#endifstatic inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i){#ifdef CONFIG_IPW_DEBUG_C3 struct ipw2100_status *status = &priv->status_queue.drv[i]; u32 match, reg; int j;#endif#ifdef ACPI_CSTATE_LIMIT_DEFINED int limit;#endif IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n", i * sizeof(struct ipw2100_status));#ifdef ACPI_CSTATE_LIMIT_DEFINED IPW_DEBUG_INFO(": Disabling C3 transitions.\n"); limit = acpi_get_cstate_limit(); if (limit > 2) { priv->cstate_limit = limit; acpi_set_cstate_limit(2); priv->config |= CFG_C3_DISABLED; }#endif#ifdef CONFIG_IPW_DEBUG_C3 /* Halt the fimrware so we can get a good image */ write_register(priv->net_dev, IPW_REG_RESET_REG, IPW_AUX_HOST_RESET_REG_STOP_MASTER); j = 5; do { udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY); read_register(priv->net_dev, IPW_REG_RESET_REG, ®); if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) break; } while (j--); match = ipw2100_match_buf(priv, (u8 *) status, sizeof(struct ipw2100_status), SEARCH_SNAPSHOT); if (match < SEARCH_SUCCESS) IPW_DEBUG_INFO("%s: DMA status match in Firmware at " "offset 0x%06X, length %d:\n", priv->net_dev->name, match, sizeof(struct ipw2100_status)); else IPW_DEBUG_INFO("%s: No DMA status match in " "Firmware.\n", priv->net_dev->name); printk_buf((u8 *) priv->status_queue.drv, sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);#endif priv->fatal_error = IPW2100_ERR_C3_CORRUPTION; priv->ieee->stats.rx_errors++; schedule_reset(priv);}static inline void isr_rx(struct ipw2100_priv *priv, int i, struct ieee80211_rx_stats *stats){ struct ipw2100_status *status = &priv->status_queue.drv[i]; struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; IPW_DEBUG_RX("Handler...\n"); if (unlikely(status->frame_size > skb_tailroom(packet->skb))) { IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" " Dropping.\n", priv->net_dev->name, status->frame_size, skb_tailroom(packet->skb)); priv->ieee->stats.rx_errors++; return; } if (unlikely(!netif_running(priv->net_dev))) { priv->ieee->stats.rx_errors++; priv->wstats.discard.misc++; IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); return; }#ifdef CONFIG_IPW2100_MONITOR if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR && priv->config & CFG_CRC_CHECK && status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); priv->ieee->stats.rx_errors++; return; }#endif if (unlikely(priv->ieee->iw_mode !
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -