static int adm8211_write_bbp(struct ieee80211_hw *dev, u8 addr, u8 data) { struct adm8211_priv *priv = dev->priv; unsigned int timeout; u32 reg; timeout = 10; while (timeout > 0) { reg = ADM8211_CSR_READ(BBPCTL); if (!(reg & (ADM8211_BBPCTL_WR | ADM8211_BBPCTL_RD))) break; timeout--; msleep(2); } if (timeout == 0) { wiphy_debug(dev->wiphy, "adm8211_write_bbp(%d,%d) failed prewrite (reg=0x%08x)\n", addr, data, reg); return -ETIMEDOUT; } switch (priv->bbp_type) { case ADM8211_TYPE_INTERSIL: reg = ADM8211_BBPCTL_MMISEL; /* three wire interface */ break; case ADM8211_TYPE_RFMD: reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP | (0x01 << 18); break; case ADM8211_TYPE_ADMTEK: reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP | (0x05 << 18); break; } reg |= ADM8211_BBPCTL_WR | (addr << 8) | data; ADM8211_CSR_WRITE(BBPCTL, reg); timeout = 10; while (timeout > 0) { reg = ADM8211_CSR_READ(BBPCTL); if (!(reg & ADM8211_BBPCTL_WR)) break; timeout--; msleep(2); } if (timeout == 0) { ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) & ~ADM8211_BBPCTL_WR); wiphy_debug(dev->wiphy, "adm8211_write_bbp(%d,%d) failed postwrite (reg=0x%08x)\n", addr, data, reg); return -ETIMEDOUT; } return 0; }
static int mwl_mac80211_config(struct ieee80211_hw *hw, u32 changed) { struct ieee80211_conf *conf = &hw->conf; int rc; wiphy_debug(hw->wiphy, "change: 0x%x\n", changed); if (conf->flags & IEEE80211_CONF_IDLE) rc = mwl_fwcmd_radio_disable(hw); else rc = mwl_fwcmd_radio_enable(hw); if (rc) goto out; if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { int rate = 0; if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ) { mwl_fwcmd_set_apmode(hw, AP_MODE_2_4GHZ_11AC_MIXED); mwl_fwcmd_set_linkadapt_cs_mode(hw, LINK_CS_STATE_CONSERV); rate = mwl_rates_24[0].hw_value; } else if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ) { mwl_fwcmd_set_apmode(hw, AP_MODE_11AC); mwl_fwcmd_set_linkadapt_cs_mode(hw, LINK_CS_STATE_AUTO); rate = mwl_rates_50[0].hw_value; if (conf->radar_enabled) mwl_fwcmd_set_radar_detect(hw, MONITOR_START); else mwl_fwcmd_set_radar_detect(hw, STOP_DETECT_RADAR); } rc = mwl_fwcmd_set_rf_channel(hw, conf); if (rc) goto out; rc = mwl_fwcmd_use_fixed_rate(hw, rate, rate); if (rc) goto out; rc = mwl_fwcmd_max_tx_power(hw, conf, 0); if (rc) goto out; rc = mwl_fwcmd_tx_power(hw, conf, 0); if (rc) goto out; rc = mwl_fwcmd_set_cdd(hw); } out: return rc; }
/* * CFG802.11 operation handler for setting bit rates. * * Function selects legacy bang B/G/BG from corresponding bitrates selection. * Currently only 2.4GHz band is supported. */ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, const struct cfg80211_bitrate_mask *mask) { struct mwifiex_ds_band_cfg band_cfg; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int index = 0, mode = 0, i; /* Currently only 2.4GHz is supported */ for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) { /* * Rates below 6 Mbps in the table are CCK rates; 802.11b * and from 6 they are OFDM; 802.11G */ if (mwifiex_rates[i].bitrate == 60) { index = 1 << i; break; } } if (mask->control[IEEE80211_BAND_2GHZ].legacy < index) { mode = BAND_B; } else { mode = BAND_G; if (mask->control[IEEE80211_BAND_2GHZ].legacy % index) mode |= BAND_B; } memset(&band_cfg, 0, sizeof(band_cfg)); band_cfg.config_bands = mode; if (priv->bss_mode == NL80211_IFTYPE_ADHOC) band_cfg.adhoc_start_band = mode; band_cfg.sec_chan_offset = NO_SEC_CHANNEL; if (mwifiex_set_radio_band_cfg(priv, &band_cfg)) return -EFAULT; wiphy_debug(wiphy, "info: device configured in 802.11%s%s mode\n", (mode & BAND_B) ? "b" : "", (mode & BAND_G) ? "g" : ""); return 0; }
/* * CFG802.11 operation handler for setting bit rates. * * Function selects legacy bang B/G/BG from corresponding bitrates selection. * Currently only 2.4GHz band is supported. */ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, const struct cfg80211_bitrate_mask *mask) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int index = 0, mode = 0, i; struct mwifiex_adapter *adapter = priv->adapter; /* Currently only 2.4GHz is supported */ for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) { /* * Rates below 6 Mbps in the table are CCK rates; 802.11b * and from 6 they are OFDM; 802.11G */ if (mwifiex_rates[i].bitrate == 60) { index = 1 << i; break; } } if (mask->control[IEEE80211_BAND_2GHZ].legacy < index) { mode = BAND_B; } else { mode = BAND_G; if (mask->control[IEEE80211_BAND_2GHZ].legacy % index) mode |= BAND_B; } if (!((mode | adapter->fw_bands) & ~adapter->fw_bands)) { adapter->config_bands = mode; if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { adapter->adhoc_start_band = mode; adapter->adhoc_11n_enabled = false; } } adapter->sec_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; adapter->channel_type = NL80211_CHAN_NO_HT; wiphy_debug(wiphy, "info: device configured in 802.11%s%s mode\n", (mode & BAND_B) ? "b" : "", (mode & BAND_G) ? "g" : ""); return 0; }
int mwl_fwdl_download_firmware(struct ieee80211_hw *hw) { struct mwl_priv *priv = hw->priv; const struct firmware *fw; u32 curr_iteration = 0; u32 size_fw_downloaded = 0; u32 int_code = 0; u32 len = 0; u32 fwreadysignature = HOSTCMD_SOFTAP_FWRDY_SIGNATURE; fw = priv->fw_ucode; mwl_fwcmd_reset(hw); /* FW before jumping to boot rom, it will enable PCIe transaction retry, * wait for boot code to stop it. */ usleep_range(FW_CHECK_MSECS * 1000, FW_CHECK_MSECS * 2000); writel(MACREG_A2HRIC_BIT_MASK, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CLEAR_SEL); writel(0x00, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CAUSE); writel(0x00, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_MASK); writel(MACREG_A2HRIC_BIT_MASK, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); /* this routine interacts with SC2 bootrom to download firmware binary * to the device. After DMA'd to SC2, the firmware could be deflated to * reside on its respective blocks such as ITCM, DTCM, SQRAM, * (or even DDR, AFTER DDR is init'd before fw download */ wiphy_debug(hw->wiphy, "fw download start\n"); /* Disable PFU before FWDL */ writel(0x100, priv->iobase1 + 0xE0E4); /* make sure SCRATCH2 C40 is clear, in case we are too quick */ while (readl(priv->iobase1 + 0xc40) == 0) cond_resched(); while (size_fw_downloaded < fw->size) { len = readl(priv->iobase1 + 0xc40); if (!len) break; /* this copies the next chunk of fw binary to be delivered */ memcpy((char *)&priv->pcmd_buf[0], (fw->data + size_fw_downloaded), len); /* this function writes pdata to c10, then write 2 to c18 */ mwl_fwdl_trig_pcicmd_bootcode(priv); /* this is arbitrary per your platform; we use 0xffff */ curr_iteration = FW_MAX_NUM_CHECKS; /* NOTE: the following back to back checks on C1C is time * sensitive, hence may need to be tweaked dependent on host * processor. Time for SC2 to go from the write of event 2 to * C1C == 2 is ~1300 nSec. Hence the checkings on host has to * consider how efficient your code can be to meet this timing, * or you can alternatively tweak this routines to fit your * platform */ do { int_code = readl(priv->iobase1 + 0xc1c); if (int_code != 0) break; cond_resched(); curr_iteration--; } while (curr_iteration); do { int_code = readl(priv->iobase1 + 0xc1c); if ((int_code & MACREG_H2ARIC_BIT_DOOR_BELL) != MACREG_H2ARIC_BIT_DOOR_BELL) break; cond_resched(); curr_iteration--; } while (curr_iteration); if (curr_iteration == 0) { /* This limited loop check allows you to exit gracefully * without locking up your entire system just because fw * download failed */ wiphy_err(hw->wiphy, "Exhausted curr_iteration for fw download\n"); goto err_download; } size_fw_downloaded += len; } wiphy_debug(hw->wiphy, "FwSize = %d downloaded Size = %d curr_iteration %d\n", (int)fw->size, size_fw_downloaded, curr_iteration); /* Now firware is downloaded successfully, so this part is to check * whether fw can properly execute to an extent that write back * signature to indicate its readiness to the host. NOTE: if your * downloaded fw crashes, this signature checking will fail. This * part is similar as SC1 */ *((u32 *)&priv->pcmd_buf[1]) = 0; mwl_fwdl_trig_pcicmd(priv); curr_iteration = FW_MAX_NUM_CHECKS; do { curr_iteration--; writel(HOSTCMD_SOFTAP_MODE, priv->iobase1 + MACREG_REG_GEN_PTR); usleep_range(FW_CHECK_MSECS * 1000, FW_CHECK_MSECS * 2000); int_code = readl(priv->iobase1 + MACREG_REG_INT_CODE); if (!(curr_iteration % 0xff) && (int_code != 0)) wiphy_err(hw->wiphy, "%x;", int_code); } while ((curr_iteration) && (int_code != fwreadysignature)); if (curr_iteration == 0) { wiphy_err(hw->wiphy, "Exhausted curr_iteration for fw signature\n"); goto err_download; } wiphy_debug(hw->wiphy, "fw download complete\n"); writel(0x00, priv->iobase1 + MACREG_REG_INT_CODE); return 0; err_download: mwl_fwcmd_reset(hw); return -EIO; }
int ieee80211_register_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); int result, i; enum ieee80211_band band; int channels, max_bitrates; bool supp_ht; static const u32 cipher_suites[] = { /* keep WEP first, it may be removed below */ WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, /* keep last -- depends on hw flags! */ WLAN_CIPHER_SUITE_AES_CMAC }; if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) #ifdef CONFIG_PM && (!local->ops->suspend || !local->ops->resume) #endif ) return -EINVAL; if (hw->max_report_rates == 0) hw->max_report_rates = hw->max_rates; /* * generic code guarantees at least one band, * set this very early because much code assumes * that hw.conf.channel is assigned */ channels = 0; max_bitrates = 0; supp_ht = false; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; sband = local->hw.wiphy->bands[band]; if (!sband) continue; if (!local->oper_channel) { /* init channel we're on */ local->hw.conf.channel = local->oper_channel = &sband->channels[0]; local->hw.conf.channel_type = NL80211_CHAN_NO_HT; } channels += sband->n_channels; if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; } local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + sizeof(void *) * channels, GFP_KERNEL); if (!local->int_scan_req) return -ENOMEM; /* if low-level driver supports AP, we also support VLAN */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN); } /* mac80211 always supports monitor */ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); /* * mac80211 doesn't support more than 1 channel, and also not more * than one IBSS interface */ for (i = 0; i < hw->wiphy->n_iface_combinations; i++) { const struct ieee80211_iface_combination *c; int j; c = &hw->wiphy->iface_combinations[i]; if (c->num_different_channels > 1) return -EINVAL; for (j = 0; j < c->n_limits; j++) if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && c->limits[j].max > 1) return -EINVAL; } #ifndef CONFIG_MAC80211_MESH /* mesh depends on Kconfig, but drivers should set it if they want */ local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); #endif /* if the underlying driver supports mesh, mac80211 will (at least) * provide routing of mesh authentication frames to userspace */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH; /* mac80211 supports control port protocol changing */ local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); /* * Calculate scan IE length -- we need this to alloc * memory and to subtract from the driver limit. It * includes the DS Params, (extended) supported rates, and HT * information -- SSID is the driver's responsibility. */ local->scan_ies_len = 4 + max_bitrates /* (ext) supp rates */ + 3 /* DS Params */; if (supp_ht) local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ local->hw.wiphy->max_scan_ssids = 4; local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; } /* * If the driver supports any scan IEs, then assume the * limit includes the IEs mac80211 will add, otherwise * leave it at zero and let the driver sort it out; we * still pass our IEs to the driver but userspace will * not be allowed to in that case. */ if (local->hw.wiphy->max_scan_ie_len) local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; /* Set up cipher suites unless driver already did */ if (!local->hw.wiphy->cipher_suites) { local->hw.wiphy->cipher_suites = cipher_suites; local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) local->hw.wiphy->n_cipher_suites--; } if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { if (local->hw.wiphy->cipher_suites == cipher_suites) { local->hw.wiphy->cipher_suites += 2; local->hw.wiphy->n_cipher_suites -= 2; } else { u32 *suites; int r, w = 0; /* Filter out WEP */ suites = kmemdup( local->hw.wiphy->cipher_suites, sizeof(u32) * local->hw.wiphy->n_cipher_suites, GFP_KERNEL); if (!suites) return -ENOMEM; for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { u32 suite = local->hw.wiphy->cipher_suites[r]; if (suite == WLAN_CIPHER_SUITE_WEP40 || suite == WLAN_CIPHER_SUITE_WEP104) continue; suites[w++] = suite; } local->hw.wiphy->cipher_suites = suites; local->hw.wiphy->n_cipher_suites = w; local->wiphy_ciphers_allocated = true; } } if (!local->ops->remain_on_channel) local->hw.wiphy->max_remain_on_channel_duration = 5000; if (local->ops->sched_scan_start) local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; result = wiphy_register(local->hw.wiphy); if (result < 0) goto fail_wiphy_register; /* * We use the number of queues for feature tests (QoS, HT) internally * so restrict them appropriately. */ if (hw->queues > IEEE80211_MAX_QUEUES) hw->queues = IEEE80211_MAX_QUEUES; local->workqueue = alloc_ordered_workqueue(wiphy_name(local->hw.wiphy), 0); if (!local->workqueue) { result = -ENOMEM; goto fail_workqueue; } /* * The hardware needs headroom for sending the frame, * and we need some headroom for passing the frame to monitor * interfaces, but never both at the same time. */ #ifndef __CHECKER__ BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != sizeof(struct ieee80211_tx_status_rtap_hdr)); #endif local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, sizeof(struct ieee80211_tx_status_rtap_hdr)); debugfs_hw_add(local); /* * if the driver doesn't specify a max listen interval we * use 5 which should be a safe default */ if (local->hw.max_listen_interval == 0) local->hw.max_listen_interval = 5; local->hw.conf.listen_interval = local->hw.max_listen_interval; local->dynamic_ps_forced_timeout = -1; result = ieee80211_wep_init(local); if (result < 0) wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", result); rtnl_lock(); result = ieee80211_init_rate_ctrl_alg(local, hw->rate_control_algorithm); if (result < 0) { wiphy_debug(local->hw.wiphy, "Failed to initialize rate control algorithm\n"); goto fail_rate; } /* add one default STA interface if supported */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { result = ieee80211_if_add(local, "wlan%d", NULL, NL80211_IFTYPE_STATION, NULL); if (result) wiphy_warn(local->hw.wiphy, "Failed to add default virtual iface\n"); } rtnl_unlock(); ieee80211_led_init(local); local->network_latency_notifier.notifier_call = ieee80211_max_network_latency; result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, &local->network_latency_notifier); if (result) { rtnl_lock(); goto fail_pm_qos; } #ifdef CONFIG_INET local->ifa_notifier.notifier_call = ieee80211_ifa_changed; result = register_inetaddr_notifier(&local->ifa_notifier); if (result) goto fail_ifa; #endif netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, local->hw.napi_weight); return 0; #ifdef CONFIG_INET fail_ifa: pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, &local->network_latency_notifier); rtnl_lock(); #endif fail_pm_qos: ieee80211_led_exit(local); ieee80211_remove_interfaces(local); fail_rate: rtnl_unlock(); ieee80211_wep_free(local); sta_info_stop(local); destroy_workqueue(local->workqueue); fail_workqueue: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: if (local->wiphy_ciphers_allocated) kfree(local->hw.wiphy->cipher_suites); kfree(local->int_scan_req); return result; }
static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan) { static const u32 adm8211_rfmd2958_reg5[] = {0x22BD, 0x22D2, 0x22E8, 0x22FE, 0x2314, 0x232A, 0x2340, 0x2355, 0x236B, 0x2381, 0x2397, 0x23AD, 0x23C2, 0x23F7}; static const u32 adm8211_rfmd2958_reg6[] = {0x05D17, 0x3A2E8, 0x2E8BA, 0x22E8B, 0x1745D, 0x0BA2E, 0x00000, 0x345D1, 0x28BA2, 0x1D174, 0x11745, 0x05D17, 0x3A2E8, 0x11745}; struct adm8211_priv *priv = dev->priv; u8 ant_power = priv->ant_power > 0x3F ? priv->eeprom->antenna_power[chan - 1] : priv->ant_power; u8 tx_power = priv->tx_power > 0x3F ? priv->eeprom->tx_power[chan - 1] : priv->tx_power; u8 lpf_cutoff = priv->lpf_cutoff == 0xFF ? priv->eeprom->lpf_cutoff[chan - 1] : priv->lpf_cutoff; u8 lnags_thresh = priv->lnags_threshold == 0xFF ? priv->eeprom->lnags_threshold[chan - 1] : priv->lnags_threshold; u32 reg; ADM8211_IDLE(); /* Program synthesizer to new channel */ switch (priv->transceiver_type) { case ADM8211_RFMD2958: case ADM8211_RFMD2958_RF3000_CONTROL_POWER: adm8211_rf_write_syn_rfmd2958(dev, 0x00, 0x04007); adm8211_rf_write_syn_rfmd2958(dev, 0x02, 0x00033); adm8211_rf_write_syn_rfmd2958(dev, 0x05, adm8211_rfmd2958_reg5[chan - 1]); adm8211_rf_write_syn_rfmd2958(dev, 0x06, adm8211_rfmd2958_reg6[chan - 1]); break; case ADM8211_RFMD2948: adm8211_rf_write_syn_rfmd2948(dev, SI4126_MAIN_CONF, SI4126_MAIN_XINDIV2); adm8211_rf_write_syn_rfmd2948(dev, SI4126_POWERDOWN, SI4126_POWERDOWN_PDIB | SI4126_POWERDOWN_PDRB); adm8211_rf_write_syn_rfmd2948(dev, SI4126_PHASE_DET_GAIN, 0); adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_N_DIV, (chan == 14 ? 2110 : (2033 + (chan * 5)))); adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_N_DIV, 1496); adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_R_DIV, 44); adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_R_DIV, 44); break; case ADM8211_MAX2820: adm8211_rf_write_syn_max2820(dev, 0x3, (chan == 14 ? 0x054 : (0x7 + (chan * 5)))); break; case ADM8211_AL2210L: adm8211_rf_write_syn_al2210l(dev, 0x0, (chan == 14 ? 0x229B4 : (0x22967 + (chan * 5)))); break; default: wiphy_debug(dev->wiphy, "unsupported transceiver type %d\n", priv->transceiver_type); break; } /* write BBP regs */ if (priv->bbp_type == ADM8211_TYPE_RFMD) { /* SMC 2635W specific? adm8211b doesn't use the 2948 though.. */ /* TODO: remove if SMC 2635W doesn't need this */ if (priv->transceiver_type == ADM8211_RFMD2948) { reg = ADM8211_CSR_READ(GPIO); reg &= 0xfffc0000; reg |= ADM8211_CSR_GPIO_EN0; if (chan != 14) reg |= ADM8211_CSR_GPIO_O0; ADM8211_CSR_WRITE(GPIO, reg); } if (priv->transceiver_type == ADM8211_RFMD2958) { /* set PCNT2 */ adm8211_rf_write_syn_rfmd2958(dev, 0x0B, 0x07100); /* set PCNT1 P_DESIRED/MID_BIAS */ reg = le16_to_cpu(priv->eeprom->cr49); reg >>= 13; reg <<= 15; reg |= ant_power << 9; adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg); /* set TXRX TX_GAIN */ adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 | (priv->pdev->revision < ADM8211_REV_CA ? tx_power : 0)); } else {
static void adm8211_interrupt_rci(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; unsigned int entry = priv->cur_rx % priv->rx_ring_size; u32 status; unsigned int pktlen; struct sk_buff *skb, *newskb; unsigned int limit = priv->rx_ring_size; u8 rssi, rate; while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) { if (!limit--) break; status = le32_to_cpu(priv->rx_ring[entry].status); rate = (status & RDES0_STATUS_RXDR) >> 12; rssi = le32_to_cpu(priv->rx_ring[entry].length) & RDES1_STATUS_RSSI; pktlen = status & RDES0_STATUS_FL; if (pktlen > RX_PKT_SIZE) { if (net_ratelimit()) wiphy_debug(dev->wiphy, "frame too long (%d)\n", pktlen); pktlen = RX_PKT_SIZE; } if (!priv->soft_rx_crc && status & RDES0_STATUS_ES) { skb = NULL; /* old buffer will be reused */ /* TODO: update RX error stats */ /* TODO: check RDES0_STATUS_CRC*E */ } else if (pktlen < RX_COPY_BREAK) { skb = dev_alloc_skb(pktlen); if (skb) { pci_dma_sync_single_for_cpu( priv->pdev, priv->rx_buffers[entry].mapping, pktlen, PCI_DMA_FROMDEVICE); memcpy(skb_put(skb, pktlen), skb_tail_pointer(priv->rx_buffers[entry].skb), pktlen); pci_dma_sync_single_for_device( priv->pdev, priv->rx_buffers[entry].mapping, RX_PKT_SIZE, PCI_DMA_FROMDEVICE); } } else { newskb = dev_alloc_skb(RX_PKT_SIZE); if (newskb) { skb = priv->rx_buffers[entry].skb; skb_put(skb, pktlen); pci_unmap_single( priv->pdev, priv->rx_buffers[entry].mapping, RX_PKT_SIZE, PCI_DMA_FROMDEVICE); priv->rx_buffers[entry].skb = newskb; priv->rx_buffers[entry].mapping = pci_map_single(priv->pdev, skb_tail_pointer(newskb), RX_PKT_SIZE, PCI_DMA_FROMDEVICE); } else { skb = NULL; /* TODO: update rx dropped stats */ } priv->rx_ring[entry].buffer1 = cpu_to_le32(priv->rx_buffers[entry].mapping); } priv->rx_ring[entry].status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL); priv->rx_ring[entry].length = cpu_to_le32(RX_PKT_SIZE | (entry == priv->rx_ring_size - 1 ? RDES1_CONTROL_RER : 0)); if (skb) { struct ieee80211_rx_status rx_status = {0}; if (priv->pdev->revision < ADM8211_REV_CA) rx_status.signal = rssi; else rx_status.signal = 100 - rssi; rx_status.rate_idx = rate; rx_status.freq = adm8211_channels[priv->channel - 1].center_freq; rx_status.band = IEEE80211_BAND_2GHZ; memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(dev, skb); } entry = (++priv->cur_rx) % priv->rx_ring_size; } /* TODO: check LPC and update stats? */ }