📄 adm8211.c
字号:
break; } } else printk(KERN_DEBUG "%s: unsupported BBP %d\n", wiphy_name(dev->wiphy), priv->bbp_type); ADM8211_CSR_WRITE(SYNRF, 0); /* Set RF CAL control source to MAC control */ reg = ADM8211_CSR_READ(SYNCTL); reg |= ADM8211_SYNCTL_SELCAL; ADM8211_CSR_WRITE(SYNCTL, reg); return 0;}/* configures hw beacons/probe responses */static int adm8211_set_rate(struct ieee80211_hw *dev){ struct adm8211_priv *priv = dev->priv; u32 reg; int i = 0; u8 rate_buf[12] = {0}; /* write supported rates */ if (priv->pdev->revision != ADM8211_REV_BA) { rate_buf[0] = ARRAY_SIZE(adm8211_rates); for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++) rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80; } else { /* workaround for rev BA specific bug */ rate_buf[0] = 0x04; rate_buf[1] = 0x82; rate_buf[2] = 0x04; rate_buf[3] = 0x0b; rate_buf[4] = 0x16; } adm8211_write_sram_bytes(dev, ADM8211_SRAM_SUPP_RATE, rate_buf, ARRAY_SIZE(adm8211_rates) + 1); reg = ADM8211_CSR_READ(PLCPHD) & 0x00FFFFFF; /* keep bits 0-23 */ reg |= 1 << 15; /* short preamble */ reg |= 110 << 24; ADM8211_CSR_WRITE(PLCPHD, reg); /* MTMLT = 512 TU (max TX MSDU lifetime) * BCNTSIG = plcp_signal (beacon, probe resp, and atim TX rate) * SRTYLIM = 224 (short retry limit, TX header value is default) */ ADM8211_CSR_WRITE(TXLMT, (512 << 16) | (110 << 8) | (224 << 0)); return 0;}static void adm8211_hw_init(struct ieee80211_hw *dev){ struct adm8211_priv *priv = dev->priv; u32 reg; u8 cline; reg = le32_to_cpu(ADM8211_CSR_READ(PAR)); reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME; reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL); if (!pci_set_mwi(priv->pdev)) { reg |= 0x1 << 24; pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cline); switch (cline) { case 0x8: reg |= (0x1 << 14); break; case 0x16: reg |= (0x2 << 14); break; case 0x32: reg |= (0x3 << 14); break; default: reg |= (0x0 << 14); break; } } ADM8211_CSR_WRITE(PAR, reg); reg = ADM8211_CSR_READ(CSR_TEST1); reg &= ~(0xF << 28); reg |= (1 << 28) | (1 << 31); ADM8211_CSR_WRITE(CSR_TEST1, reg); /* lose link after 4 lost beacons */ reg = (0x04 << 21) | ADM8211_WCSR_TSFTWE | ADM8211_WCSR_LSOE; ADM8211_CSR_WRITE(WCSR, reg); /* Disable APM, enable receive FIFO threshold, and set drain receive * threshold to store-and-forward */ reg = ADM8211_CSR_READ(CMDR); reg &= ~(ADM8211_CMDR_APM | ADM8211_CMDR_DRT); reg |= ADM8211_CMDR_RTE | ADM8211_CMDR_DRT_SF; ADM8211_CSR_WRITE(CMDR, reg); adm8211_set_rate(dev); /* 4-bit values: * PWR1UP = 8 * 2 ms * PWR0PAPE = 8 us or 5 us * PWR1PAPE = 1 us or 3 us * PWR0TRSW = 5 us * PWR1TRSW = 12 us * PWR0PE2 = 13 us * PWR1PE2 = 1 us * PWR0TXPE = 8 or 6 */ if (priv->pdev->revision < ADM8211_REV_CA) ADM8211_CSR_WRITE(TOFS2, 0x8815cd18); else ADM8211_CSR_WRITE(TOFS2, 0x8535cd16); /* Enable store and forward for transmit */ priv->nar = ADM8211_NAR_SF | ADM8211_NAR_PB; ADM8211_CSR_WRITE(NAR, priv->nar); /* Reset RF */ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_RADIO); ADM8211_CSR_READ(SYNRF); msleep(10); ADM8211_CSR_WRITE(SYNRF, 0); ADM8211_CSR_READ(SYNRF); msleep(5); /* Set CFP Max Duration to 0x10 TU */ reg = ADM8211_CSR_READ(CFPP); reg &= ~(0xffff << 8); reg |= 0x0010 << 8; ADM8211_CSR_WRITE(CFPP, reg); /* USCNT = 0x16 (number of system clocks, 22 MHz, in 1us * TUCNT = 0x3ff - Tu counter 1024 us */ ADM8211_CSR_WRITE(TOFS0, (0x16 << 24) | 0x3ff); /* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us), * DIFS=50 us, EIFS=100 us */ if (priv->pdev->revision < ADM8211_REV_CA) ADM8211_CSR_WRITE(IFST, (20 << 23) | (110 << 15) | (50 << 9) | 100); else ADM8211_CSR_WRITE(IFST, (20 << 23) | (24 << 15) | (50 << 9) | 100); /* PCNT = 1 (MAC idle time awake/sleep, unit S) * RMRD = 2346 * 8 + 1 us (max RX duration) */ ADM8211_CSR_WRITE(RMD, (1 << 16) | 18769); /* MART=65535 us, MIRT=256 us, TSFTOFST=0 us */ ADM8211_CSR_WRITE(RSPT, 0xffffff00); /* Initialize BBP (and SYN) */ adm8211_hw_init_bbp(dev); /* make sure interrupts are off */ ADM8211_CSR_WRITE(IER, 0); /* ACK interrupts */ ADM8211_CSR_WRITE(STSR, ADM8211_CSR_READ(STSR)); /* Setup WEP (turns it off for now) */ reg = ADM8211_CSR_READ(MACTEST); reg &= ~(7 << 20); ADM8211_CSR_WRITE(MACTEST, reg); reg = ADM8211_CSR_READ(WEPCTL); reg &= ~ADM8211_WEPCTL_WEPENABLE; reg |= ADM8211_WEPCTL_WEPRXBYP; ADM8211_CSR_WRITE(WEPCTL, reg); /* Clear the missed-packet counter. */ ADM8211_CSR_READ(LPC);}static int adm8211_hw_reset(struct ieee80211_hw *dev){ struct adm8211_priv *priv = dev->priv; u32 reg, tmp; int timeout = 100; /* Power-on issue */ /* TODO: check if this is necessary */ ADM8211_CSR_WRITE(FRCTL, 0); /* Reset the chip */ tmp = ADM8211_CSR_READ(PAR); ADM8211_CSR_WRITE(PAR, ADM8211_PAR_SWR); while ((ADM8211_CSR_READ(PAR) & ADM8211_PAR_SWR) && timeout--) msleep(50); if (timeout <= 0) return -ETIMEDOUT; ADM8211_CSR_WRITE(PAR, tmp); if (priv->pdev->revision == ADM8211_REV_BA && (priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER || priv->transceiver_type == ADM8211_RFMD2958)) { reg = ADM8211_CSR_READ(CSR_TEST1); reg |= (1 << 4) | (1 << 5); ADM8211_CSR_WRITE(CSR_TEST1, reg); } else if (priv->pdev->revision == ADM8211_REV_CA) { reg = ADM8211_CSR_READ(CSR_TEST1); reg &= ~((1 << 4) | (1 << 5)); ADM8211_CSR_WRITE(CSR_TEST1, reg); } ADM8211_CSR_WRITE(FRCTL, 0); reg = ADM8211_CSR_READ(CSR_TEST0); reg |= ADM8211_CSR_TEST0_EPRLD; /* EEPROM Recall */ ADM8211_CSR_WRITE(CSR_TEST0, reg); adm8211_clear_sram(dev); return 0;}static u64 adm8211_get_tsft(struct ieee80211_hw *dev){ struct adm8211_priv *priv = dev->priv; u32 tsftl; u64 tsft; tsftl = ADM8211_CSR_READ(TSFTL); tsft = ADM8211_CSR_READ(TSFTH); tsft <<= 32; tsft |= tsftl; return tsft;}static void adm8211_set_interval(struct ieee80211_hw *dev, unsigned short bi, unsigned short li){ struct adm8211_priv *priv = dev->priv; u32 reg; /* BP (beacon interval) = data->beacon_interval * LI (listen interval) = data->listen_interval (in beacon intervals) */ reg = (bi << 16) | li; ADM8211_CSR_WRITE(BPLI, reg);}static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid){ struct adm8211_priv *priv = dev->priv; u32 reg; ADM8211_CSR_WRITE(BSSID0, le32_to_cpu(*(__le32 *)bssid)); reg = ADM8211_CSR_READ(ABDA1); reg &= 0x0000ffff; reg |= (bssid[4] << 16) | (bssid[5] << 24); ADM8211_CSR_WRITE(ABDA1, reg);}static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len){ struct adm8211_priv *priv = dev->priv; u8 buf[36]; if (ssid_len > 32) return -EINVAL; memset(buf, 0, sizeof(buf)); buf[0] = ssid_len; memcpy(buf + 1, ssid, ssid_len); adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33); /* TODO: configure beacon for adhoc? */ return 0;}static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf){ struct adm8211_priv *priv = dev->priv; if (conf->channel != priv->channel) { priv->channel = conf->channel; adm8211_rf_set_channel(dev, priv->channel); } return 0;}static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id, struct ieee80211_if_conf *conf){ struct adm8211_priv *priv = dev->priv; if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { adm8211_set_bssid(dev, conf->bssid); memcpy(priv->bssid, conf->bssid, ETH_ALEN); } if (conf->ssid_len != priv->ssid_len || memcmp(conf->ssid, priv->ssid, conf->ssid_len)) { adm8211_set_ssid(dev, conf->ssid, conf->ssid_len); priv->ssid_len = conf->ssid_len; memcpy(priv->ssid, conf->ssid, conf->ssid_len); } return 0;}static void adm8211_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_mc_list *mclist){ static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; struct adm8211_priv *priv = dev->priv; unsigned int bit_nr, new_flags; u32 mc_filter[2]; int i; new_flags = 0; if (*total_flags & FIF_PROMISC_IN_BSS) { new_flags |= FIF_PROMISC_IN_BSS; priv->nar |= ADM8211_NAR_PR; priv->nar &= ~ADM8211_NAR_MM; mc_filter[1] = mc_filter[0] = ~0; } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { new_flags |= FIF_ALLMULTI; priv->nar &= ~ADM8211_NAR_PR; priv->nar |= ADM8211_NAR_MM; mc_filter[1] = mc_filter[0] = ~0; } else { priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); mc_filter[1] = mc_filter[0] = 0; for (i = 0; i < mc_count; i++) { if (!mclist) break; bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; bit_nr &= 0x3F; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); mclist = mclist->next; } } ADM8211_IDLE_RX(); ADM8211_CSR_WRITE(MAR0, mc_filter[0]); ADM8211_CSR_WRITE(MAR1, mc_filter[1]); ADM8211_CSR_READ(NAR); if (priv->nar & ADM8211_NAR_PR) dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS; else dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; if (*total_flags & FIF_BCN_PRBRESP_PROMISC) adm8211_set_bssid(dev, bcast); else adm8211_set_bssid(dev, priv->bssid); ADM8211_RESTORE(); *total_flags = new_flags;}static int adm8211_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf){ struct adm8211_priv *priv = dev->priv; if (priv->mode != IEEE80211_IF_TYPE_MNTR) return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: priv->mode = conf->type; break; default: return -EOPNOTSUPP; } ADM8211_IDLE(); ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr)); ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); adm8211_update_mode(dev); ADM8211_RESTORE(); return 0;}static void adm8211_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf){ struct adm8211_priv *priv = dev->priv; priv->mode = IEEE80211_IF_TYPE_MNTR;}static int adm8211_init_rings(struct ieee80211_hw *dev){ struct adm8211_priv *priv = dev->priv; struct adm8211_desc *desc = NULL; struct adm8211_rx_ring_info *rx_info; struct adm8211_tx_ring_info *tx_info; unsigned int i; for (i = 0; i < priv->rx_ring_size; i++) { desc = &priv->rx_ring[i]; desc->status = 0; desc->length = cpu_to_le32(RX_PKT_SIZE); priv->rx_buffers[i].skb = NULL; } /* Mark the end of RX ring; hw returns to base address after this * descriptor */ desc->length |= cpu_to_le32(RDES1_CONTROL_RER); for (i = 0; i < priv->rx_ring_size; i++) { desc = &priv->rx_ring[i]; rx_info = &priv->rx_buffers[i]; rx_info->skb = dev_alloc_skb(RX_PKT_SIZE); if (rx_info->skb == NULL) break; rx_info->mapping = pci_map_single(priv->pdev, skb_tail_pointer(rx_info->skb), RX_PKT_SIZE, PCI_DMA_FROMDEVICE); desc->buffer1 = cpu_to_le32(rx_info->mapping); desc->status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL); } /* Setup TX ring. TX buffers descriptors will be filled in as needed */ for (i = 0; i < priv->tx_ring_size; i++) { desc = &priv->tx_ring[i]; tx_info = &priv->tx_buffers[i]; tx_info->skb = NULL; tx_info->mapping = 0; desc->status = 0; } desc->length = cpu_to_le32(TDES1_CONTROL_TER); priv->cur_rx = priv->cur_tx = priv->dirty_tx = 0; ADM8211_CSR_WRITE(RDB, priv->rx_ring_dma); ADM8211_CSR_WRITE(TDBD, priv->tx_ring_dma); return 0;}static void adm8211_free_rings(struct ieee80211_hw *dev){ struct adm8211_priv *priv = dev->priv; unsigned int i; for (i = 0; i < priv->rx_ring_size; i++) { if (!priv->rx_buffers[i].skb) continue; pci_unmap_single( priv->pdev, priv->rx_buffers[i].mapping, RX_PKT_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(priv->rx_buffers[i].skb); } for (i = 0; i < priv->tx_ring_size; i++) { if (!priv->tx_buffers[i].skb) continue; pci_unmap_single(priv->pdev, priv->tx_buffers[i].mapping, priv->tx_buffers[i].skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(priv->tx_buffers[i].skb); }}static int adm8211_start(struct ieee80211_hw *dev){ struct adm8211_priv *priv = dev->priv; int retval; /* Power up MAC and RF chips */ retval = adm8211_hw_reset(dev); if (retval) { printk(KERN_ERR "%s: hardware reset failed\n", wiphy_name(dev->wiphy)); goto fail; } retval = adm8211_init_rings(dev); if (retval) { printk(KERN_ERR "%s: failed to initialize rings\n", wiphy_name(dev->wiphy)); goto fail; } /* Init hardware */ adm8211_hw_init(dev); adm8211_rf_set_channel(dev, priv->channel); retval = request_irq(priv->pdev->irq, &adm8211_interrupt, IRQF_SHARED, "adm8211", dev); if (retval) { printk(KERN_ERR "%s: failed to register IRQ handler\n", wiphy_name(dev->wiphy)); goto fail; } ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE | ADM8211_IER_RCIE | ADM8211_IER_TCIE | ADM8211_IER_TDUIE | ADM8211_IER_GPTIE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -