📄 ar5211.c
字号:
/* $OpenBSD: ar5211.c,v 1.25 2005/12/18 17:59:58 reyk Exp $ *//* * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *//* * HAL interface for the Atheros AR5001 Wireless LAN chipset * (AR5211 + AR5111). */#include "ar5xxx.h"#include "ar5211reg.h"#include "ar5211var.h"HAL_BOOL ar5k_ar5211_nic_reset(struct ath_hal *, u_int32_t);HAL_BOOL ar5k_ar5211_nic_wakeup(struct ath_hal *, u_int16_t);u_int16_t ar5k_ar5211_radio_revision(struct ath_hal *, HAL_CHIP);void ar5k_ar5211_fill(struct ath_hal *);void ar5k_ar5211_rfregs(struct ath_hal *, HAL_CHANNEL *, u_int, u_int);/* * Initial register setting for the AR5211 */static const struct ar5k_ini ar5211_ini[] = AR5K_AR5211_INI;static const struct ar5k_ar5211_ini_mode ar5211_mode[] = AR5K_AR5211_INI_MODE;static const struct ar5k_ar5211_ini_rf ar5211_rf[] = AR5K_AR5211_INI_RF;AR5K_HAL_FUNCTIONS(extern, ar5k_ar5211,);voidar5k_ar5211_fill(struct ath_hal *hal){ hal->ah_magic = AR5K_AR5211_MAGIC; /* * Init/Exit functions */ AR5K_HAL_FUNCTION(hal, ar5211, get_rate_table); AR5K_HAL_FUNCTION(hal, ar5211, detach); /* * Reset functions */ AR5K_HAL_FUNCTION(hal, ar5211, reset); AR5K_HAL_FUNCTION(hal, ar5211, set_opmode); AR5K_HAL_FUNCTION(hal, ar5211, calibrate); /* * TX functions */ AR5K_HAL_FUNCTION(hal, ar5211, update_tx_triglevel); AR5K_HAL_FUNCTION(hal, ar5211, setup_tx_queue); AR5K_HAL_FUNCTION(hal, ar5211, setup_tx_queueprops); AR5K_HAL_FUNCTION(hal, ar5211, release_tx_queue); AR5K_HAL_FUNCTION(hal, ar5211, reset_tx_queue); AR5K_HAL_FUNCTION(hal, ar5211, get_tx_buf); AR5K_HAL_FUNCTION(hal, ar5211, put_tx_buf); AR5K_HAL_FUNCTION(hal, ar5211, tx_start); AR5K_HAL_FUNCTION(hal, ar5211, stop_tx_dma); AR5K_HAL_FUNCTION(hal, ar5211, setup_tx_desc); AR5K_HAL_FUNCTION(hal, ar5211, setup_xtx_desc); AR5K_HAL_FUNCTION(hal, ar5211, fill_tx_desc); AR5K_HAL_FUNCTION(hal, ar5211, proc_tx_desc); AR5K_HAL_FUNCTION(hal, ar5211, has_veol); /* * RX functions */ AR5K_HAL_FUNCTION(hal, ar5211, get_rx_buf); AR5K_HAL_FUNCTION(hal, ar5211, put_rx_buf); AR5K_HAL_FUNCTION(hal, ar5211, start_rx); AR5K_HAL_FUNCTION(hal, ar5211, stop_rx_dma); AR5K_HAL_FUNCTION(hal, ar5211, start_rx_pcu); AR5K_HAL_FUNCTION(hal, ar5211, stop_pcu_recv); AR5K_HAL_FUNCTION(hal, ar5211, set_mcast_filter); AR5K_HAL_FUNCTION(hal, ar5211, set_mcast_filterindex); AR5K_HAL_FUNCTION(hal, ar5211, clear_mcast_filter_idx); AR5K_HAL_FUNCTION(hal, ar5211, get_rx_filter); AR5K_HAL_FUNCTION(hal, ar5211, set_rx_filter); AR5K_HAL_FUNCTION(hal, ar5211, setup_rx_desc); AR5K_HAL_FUNCTION(hal, ar5211, proc_rx_desc); AR5K_HAL_FUNCTION(hal, ar5211, set_rx_signal); /* * Misc functions */ AR5K_HAL_FUNCTION(hal, ar5211, dump_state); AR5K_HAL_FUNCTION(hal, ar5211, get_diag_state); AR5K_HAL_FUNCTION(hal, ar5211, get_lladdr); AR5K_HAL_FUNCTION(hal, ar5211, set_lladdr); AR5K_HAL_FUNCTION(hal, ar5211, set_regdomain); AR5K_HAL_FUNCTION(hal, ar5211, set_ledstate); AR5K_HAL_FUNCTION(hal, ar5211, set_associd); AR5K_HAL_FUNCTION(hal, ar5211, set_gpio_input); AR5K_HAL_FUNCTION(hal, ar5211, set_gpio_output); AR5K_HAL_FUNCTION(hal, ar5211, get_gpio); AR5K_HAL_FUNCTION(hal, ar5211, set_gpio); AR5K_HAL_FUNCTION(hal, ar5211, set_gpio_intr); AR5K_HAL_FUNCTION(hal, ar5211, get_tsf32); AR5K_HAL_FUNCTION(hal, ar5211, get_tsf64); AR5K_HAL_FUNCTION(hal, ar5211, reset_tsf); AR5K_HAL_FUNCTION(hal, ar5211, get_regdomain); AR5K_HAL_FUNCTION(hal, ar5211, detect_card_present); AR5K_HAL_FUNCTION(hal, ar5211, update_mib_counters); AR5K_HAL_FUNCTION(hal, ar5211, get_rf_gain); AR5K_HAL_FUNCTION(hal, ar5211, set_slot_time); AR5K_HAL_FUNCTION(hal, ar5211, get_slot_time); AR5K_HAL_FUNCTION(hal, ar5211, set_ack_timeout); AR5K_HAL_FUNCTION(hal, ar5211, get_ack_timeout); AR5K_HAL_FUNCTION(hal, ar5211, set_cts_timeout); AR5K_HAL_FUNCTION(hal, ar5211, get_cts_timeout); /* * Key table (WEP) functions */ AR5K_HAL_FUNCTION(hal, ar5211, is_cipher_supported); AR5K_HAL_FUNCTION(hal, ar5211, get_keycache_size); AR5K_HAL_FUNCTION(hal, ar5211, reset_key); AR5K_HAL_FUNCTION(hal, ar5211, is_key_valid); AR5K_HAL_FUNCTION(hal, ar5211, set_key); AR5K_HAL_FUNCTION(hal, ar5211, set_key_lladdr); /* * Power management functions */ AR5K_HAL_FUNCTION(hal, ar5211, set_power); AR5K_HAL_FUNCTION(hal, ar5211, get_power_mode); AR5K_HAL_FUNCTION(hal, ar5211, query_pspoll_support); AR5K_HAL_FUNCTION(hal, ar5211, init_pspoll); AR5K_HAL_FUNCTION(hal, ar5211, enable_pspoll); AR5K_HAL_FUNCTION(hal, ar5211, disable_pspoll); /* * Beacon functions */ AR5K_HAL_FUNCTION(hal, ar5211, init_beacon); AR5K_HAL_FUNCTION(hal, ar5211, set_beacon_timers); AR5K_HAL_FUNCTION(hal, ar5211, reset_beacon); AR5K_HAL_FUNCTION(hal, ar5211, wait_for_beacon); /* * Interrupt functions */ AR5K_HAL_FUNCTION(hal, ar5211, is_intr_pending); AR5K_HAL_FUNCTION(hal, ar5211, get_isr); AR5K_HAL_FUNCTION(hal, ar5211, get_intr); AR5K_HAL_FUNCTION(hal, ar5211, set_intr); /* * Chipset functions (ar5k-specific, non-HAL) */ AR5K_HAL_FUNCTION(hal, ar5211, get_capabilities); AR5K_HAL_FUNCTION(hal, ar5211, radar_alert); /* * EEPROM access */ AR5K_HAL_FUNCTION(hal, ar5211, eeprom_is_busy); AR5K_HAL_FUNCTION(hal, ar5211, eeprom_read); AR5K_HAL_FUNCTION(hal, ar5211, eeprom_write); /* Functions not found in OpenBSD */ AR5K_HAL_FUNCTION(hal, ar5211, get_tx_queueprops); AR5K_HAL_FUNCTION(hal, ar5211, get_capability); AR5K_HAL_FUNCTION(hal, ar5211, num_tx_pending); AR5K_HAL_FUNCTION(hal, ar5211, phy_disable); AR5K_HAL_FUNCTION(hal, ar5211, set_pcu_config); /*Totaly unimplemented*/ AR5K_HAL_FUNCTION(hal, ar5211, set_capability); AR5K_HAL_FUNCTION(hal, ar5211, proc_mib_event); AR5K_HAL_FUNCTION(hal, ar5211, get_tx_inter_queue); AR5K_HAL_FUNCTION(hal, ar5211, set_txpower_limit); AR5K_HAL_FUNCTION(hal, ar5211, set_def_antenna); AR5K_HAL_FUNCTION(hal, ar5211, get_def_antenna);}struct ath_hal * /*Ported & removed an arg from call to set_associd*/ar5k_ar5211_attach(u_int16_t device, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status){ struct ath_hal *hal = (struct ath_hal*) sc; u_int8_t mac[IEEE80211_ADDR_LEN]; u_int32_t srev; ar5k_ar5211_fill(hal); /* Bring device out of sleep and reset it's units */ if (ar5k_ar5211_nic_wakeup(hal, AR5K_INIT_MODE) != AH_TRUE) return (NULL); /* Get MAC, PHY and RADIO revisions */ srev = AR5K_REG_READ(AR5K_AR5211_SREV); hal->ah_mac_srev = srev; hal->ah_mac_version = AR5K_REG_MS(srev, AR5K_AR5211_SREV_VER); hal->ah_mac_revision = AR5K_REG_MS(srev, AR5K_AR5211_SREV_REV); hal->ah_phy_revision = AR5K_REG_READ(AR5K_AR5211_PHY_CHIP_ID) & 0x00ffffffff; hal->ah_radio_5ghz_revision = ar5k_ar5211_radio_revision(hal, HAL_CHIP_5GHZ); hal->ah_radio_2ghz_revision = 0; /* Identify the chipset (this has to be done in an early step) */ hal->ah_version = AR5K_AR5211; hal->ah_radio = AR5K_AR5111; hal->ah_phy = AR5K_AR5211_PHY(0); bcopy(etherbroadcastaddr, mac, IEEE80211_ADDR_LEN); ar5k_ar5211_set_associd(hal, mac, 0); ar5k_ar5211_get_lladdr(hal, mac); ar5k_ar5211_set_opmode(hal); return (hal);}HAL_BOOLar5k_ar5211_nic_reset(struct ath_hal *hal, u_int32_t val){ HAL_BOOL ret = AH_FALSE; u_int32_t mask = val ? val : ~0; /* Read-and-clear */ AR5K_REG_READ(AR5K_AR5211_RXDP); /* * Reset the device and wait until success */ AR5K_REG_WRITE(AR5K_AR5211_RC, val); /* Wait at least 128 PCI clocks */ AR5K_DELAY(15); val &= AR5K_AR5211_RC_PCU | AR5K_AR5211_RC_BB; mask &= AR5K_AR5211_RC_PCU | AR5K_AR5211_RC_BB; ret = ar5k_register_timeout(hal, AR5K_AR5211_RC, mask, val, AH_FALSE); /* * Reset configuration register */ if ((val & AR5K_AR5211_RC_PCU) == 0) AR5K_REG_WRITE(AR5K_AR5211_CFG, AR5K_AR5211_INIT_CFG); return (ret);}HAL_BOOLar5k_ar5211_nic_wakeup(struct ath_hal *hal, u_int16_t flags){ u_int32_t turbo, mode, clock; turbo = 0; mode = 0; clock = 0; /* * Get channel mode flags */ if (flags & IEEE80211_CHAN_2GHZ) { mode |= AR5K_AR5211_PHY_MODE_FREQ_2GHZ; clock |= AR5K_AR5211_PHY_PLL_44MHZ; } else if (flags & IEEE80211_CHAN_5GHZ) { mode |= AR5K_AR5211_PHY_MODE_FREQ_5GHZ; clock |= AR5K_AR5211_PHY_PLL_40MHZ; } else { AR5K_PRINT("invalid radio frequency mode\n"); return (AH_FALSE); } if ((flags & IEEE80211_CHAN_CCK) || (flags & IEEE80211_CHAN_DYN)) { /* Dynamic OFDM/CCK is not supported by the AR5211 */ mode |= AR5K_AR5211_PHY_MODE_MOD_CCK; } else if (flags & IEEE80211_CHAN_OFDM) { mode |= AR5K_AR5211_PHY_MODE_MOD_OFDM; } else { AR5K_PRINT("invalid radio frequency mode\n"); return (AH_FALSE); } if (flags & IEEE80211_CHAN_TURBO) { turbo = AR5K_AR5211_PHY_TURBO_MODE | AR5K_AR5211_PHY_TURBO_SHORT; } /* * Reset and wakeup the device */ /* ...reset chipset and PCI device */ if (ar5k_ar5211_nic_reset(hal, AR5K_AR5211_RC_CHIP | AR5K_AR5211_RC_PCI) == AH_FALSE) { AR5K_PRINT("failed to reset the AR5211 + PCI chipset\n"); return (AH_FALSE); } /* ...wakeup */ if (ar5k_ar5211_set_power(hal, HAL_PM_AWAKE, AH_TRUE, 0) == AH_FALSE) { AR5K_PRINT("failed to resume the AR5211 (again)\n"); return (AH_FALSE); } /* ...final warm reset */ if (ar5k_ar5211_nic_reset(hal, 0) == AH_FALSE) { AR5K_PRINT("failed to warm reset the AR5211\n"); return (AH_FALSE); } /* ...set the PHY operating mode */ AR5K_REG_WRITE(AR5K_AR5211_PHY_PLL, clock); AR5K_DELAY(300); AR5K_REG_WRITE(AR5K_AR5211_PHY_MODE, mode); AR5K_REG_WRITE(AR5K_AR5211_PHY_TURBO, turbo); return (AH_TRUE);}u_int16_tar5k_ar5211_radio_revision(struct ath_hal *hal, HAL_CHIP chip){ int i; u_int32_t srev; u_int16_t ret; /* * Set the radio chip access register */ switch (chip) { case HAL_CHIP_2GHZ: AR5K_REG_WRITE(AR5K_AR5211_PHY(0), AR5K_AR5211_PHY_SHIFT_2GHZ); break; case HAL_CHIP_5GHZ: AR5K_REG_WRITE(AR5K_AR5211_PHY(0), AR5K_AR5211_PHY_SHIFT_5GHZ); break; default: return (0); } AR5K_DELAY(2000); /* ...wait until PHY is ready and read the selected radio revision */ AR5K_REG_WRITE(AR5K_AR5211_PHY(0x34), 0x00001c16); for (i = 0; i < 8; i++) AR5K_REG_WRITE(AR5K_AR5211_PHY(0x20), 0x00010000); srev = (AR5K_REG_READ(AR5K_AR5211_PHY(0x100)) >> 24) & 0xff; ret = ar5k_bitswap(((srev & 0xf0) >> 4) | ((srev & 0x0f) << 4), 8); /* Reset to the 5GHz mode */ AR5K_REG_WRITE(AR5K_AR5211_PHY(0), AR5K_AR5211_PHY_SHIFT_5GHZ); return (ret);}const HAL_RATE_TABLE *ar5k_ar5211_get_rate_table(struct ath_hal *hal, u_int mode){ switch (mode) { case HAL_MODE_11A: return (&hal->ah_rt_11a); case HAL_MODE_TURBO: return (&hal->ah_rt_turbo); case HAL_MODE_11B: return (&hal->ah_rt_11b); case HAL_MODE_11G: case HAL_MODE_PUREG: return (&hal->ah_rt_11g); default: return (NULL); } return (NULL);}void /*O.K.*/ar5k_ar5211_detach(struct ath_hal *hal){ /* * Free HAL structure, assume interrupts are down */ free(hal, M_DEVBUF);}HAL_BOOL /*New*/ar5k_ar5211_phy_disable(struct ath_hal *hal){ AR5K_TRACE; /*Just a try M.F.*/ AR5K_REG_WRITE(AR5K_AR5211_PHY_ACTIVE, AR5K_AR5211_PHY_DISABLE); return AH_TRUE;}HAL_BOOL /*Ported*/ar5k_ar5211_reset(struct ath_hal *hal, HAL_OPMODE op_mode, HAL_CHANNEL *channel, HAL_BOOL change_channel, HAL_STATUS *status){ struct ar5k_eeprom_info *ee = &hal->ah_capabilities.cap_eeprom; u_int8_t mac[IEEE80211_ADDR_LEN]; u_int32_t data, s_seq, s_ant, s_led[3]; u_int i, mode, freq, ee_mode, ant[2]; /* * Save some registers before a reset */ if (change_channel == AH_TRUE) { s_seq = AR5K_REG_READ(AR5K_AR5211_DCU_SEQNUM(0)); s_ant = AR5K_REG_READ(AR5K_AR5211_DEFAULT_ANTENNA); } else { s_seq = 0; s_ant = 1; } s_led[0] = AR5K_REG_READ(AR5K_AR5211_PCICFG) & AR5K_AR5211_PCICFG_LEDSTATE; s_led[1] = AR5K_REG_READ(AR5K_AR5211_GPIOCR); s_led[2] = AR5K_REG_READ(AR5K_AR5211_GPIODO); if (ar5k_ar5211_nic_wakeup(hal, channel->c_channel_flags) == AH_FALSE) return (AH_FALSE); /* * Initialize operating mode */ hal->ah_op_mode = op_mode; if (channel->c_channel_flags & IEEE80211_CHAN_A) { mode = AR5K_INI_VAL_11A; freq = AR5K_INI_RFGAIN_5GHZ; ee_mode = AR5K_EEPROM_MODE_11A; } else if (channel->c_channel_flags & IEEE80211_CHAN_T) { mode = AR5K_INI_VAL_11A_TURBO; freq = AR5K_INI_RFGAIN_5GHZ; ee_mode = AR5K_EEPROM_MODE_11A; } else if (channel->c_channel_flags & IEEE80211_CHAN_B) { mode = AR5K_INI_VAL_11B; freq = AR5K_INI_RFGAIN_2GHZ; ee_mode = AR5K_EEPROM_MODE_11B; } else if (channel->c_channel_flags & IEEE80211_CHAN_G) { mode = AR5K_INI_VAL_11G; freq = AR5K_INI_RFGAIN_2GHZ; ee_mode = AR5K_EEPROM_MODE_11G; } else { AR5K_PRINTF("invalid channel: %d\n", channel->c_channel); return (AH_FALSE); } /* PHY access enable */ AR5K_REG_WRITE(AR5K_AR5211_PHY(0), AR5K_AR5211_PHY_SHIFT_5GHZ); /* * Write initial RF registers */ ar5k_ar5211_rfregs(hal, channel, freq, ee_mode); /* * Write initial mode settings */ for (i = 0; i < AR5K_ELEMENTS(ar5211_mode); i++) { AR5K_REG_WAIT(i); AR5K_REG_WRITE((u_int32_t)ar5211_mode[i].mode_register, ar5211_mode[i].mode_value[mode]); } /* * Write initial register settings */ for (i = 0; i < AR5K_ELEMENTS(ar5211_ini); i++) { if (change_channel == AH_TRUE && ar5211_ini[i].ini_register >= AR5K_AR5211_PCU_MIN && ar5211_ini[i].ini_register <= AR5K_AR5211_PCU_MAX) continue; AR5K_REG_WAIT(i); AR5K_REG_WRITE((u_int32_t)ar5211_ini[i].ini_register, ar5211_ini[i].ini_value); } /* * Write initial RF gain settings */ if (ar5k_rfgain(hal, AR5K_INI_PHY_5111, freq) == AH_FALSE) return (AH_FALSE); AR5K_DELAY(1000); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -