📄 ar5212.c
字号:
/* $OpenBSD: ar5212.c,v 1.28 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 * (AR5212 + AR5111/AR5112). */#include "ar5xxx.h"#include "ar5212reg.h"#include "ar5212var.h"HAL_BOOL ar5k_ar5212_nic_reset(struct ath_hal *, u_int32_t);HAL_BOOL ar5k_ar5212_nic_wakeup(struct ath_hal *, u_int16_t);u_int16_t ar5k_ar5212_radio_revision(struct ath_hal *, HAL_CHIP);void ar5k_ar5212_fill(struct ath_hal *);HAL_BOOL ar5k_ar5212_txpower(struct ath_hal *, HAL_CHANNEL *, u_int);/* * Initial register setting for the AR5212 */static const struct ar5k_ar5212_ini ar5212_ini[] = AR5K_AR5212_INI;static const struct ar5k_ar5212_ini_mode ar5212_mode[] = AR5K_AR5212_INI_MODE;AR5K_HAL_FUNCTIONS(extern, ar5k_ar5212,);void /*Functions added*/ar5k_ar5212_fill(struct ath_hal *hal){ hal->ah_magic = AR5K_AR5212_MAGIC; /* * Init/Exit functions */ AR5K_HAL_FUNCTION(hal, ar5212, get_rate_table); AR5K_HAL_FUNCTION(hal, ar5212, detach); /* * Reset functions */ AR5K_HAL_FUNCTION(hal, ar5212, reset); //AR5K_HAL_FUNCTION(hal, ar5212, set_opmode); AR5K_HAL_FUNCTION(hal, ar5212, calibrate); /* * TX functions */ AR5K_HAL_FUNCTION(hal, ar5212, update_tx_triglevel); AR5K_HAL_FUNCTION(hal, ar5212, setup_tx_queue); AR5K_HAL_FUNCTION(hal, ar5212, setup_tx_queueprops); AR5K_HAL_FUNCTION(hal, ar5212, release_tx_queue); AR5K_HAL_FUNCTION(hal, ar5212, reset_tx_queue); AR5K_HAL_FUNCTION(hal, ar5212, get_tx_buf); AR5K_HAL_FUNCTION(hal, ar5212, put_tx_buf); AR5K_HAL_FUNCTION(hal, ar5212, tx_start); AR5K_HAL_FUNCTION(hal, ar5212, stop_tx_dma); AR5K_HAL_FUNCTION(hal, ar5212, setup_tx_desc); AR5K_HAL_FUNCTION(hal, ar5212, setup_xtx_desc); AR5K_HAL_FUNCTION(hal, ar5212, fill_tx_desc); AR5K_HAL_FUNCTION(hal, ar5212, proc_tx_desc); AR5K_HAL_FUNCTION(hal, ar5212, has_veol); /* * RX functions */ AR5K_HAL_FUNCTION(hal, ar5212, get_rx_buf); AR5K_HAL_FUNCTION(hal, ar5212, put_rx_buf); AR5K_HAL_FUNCTION(hal, ar5212, start_rx); AR5K_HAL_FUNCTION(hal, ar5212, stop_rx_dma); AR5K_HAL_FUNCTION(hal, ar5212, start_rx_pcu); AR5K_HAL_FUNCTION(hal, ar5212, stop_pcu_recv); AR5K_HAL_FUNCTION(hal, ar5212, set_mcast_filter); AR5K_HAL_FUNCTION(hal, ar5212, set_mcast_filterindex); AR5K_HAL_FUNCTION(hal, ar5212, clear_mcast_filter_idx); AR5K_HAL_FUNCTION(hal, ar5212, get_rx_filter); AR5K_HAL_FUNCTION(hal, ar5212, set_rx_filter); AR5K_HAL_FUNCTION(hal, ar5212, setup_rx_desc); AR5K_HAL_FUNCTION(hal, ar5212, proc_rx_desc); AR5K_HAL_FUNCTION(hal, ar5212, set_rx_signal); /* * Misc functions */ AR5K_HAL_FUNCTION(hal, ar5212, dump_state); AR5K_HAL_FUNCTION(hal, ar5212, get_diag_state); AR5K_HAL_FUNCTION(hal, ar5212, get_lladdr); AR5K_HAL_FUNCTION(hal, ar5212, set_lladdr); AR5K_HAL_FUNCTION(hal, ar5212, set_regdomain); AR5K_HAL_FUNCTION(hal, ar5212, set_ledstate); AR5K_HAL_FUNCTION(hal, ar5212, set_associd); AR5K_HAL_FUNCTION(hal, ar5212, set_gpio_input); AR5K_HAL_FUNCTION(hal, ar5212, set_gpio_output); AR5K_HAL_FUNCTION(hal, ar5212, get_gpio); AR5K_HAL_FUNCTION(hal, ar5212, set_gpio); AR5K_HAL_FUNCTION(hal, ar5212, set_gpio_intr); AR5K_HAL_FUNCTION(hal, ar5212, get_tsf32); AR5K_HAL_FUNCTION(hal, ar5212, get_tsf64); AR5K_HAL_FUNCTION(hal, ar5212, reset_tsf); AR5K_HAL_FUNCTION(hal, ar5212, get_regdomain); AR5K_HAL_FUNCTION(hal, ar5212, detect_card_present); AR5K_HAL_FUNCTION(hal, ar5212, update_mib_counters); AR5K_HAL_FUNCTION(hal, ar5212, get_rf_gain); AR5K_HAL_FUNCTION(hal, ar5212, set_slot_time); AR5K_HAL_FUNCTION(hal, ar5212, get_slot_time); AR5K_HAL_FUNCTION(hal, ar5212, set_ack_timeout); AR5K_HAL_FUNCTION(hal, ar5212, get_ack_timeout); AR5K_HAL_FUNCTION(hal, ar5212, set_cts_timeout); AR5K_HAL_FUNCTION(hal, ar5212, get_cts_timeout); /* * Key table (WEP) functions */ AR5K_HAL_FUNCTION(hal, ar5212, is_cipher_supported); AR5K_HAL_FUNCTION(hal, ar5212, get_keycache_size); AR5K_HAL_FUNCTION(hal, ar5212, reset_key); AR5K_HAL_FUNCTION(hal, ar5212, is_key_valid); AR5K_HAL_FUNCTION(hal, ar5212, set_key); AR5K_HAL_FUNCTION(hal, ar5212, set_key_lladdr); /* * Power management functions */ AR5K_HAL_FUNCTION(hal, ar5212, set_power); AR5K_HAL_FUNCTION(hal, ar5212, get_power_mode); AR5K_HAL_FUNCTION(hal, ar5212, query_pspoll_support); AR5K_HAL_FUNCTION(hal, ar5212, init_pspoll); AR5K_HAL_FUNCTION(hal, ar5212, enable_pspoll); AR5K_HAL_FUNCTION(hal, ar5212, disable_pspoll); /* * Beacon functions */ AR5K_HAL_FUNCTION(hal, ar5212, init_beacon); AR5K_HAL_FUNCTION(hal, ar5212, set_beacon_timers); AR5K_HAL_FUNCTION(hal, ar5212, reset_beacon); AR5K_HAL_FUNCTION(hal, ar5212, wait_for_beacon); /* * Interrupt functions */ AR5K_HAL_FUNCTION(hal, ar5212, is_intr_pending); AR5K_HAL_FUNCTION(hal, ar5212, get_isr); AR5K_HAL_FUNCTION(hal, ar5212, get_intr); AR5K_HAL_FUNCTION(hal, ar5212, set_intr); /* * Chipset functions (ar5k-specific, non-HAL) */ AR5K_HAL_FUNCTION(hal, ar5212, get_capabilities); AR5K_HAL_FUNCTION(hal, ar5212, radar_alert); /* * EEPROM access */ AR5K_HAL_FUNCTION(hal, ar5212, eeprom_is_busy); AR5K_HAL_FUNCTION(hal, ar5212, eeprom_read); AR5K_HAL_FUNCTION(hal, ar5212, eeprom_write); /* Functions not found in OpenBSD */ AR5K_HAL_FUNCTION(hal, ar5212, get_tx_queueprops); AR5K_HAL_FUNCTION(hal, ar5212, get_capability); AR5K_HAL_FUNCTION(hal, ar5212, num_tx_pending); AR5K_HAL_FUNCTION(hal, ar5212, phy_disable); AR5K_HAL_FUNCTION(hal, ar5212, set_pcu_config); /*Totaly unimplemented*/ AR5K_HAL_FUNCTION(hal, ar5212, set_capability); AR5K_HAL_FUNCTION(hal, ar5212, proc_mib_event); AR5K_HAL_FUNCTION(hal, ar5212, get_tx_inter_queue); AR5K_HAL_FUNCTION(hal, ar5212, set_txpower_limit); AR5K_HAL_FUNCTION(hal, ar5212, set_def_antenna); AR5K_HAL_FUNCTION(hal, ar5212, get_def_antenna);}struct ath_hal * /*Ported & removed an arg from call to set_associd*/ar5k_ar5212_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_TRACE; ar5k_ar5212_fill(hal); /* Bring device out of sleep and reset it's units */ if (ar5k_ar5212_nic_wakeup(hal, AR5K_INIT_MODE) != AH_TRUE) return (NULL); /* Get MAC, PHY and RADIO revisions */ srev = AR5K_REG_READ(AR5K_AR5212_SREV); hal->ah_mac_srev = srev; hal->ah_mac_version = AR5K_REG_MS(srev, AR5K_AR5212_SREV_VER); hal->ah_mac_revision = AR5K_REG_MS(srev, AR5K_AR5212_SREV_REV); hal->ah_phy_revision = AR5K_REG_READ(AR5K_AR5212_PHY_CHIP_ID) & 0x00ffffffff; hal->ah_radio_5ghz_revision = ar5k_ar5212_radio_revision(hal, HAL_CHIP_5GHZ); hal->ah_radio_2ghz_revision = ar5k_ar5212_radio_revision(hal, HAL_CHIP_2GHZ); /* Single chip radio */ if (hal->ah_radio_2ghz_revision == hal->ah_radio_5ghz_revision) hal->ah_radio_2ghz_revision = 0; /* Identify the chipset (this has to be done in an early step) */ hal->ah_version = AR5K_AR5212; hal->ah_radio = hal->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112 ? AR5K_AR5111 : AR5K_AR5112; hal->ah_phy = AR5K_AR5212_PHY(0); bcopy(etherbroadcastaddr, mac, IEEE80211_ADDR_LEN); ar5k_ar5212_set_associd(hal, mac, 0); ar5k_ar5212_get_lladdr(hal, mac); ar5k_ar5212_set_opmode(hal); return (hal);}HAL_BOOL /*O.K.*/ar5k_ar5212_nic_reset(struct ath_hal *hal, u_int32_t val){ HAL_BOOL ret = AH_FALSE; u_int32_t mask = val ? val : ~0; AR5K_TRACE; /* Read-and-clear */ AR5K_REG_READ(AR5K_AR5212_RXDP); /* * Reset the device and wait until success */ AR5K_REG_WRITE(AR5K_AR5212_RC, val); /* Wait at least 128 PCI clocks */ AR5K_DELAY(15); val &= AR5K_AR5212_RC_PCU | AR5K_AR5212_RC_BB; mask &= AR5K_AR5212_RC_PCU | AR5K_AR5212_RC_BB; ret = ar5k_register_timeout(hal, AR5K_AR5212_RC, mask, val, AH_FALSE); /* * Reset configuration register */ if ((val & AR5K_AR5212_RC_PCU) == 0) AR5K_REG_WRITE(AR5K_AR5212_CFG, AR5K_AR5212_INIT_CFG); return (ret);}HAL_BOOL /*O.K.*/ar5k_ar5212_nic_wakeup(struct ath_hal *hal, u_int16_t flags){ u_int32_t turbo, mode, clock; turbo = 0; mode = 0; clock = 0; AR5K_TRACE; /* * Get channel mode flags */ if (hal->ah_radio >= AR5K_AR5112) { mode = AR5K_AR5212_PHY_MODE_RAD_AR5112; clock = AR5K_AR5212_PHY_PLL_AR5112; } else { mode = AR5K_AR5212_PHY_MODE_RAD_AR5111; clock = AR5K_AR5212_PHY_PLL_AR5111; } if (flags & IEEE80211_CHAN_2GHZ) { mode |= AR5K_AR5212_PHY_MODE_FREQ_2GHZ; clock |= AR5K_AR5212_PHY_PLL_44MHZ; } else if (flags & IEEE80211_CHAN_5GHZ) { mode |= AR5K_AR5212_PHY_MODE_FREQ_5GHZ; clock |= AR5K_AR5212_PHY_PLL_40MHZ; } else { AR5K_PRINT("invalid radio frequency mode\n"); return (AH_FALSE); } if (flags & IEEE80211_CHAN_CCK) { mode |= AR5K_AR5212_PHY_MODE_MOD_CCK; } else if (flags & IEEE80211_CHAN_OFDM) { mode |= AR5K_AR5212_PHY_MODE_MOD_OFDM; } else if (flags & IEEE80211_CHAN_DYN) { mode |= AR5K_AR5212_PHY_MODE_MOD_DYN; } else { AR5K_PRINT("invalid radio frequency mode\n"); return (AH_FALSE); } if (flags & IEEE80211_CHAN_TURBO) { turbo = AR5K_AR5212_PHY_TURBO_MODE | AR5K_AR5212_PHY_TURBO_SHORT; } /* * Reset and wakeup the device */ /* ...reset chipset and PCI device */ if (ar5k_ar5212_nic_reset(hal, AR5K_AR5212_RC_CHIP | AR5K_AR5212_RC_PCI) == AH_FALSE) { AR5K_PRINT("failed to reset the AR5212 + PCI chipset\n"); return (AH_FALSE); } /* ...wakeup */ if (ar5k_ar5212_set_power(hal, HAL_PM_AWAKE, AH_TRUE, 0) == AH_FALSE) { AR5K_PRINT("failed to resume the AR5212 (again)\n"); return (AH_FALSE); } /* ...final warm reset */ if (ar5k_ar5212_nic_reset(hal, 0) == AH_FALSE) { AR5K_PRINT("failed to warm reset the AR5212\n"); return (AH_FALSE); } /* ...set the PHY operating mode */ AR5K_REG_WRITE(AR5K_AR5212_PHY_PLL, clock); AR5K_DELAY(300); AR5K_REG_WRITE(AR5K_AR5212_PHY_MODE, mode); AR5K_REG_WRITE(AR5K_AR5212_PHY_TURBO, turbo); return (AH_TRUE);}u_int16_t /*O.K.*/ar5k_ar5212_radio_revision(struct ath_hal *hal, HAL_CHIP chip){ int i; u_int32_t srev; u_int16_t ret; AR5K_TRACE; /* * Set the radio chip access register */ switch (chip) { case HAL_CHIP_2GHZ: AR5K_REG_WRITE(AR5K_AR5212_PHY(0), AR5K_AR5212_PHY_SHIFT_2GHZ); break; case HAL_CHIP_5GHZ: AR5K_REG_WRITE(AR5K_AR5212_PHY(0), AR5K_AR5212_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_AR5212_PHY(0x34), 0x00001c16); for (i = 0; i < 8; i++) AR5K_REG_WRITE(AR5K_AR5212_PHY(0x20), 0x00010000); srev = (AR5K_REG_READ(AR5K_AR5212_PHY(0x100)) >> 24) & 0xff; ret = ar5k_bitswap(((srev & 0xf0) >> 4) | ((srev & 0x0f) << 4), 8); /* Reset to the 5GHz mode */ AR5K_REG_WRITE(AR5K_AR5212_PHY(0), AR5K_AR5212_PHY_SHIFT_5GHZ); return (ret);}const HAL_RATE_TABLE * /*O.K.*/ar5k_ar5212_get_rate_table(struct ath_hal *hal, u_int mode){ AR5K_TRACE; 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); case HAL_MODE_XR: return (&hal->ah_rt_xr); default: return (NULL); } return (NULL);}void /*O.K.*/ar5k_ar5212_detach(struct ath_hal *hal){ AR5K_TRACE; if (hal->ah_rf_banks != NULL) free(hal->ah_rf_banks, M_DEVBUF); /* * Free HAL structure, assume interrupts are down */ free(hal, M_DEVBUF);}HAL_BOOL /*New*/ar5k_ar5212_phy_disable(struct ath_hal *hal){ AR5K_TRACE; /*Just a try M.F.*/ AR5K_REG_WRITE(AR5K_AR5212_PHY_ACTIVE, AR5K_AR5212_PHY_DISABLE); return AH_TRUE;}HAL_BOOL /*Ported & removed last argument from call to set_associd*/ar5k_ar5212_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, phy, mode, freq, off, ee_mode, ant[2]; const HAL_RATE_TABLE *rt; AR5K_TRACE; *status = HAL_OK; /* * Save some registers before a reset */ if (change_channel == AH_TRUE) { s_seq = AR5K_REG_READ(AR5K_AR5212_DCU_SEQNUM(0)); s_ant = AR5K_REG_READ(AR5K_AR5212_DEFAULT_ANTENNA); } else { s_seq = 0; s_ant = 1; } s_led[0] = AR5K_REG_READ(AR5K_AR5212_PCICFG) & AR5K_AR5212_PCICFG_LEDSTATE; s_led[1] = AR5K_REG_READ(AR5K_AR5212_GPIOCR); s_led[2] = AR5K_REG_READ(AR5K_AR5212_GPIODO); if (change_channel == AH_TRUE && hal->ah_rf_banks != NULL) ar5k_ar5212_get_rf_gain(hal); if (ar5k_ar5212_nic_wakeup(hal, channel->c_channel_flags) == AH_FALSE) { *status = HAL_EIO; return (AH_FALSE); } /* * Initialize operating mode */ hal->ah_op_mode = op_mode; if (hal->ah_radio == AR5K_AR5111) { phy = AR5K_INI_PHY_5111; } else if (hal->ah_radio == AR5K_AR5112) { phy = AR5K_INI_PHY_5112; } else { AR5K_PRINTF("invalid phy radio: %u\n", hal->ah_radio);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -