📄 hostap_hw.c
字号:
prism2_check_sta_fw_version(local); if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, &dev->dev_addr, 6, 1) < 0) { printk("%s: could not get own MAC address\n", dev->name); } list_for_each(ptr, &local->hostap_interfaces) { iface = list_entry(ptr, struct hostap_interface, list); memcpy(iface->dev->dev_addr, dev->dev_addr, ETH_ALEN); } } else if (local->fw_ap) prism2_check_sta_fw_version(local); prism2_setup_rids(dev); /* MAC is now configured, but port 0 is not yet enabled */ return 0; failed: if (!local->no_pri) printk(KERN_WARNING "%s: Initialization failed\n", dev_info); return 1;}static int prism2_hw_enable(struct net_device *dev, int initial){ struct hostap_interface *iface; local_info_t *local; int was_resetting; iface = netdev_priv(dev); local = iface->local; was_resetting = local->hw_resetting; if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { printk("%s: MAC port 0 enabling failed\n", dev->name); return 1; } local->hw_ready = 1; local->hw_reset_tries = 0; local->hw_resetting = 0; hfa384x_enable_interrupts(dev); /* at least D-Link DWL-650 seems to require additional port reset * before it starts acting as an AP, so reset port automatically * here just in case */ if (initial && prism2_reset_port(dev)) { printk("%s: MAC port 0 reseting failed\n", dev->name); return 1; } if (was_resetting && netif_queue_stopped(dev)) { /* If hw_reset() was called during pending transmit, netif * queue was stopped. Wake it up now since the wlan card has * been resetted. */ netif_wake_queue(dev); } return 0;}static int prism2_hw_config(struct net_device *dev, int initial){ struct hostap_interface *iface; local_info_t *local; iface = netdev_priv(dev); local = iface->local; if (local->hw_downloading) return 1; if (prism2_hw_init(dev, initial)) { return local->no_pri ? 0 : 1; } if (prism2_hw_init2(dev, initial)) return 1; /* Enable firmware if secondary image is loaded and at least one of the * netdevices is up. */ if (!local->pri_only && (initial == 0 || (initial == 2 && local->num_dev_open > 0))) { if (!local->dev_enabled) prism2_callback(local, PRISM2_CALLBACK_ENABLE); local->dev_enabled = 1; return prism2_hw_enable(dev, initial); } return 0;}static void prism2_hw_shutdown(struct net_device *dev, int no_disable){ struct hostap_interface *iface; local_info_t *local; iface = netdev_priv(dev); local = iface->local; /* Allow only command completion events during disable */ hfa384x_events_only_cmd(dev); local->hw_ready = 0; if (local->dev_enabled) prism2_callback(local, PRISM2_CALLBACK_DISABLE); local->dev_enabled = 0; if (local->func->card_present && !local->func->card_present(local)) { printk(KERN_DEBUG "%s: card already removed or not configured " "during shutdown\n", dev->name); return; } if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); hfa384x_disable_interrupts(dev); if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL) hfa384x_events_only_cmd(dev); else prism2_clear_cmd_queue(local);}static void prism2_hw_reset(struct net_device *dev){ struct hostap_interface *iface; local_info_t *local;#if 0 static long last_reset = 0; /* do not reset card more than once per second to avoid ending up in a * busy loop reseting the card */ if (time_before_eq(jiffies, last_reset + HZ)) return; last_reset = jiffies;#endif iface = netdev_priv(dev); local = iface->local; if (in_interrupt()) { printk(KERN_DEBUG "%s: driver bug - prism2_hw_reset() called " "in interrupt context\n", dev->name); return; } if (local->hw_downloading) return; if (local->hw_resetting) { printk(KERN_WARNING "%s: %s: already resetting card - " "ignoring reset request\n", dev_info, dev->name); return; } local->hw_reset_tries++; if (local->hw_reset_tries > 10) { printk(KERN_WARNING "%s: too many reset tries, skipping\n", dev->name); return; } printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); hfa384x_disable_interrupts(dev); local->hw_resetting = 1; if (local->func->cor_sreset) { /* Host system seems to hang in some cases with high traffic * load or shared interrupts during COR sreset. Disable shared * interrupts during reset to avoid these crashes. COS sreset * takes quite a long time, so it is unfortunate that this * seems to be needed. Anyway, I do not know of any better way * of avoiding the crash. */ disable_irq(dev->irq); local->func->cor_sreset(local); enable_irq(dev->irq); } prism2_hw_shutdown(dev, 1); prism2_hw_config(dev, 0); local->hw_resetting = 0;#ifdef PRISM2_DOWNLOAD_SUPPORT if (local->dl_pri) { printk(KERN_DEBUG "%s: persistent download of primary " "firmware\n", dev->name); if (prism2_download_genesis(local, local->dl_pri) < 0) printk(KERN_WARNING "%s: download (PRI) failed\n", dev->name); } if (local->dl_sec) { printk(KERN_DEBUG "%s: persistent download of secondary " "firmware\n", dev->name); if (prism2_download_volatile(local, local->dl_sec) < 0) printk(KERN_WARNING "%s: download (SEC) failed\n", dev->name); }#endif /* PRISM2_DOWNLOAD_SUPPORT */ /* TODO: restore beacon TIM bits for STAs that have buffered frames */}static void prism2_schedule_reset(local_info_t *local){ schedule_work(&local->reset_queue);}/* Called only as scheduled task after noticing card timeout in interrupt * context */static void handle_reset_queue(void *data){ local_info_t *local = (local_info_t *) data; printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); prism2_hw_reset(local->dev); if (netif_queue_stopped(local->dev)) { int i; for (i = 0; i < PRISM2_TXFID_COUNT; i++) if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) { PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: " "wake up queue\n"); netif_wake_queue(local->dev); break; } }}static int prism2_get_txfid_idx(local_info_t *local){ int idx, end; unsigned long flags; spin_lock_irqsave(&local->txfidlock, flags); end = idx = local->next_txfid; do { if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { local->intransmitfid[idx] = PRISM2_TXFID_RESERVED; spin_unlock_irqrestore(&local->txfidlock, flags); return idx; } idx++; if (idx >= PRISM2_TXFID_COUNT) idx = 0; } while (idx != end); spin_unlock_irqrestore(&local->txfidlock, flags); PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: " "packet dropped\n"); local->stats.tx_dropped++; return -1;}/* Called only from hardware IRQ */static void prism2_transmit_cb(struct net_device *dev, long context, u16 resp0, u16 res){ struct hostap_interface *iface; local_info_t *local; int idx = (int) context; iface = netdev_priv(dev); local = iface->local; if (res) { printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n", dev->name, res); return; } if (idx < 0 || idx >= PRISM2_TXFID_COUNT) { printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid " "idx=%d\n", dev->name, idx); return; } if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called " "with no pending transmit\n", dev->name); } if (netif_queue_stopped(dev)) { /* ready for next TX, so wake up queue that was stopped in * prism2_transmit() */ netif_wake_queue(dev); } spin_lock(&local->txfidlock); /* With reclaim, Resp0 contains new txfid for transmit; the old txfid * will be automatically allocated for the next TX frame */ local->intransmitfid[idx] = resp0; PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, " "resp0=0x%04x, transmit_txfid=0x%04x\n", dev->name, idx, local->txfid[idx], resp0, local->intransmitfid[local->next_txfid]); idx++; if (idx >= PRISM2_TXFID_COUNT) idx = 0; local->next_txfid = idx; /* check if all TX buffers are occupied */ do { if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { spin_unlock(&local->txfidlock); return; } idx++; if (idx >= PRISM2_TXFID_COUNT) idx = 0; } while (idx != local->next_txfid); spin_unlock(&local->txfidlock); /* no empty TX buffers, stop queue */ netif_stop_queue(dev);}/* Called only from software IRQ if PCI bus master is not used (with bus master * this can be called both from software and hardware IRQ) */static int prism2_transmit(struct net_device *dev, int idx){ struct hostap_interface *iface; local_info_t *local; int res; iface = netdev_priv(dev); local = iface->local; /* The driver tries to stop netif queue so that there would not be * more than one attempt to transmit frames going on; check that this * is really the case */ if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called " "when previous TX was pending\n", dev->name); return -1; } /* stop the queue for the time that transmit is pending */ netif_stop_queue(dev); /* transmit packet */ res = hfa384x_cmd_callback( dev, HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM, local->txfid[idx], prism2_transmit_cb, (long) idx); if (res) { struct net_device_stats *stats; printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT " "failed (res=%d)\n", dev->name, res); stats = hostap_get_stats(dev); stats->tx_dropped++; netif_wake_queue(dev); return -1; } dev->trans_start = jiffies; /* Since we did not wait for command completion, the card continues * to process on the background and we will finish handling when * command completion event is handled (prism2_cmd_ev() function) */ return 0;}/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and * send the payload with this descriptor) *//* Called only from software IRQ */static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev){ struct hostap_interface *iface; local_info_t *local; struct hfa384x_tx_frame txdesc; struct hostap_skb_tx_data *meta; int hdr_len, data_len, idx, res, ret = -1; u16 tx_control, fc; iface = netdev_priv(dev); local = iface->local; meta = (struct hostap_skb_tx_data *) skb->cb; prism2_callback(local, PRISM2_CALLBACK_TX_START); if ((local->func->card_present && !local->func->card_present(local)) || !local->hw_ready || local->hw_downloading || local->pri_only) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -" " skipping\n", dev->name); } goto fail; } memset(&txdesc, 0, sizeof(txdesc)); /* skb->data starts with txdesc->frame_control */ hdr_len = 24; memcpy(&txdesc.frame_control, skb->data, hdr_len); fc = le16_to_cpu(txdesc.frame_control); if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) && skb->len >= 30) { /* Addr4 */ memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN); hdr_len += ETH_ALEN; } tx_control = local->tx_control; if (meta->tx_cb_idx) { tx_control |= HFA384X_TX_CTRL_TX_OK; txdesc.sw_support = cpu_to_le16(meta->tx_cb_idx); } txdesc.tx_control = cpu_to_le16(tx_control); txdesc.tx_rate = meta->rate; data_len = skb->len - hdr_len; txdesc.data_len = cpu_to_le16(data_len); txdesc.len = cpu_to_be16(data_len); idx = prism2_get_txfid_idx(local); if (idx < 0) goto fail; if (local->frame_dump & PRISM2_DUMP_TX_HDR) hostap_dump_tx_header(dev->name, &txdesc); spin_lock(&local->baplock); res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); if (!res) res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); if (!res) res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len, skb->len - hdr_len); spin_unlock(&local->baplock); if (!res) res = prism2_transmit(dev, idx); if (res) { printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n", dev->name); local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; schedule_work(&local->reset_queue); goto fail; } ret = 0;fail: prism2_callback(local, PRISM2_CALLBACK_TX_END); return ret;}/* Some SMP systems have reported number of odd errors with hostap_pci. fid
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -