📄 ar5210.c
字号:
goto no; } no: return (HAL_EINVAL); yes: return HAL_OK; }HAL_BOOLar5k_ar5210_set_capability(struct ath_hal *hal, HAL_CAPABILITY_TYPE cap_type, u_int32_t capability, u_int32_t setting, HAL_STATUS *status) { AR5K_TRACE; if (status) { *status = HAL_OK; } return (AH_FALSE);}/* * Key table (WEP) functions */HAL_BOOLar5k_ar5210_is_cipher_supported(struct ath_hal *hal, HAL_CIPHER cipher){ /* * The AR5210 only supports WEP */ if (cipher == HAL_CIPHER_WEP) return (AH_TRUE); return (AH_FALSE);}u_int32_tar5k_ar5210_get_keycache_size(struct ath_hal *hal){ return (AR5K_AR5210_KEYCACHE_SIZE);}HAL_BOOLar5k_ar5210_reset_key(struct ath_hal *hal, u_int16_t entry){ int i; AR5K_ASSERT_ENTRY(entry, AR5K_AR5210_KEYTABLE_SIZE); for (i = 0; i < AR5K_AR5210_KEYCACHE_SIZE; i++) AR5K_REG_WRITE(AR5K_AR5210_KEYTABLE_OFF(entry, i), 0); return (AH_FALSE);}HAL_BOOLar5k_ar5210_is_key_valid(struct ath_hal *hal, u_int16_t entry){ AR5K_ASSERT_ENTRY(entry, AR5K_AR5210_KEYTABLE_SIZE); /* * Check the validation flag at the end of the entry */ if (AR5K_REG_READ(AR5K_AR5210_KEYTABLE_MAC1(entry)) & AR5K_AR5210_KEYTABLE_VALID) return (AH_TRUE); return (AH_FALSE);}HAL_BOOLar5k_ar5210_set_key(struct ath_hal *hal, u_int16_t entry, const HAL_KEYVAL *keyval, const u_int8_t *mac, int xor_notused){ int i; u_int32_t key_v[AR5K_AR5210_KEYCACHE_SIZE - 2]; AR5K_ASSERT_ENTRY(entry, AR5K_AR5210_KEYTABLE_SIZE); bzero(&key_v, sizeof(key_v)); switch (keyval->wk_len) { case AR5K_KEYVAL_LENGTH_40: bcopy(keyval->wk_key, &key_v[0], 4); bcopy(keyval->wk_key + 4, &key_v[1], 1); key_v[5] = AR5K_AR5210_KEYTABLE_TYPE_40; break; case AR5K_KEYVAL_LENGTH_104: bcopy(keyval->wk_key, &key_v[0], 4); bcopy(keyval->wk_key + 4, &key_v[1], 2); bcopy(keyval->wk_key + 6, &key_v[2], 4); bcopy(keyval->wk_key + 10, &key_v[3], 2); bcopy(keyval->wk_key + 12, &key_v[4], 1); key_v[5] = AR5K_AR5210_KEYTABLE_TYPE_104; break; case AR5K_KEYVAL_LENGTH_128: bcopy(keyval->wk_key, &key_v[0], 4); bcopy(keyval->wk_key + 4, &key_v[1], 2); bcopy(keyval->wk_key + 6, &key_v[2], 4); bcopy(keyval->wk_key + 10, &key_v[3], 2); bcopy(keyval->wk_key + 12, &key_v[4], 4); key_v[5] = AR5K_AR5210_KEYTABLE_TYPE_128; break; default: /* Unsupported key length (not WEP40/104/128) */ return (AH_FALSE); } for (i = 0; i < AR5K_ELEMENTS(key_v); i++) AR5K_REG_WRITE(AR5K_AR5210_KEYTABLE_OFF(entry, i), key_v[i]); return (ar5k_ar5210_set_key_lladdr(hal, entry, mac));}HAL_BOOLar5k_ar5210_set_key_lladdr(struct ath_hal *hal, u_int16_t entry, const u_int8_t *mac){ u_int32_t low_id, high_id; const u_int8_t *mac_v; /* * Invalid entry (key table overflow) */ AR5K_ASSERT_ENTRY(entry, AR5K_AR5210_KEYTABLE_SIZE); /* MAC may be NULL if it's a broadcast key */ mac_v = mac == NULL ? etherbroadcastaddr : mac; bcopy(mac_v, &low_id, 4); bcopy(mac_v + 4, &high_id, 2); high_id |= AR5K_AR5210_KEYTABLE_VALID; AR5K_REG_WRITE(AR5K_AR5210_KEYTABLE_MAC0(entry), low_id); AR5K_REG_WRITE(AR5K_AR5210_KEYTABLE_MAC1(entry), high_id); return (AH_TRUE);}/* * Power management functions */HAL_BOOLar5k_ar5210_set_power(struct ath_hal *hal, HAL_POWER_MODE mode, HAL_BOOL set_chip, u_int16_t sleep_duration){ u_int32_t staid; int i; staid = AR5K_REG_READ(AR5K_AR5210_STA_ID1); switch (mode) { case HAL_PM_AUTO: staid &= ~AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA; /* fallthrough */ case HAL_PM_NETWORK_SLEEP: if (set_chip == AH_TRUE) { AR5K_REG_WRITE(AR5K_AR5210_SCR, AR5K_AR5210_SCR_SLE | sleep_duration); } staid |= AR5K_AR5210_STA_ID1_PWR_SV; break; case HAL_PM_FULL_SLEEP: if (set_chip == AH_TRUE) { AR5K_REG_WRITE(AR5K_AR5210_SCR, AR5K_AR5210_SCR_SLE_SLP); } staid |= AR5K_AR5210_STA_ID1_PWR_SV; break; case HAL_PM_AWAKE: if (set_chip == AH_FALSE) goto commit; AR5K_REG_WRITE(AR5K_AR5210_SCR, AR5K_AR5210_SCR_SLE_WAKE); for (i = 5000; i > 0; i--) { /* Check if the AR5210 did wake up */ if ((AR5K_REG_READ(AR5K_AR5210_PCICFG) & AR5K_AR5210_PCICFG_SPWR_DN) == 0) break; /* Wait a bit and retry */ AR5K_DELAY(200); AR5K_REG_WRITE(AR5K_AR5210_SCR, AR5K_AR5210_SCR_SLE_WAKE); } /* Fail if the AR5210 didn't wake up */ if (i <= 0) return (AH_FALSE); staid &= ~AR5K_AR5210_STA_ID1_PWR_SV; break; default: return (AH_FALSE); } commit: hal->ah_power_mode = mode; AR5K_REG_WRITE(AR5K_AR5210_STA_ID1, staid); return (AH_TRUE);}HAL_POWER_MODEar5k_ar5210_get_power_mode(struct ath_hal *hal){ return (hal->ah_power_mode);}HAL_BOOLar5k_ar5210_query_pspoll_support(struct ath_hal *hal){ /* I think so, why not? */ return (AH_TRUE);}HAL_BOOLar5k_ar5210_init_pspoll(struct ath_hal *hal){ /* * Not used on the AR5210 */ return (AH_FALSE);}HAL_BOOLar5k_ar5210_enable_pspoll(struct ath_hal *hal, u_int8_t *bssid, u_int16_t assoc_id){ AR5K_REG_DISABLE_BITS(AR5K_AR5210_STA_ID1, AR5K_AR5210_STA_ID1_NO_PSPOLL | AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA); return (AH_TRUE);}HAL_BOOLar5k_ar5210_disable_pspoll(struct ath_hal *hal){ AR5K_REG_ENABLE_BITS(AR5K_AR5210_STA_ID1, AR5K_AR5210_STA_ID1_NO_PSPOLL | AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA); return (AH_TRUE);}HAL_BOOL /*Unimplemented*/ar5k_ar5210_set_txpower_limit(struct ath_hal *hal, u_int32_t power){ AR5K_TRACE; return (AH_FALSE);}/* * Beacon functions */voidar5k_ar5210_init_beacon(struct ath_hal *hal, u_int32_t next_beacon, u_int32_t interval){ u_int32_t timer1, timer2, timer3; /* * Set the additional timers by mode */ switch (hal->ah_op_mode) { case HAL_M_STA: timer1 = 0xffffffff; timer2 = 0xffffffff; timer3 = 1; break; default: timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; timer3 = next_beacon + hal->ah_atim_window; break; } /* * Enable all timers and set the beacon register * (next beacon, DMA beacon, software beacon, ATIM window time) */ AR5K_REG_WRITE(AR5K_AR5210_TIMER0, next_beacon); AR5K_REG_WRITE(AR5K_AR5210_TIMER1, timer1); AR5K_REG_WRITE(AR5K_AR5210_TIMER2, timer2); AR5K_REG_WRITE(AR5K_AR5210_TIMER3, timer3); AR5K_REG_WRITE(AR5K_AR5210_BEACON, interval & (AR5K_AR5210_BEACON_PERIOD | AR5K_AR5210_BEACON_RESET_TSF | AR5K_AR5210_BEACON_EN));}void /*Removed arguments - should be changed through *state - review HAL_BEACON_STATE struct*/ar5k_ar5210_set_beacon_timers(struct ath_hal *hal, const HAL_BEACON_STATE *state){ u_int32_t cfp_period, next_cfp; u_int32_t dtim_count = 0; /* XXX */ u_int32_t cfp_count = 0; /* XXX */ u_int32_t tsf = 0; /* XXX */ /* Return on an invalid beacon state */ if (state->bs_interval < 1) return; /* * PCF support? */ if (state->bs_cfp_period > 0) { /* Enable CFP mode and set the CFP and timer registers */ cfp_period = state->bs_cfp_period * state->bs_dtim_period * state->bs_interval; next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * state->bs_interval; AR5K_REG_DISABLE_BITS(AR5K_AR5210_STA_ID1, AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA | AR5K_AR5210_STA_ID1_PCF); AR5K_REG_WRITE(AR5K_AR5210_CFP_PERIOD, cfp_period); AR5K_REG_WRITE(AR5K_AR5210_CFP_DUR, state->bs_cfp_max_duration); AR5K_REG_WRITE(AR5K_AR5210_TIMER2, (tsf + (next_cfp == 0 ? cfp_period : next_cfp)) << 3); } else { /* Disable PCF mode */ AR5K_REG_DISABLE_BITS(AR5K_AR5210_STA_ID1, AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA | AR5K_AR5210_STA_ID1_PCF); } /* * Enable the beacon timer register */ AR5K_REG_WRITE(AR5K_AR5210_TIMER0, state->bs_next_beacon); /* * Start the beacon timers */ AR5K_REG_WRITE(AR5K_AR5210_BEACON, (AR5K_REG_READ(AR5K_AR5210_BEACON) &~ (AR5K_AR5210_BEACON_PERIOD | AR5K_AR5210_BEACON_TIM)) | AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, AR5K_AR5210_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, AR5K_AR5210_BEACON_PERIOD)); /* * Write new beacon miss threshold, if it appears to be valid */ if (state->bs_bmiss_threshold <= (AR5K_AR5210_RSSI_THR_BM_THR >> AR5K_AR5210_RSSI_THR_BM_THR_S)) { AR5K_REG_WRITE_BITS(AR5K_AR5210_RSSI_THR, AR5K_AR5210_RSSI_THR_BM_THR, state->bs_bmiss_threshold); }}voidar5k_ar5210_reset_beacon(struct ath_hal *hal){ /* * Disable beacon timer */ AR5K_REG_WRITE(AR5K_AR5210_TIMER0, 0); /* * Disable some beacon register values */ AR5K_REG_DISABLE_BITS(AR5K_AR5210_STA_ID1, AR5K_AR5210_STA_ID1_DEFAULT_ANTENNA | AR5K_AR5210_STA_ID1_PCF); AR5K_REG_WRITE(AR5K_AR5210_BEACON, AR5K_AR5210_BEACON_PERIOD);}HAL_BOOLar5k_ar5210_wait_for_beacon(struct ath_hal *hal, HAL_BUS_ADDR phys_addr){ int i; /* * Wait for beaconn queue to be done */ for (i = (AR5K_TUNE_BEACON_INTERVAL / 2); i > 0 && (AR5K_REG_READ(AR5K_AR5210_BSR) & AR5K_AR5210_BSR_TXQ1F) != 0 && (AR5K_REG_READ(AR5K_AR5210_CR) & AR5K_AR5210_CR_TXE1) != 0; i--); /* Timeout... */ if (i <= 0) { /* * Re-schedule the beacon queue */ AR5K_REG_WRITE(AR5K_AR5210_TXDP1, (u_int32_t)phys_addr); AR5K_REG_WRITE(AR5K_AR5210_BCR, AR5K_AR5210_BCR_TQ1V | AR5K_AR5210_BCR_BDMAE); return (AH_FALSE); } return (AH_TRUE);}/* * Interrupt handling */HAL_BOOLar5k_ar5210_is_intr_pending(struct ath_hal *hal){ return (AR5K_REG_READ(AR5K_AR5210_INTPEND) == 0 ? AH_FALSE : AH_TRUE);}HAL_BOOLar5k_ar5210_get_isr(struct ath_hal *hal, u_int32_t *interrupt_mask){ u_int32_t data; if ((data = AR5K_REG_READ(AR5K_AR5210_ISR)) == HAL_INT_NOCARD) { *interrupt_mask = data; return (AH_FALSE); } /* * Get abstract interrupt mask (HAL-compatible) */ *interrupt_mask = (data & HAL_INT_COMMON) & hal->ah_imr; if (data & (AR5K_AR5210_ISR_RXOK | AR5K_AR5210_ISR_RXERR)) *interrupt_mask |= HAL_INT_RX; if (data & (AR5K_AR5210_ISR_TXOK | AR5K_AR5210_ISR_TXERR)) *interrupt_mask |= HAL_INT_TX; if (data & AR5K_AR5210_ISR_FATAL) *interrupt_mask |= HAL_INT_FATAL; /* * Special interrupt handling (not caught by the driver) */ if (((*interrupt_mask) & AR5K_AR5210_ISR_RXPHY) && hal->ah_radar.r_enabled == AH_TRUE) ar5k_radar_alert(hal); /* XXX BMISS interrupts may occur after association */ *interrupt_mask &= ~HAL_INT_BMISS; return (AH_TRUE);}u_int32_tar5k_ar5210_get_intr(struct ath_hal *hal){ /* Return the interrupt mask stored previously */ return (hal->ah_imr);}HAL_INTar5k_ar5210_set_intr(struct ath_hal *hal, HAL_INT new_mask){ HAL_INT old_mask, int_mask; /* * Disable card interrupts to prevent any race conditions * (they will be re-enabled afterwards). */ AR5K_REG_WRITE(AR5K_AR5210_IER, AR5K_AR5210_IER_DISABLE); old_mask = hal->ah_imr; /* * Add additional, chipset-dependent interrupt mask flags * and write them to the IMR (interrupt mask register). */ int_mask = new_mask & HAL_INT_COMMON; if (new_mask & HAL_INT_RX) int_mask |= AR5K_AR5210_IMR_RXOK | AR5K_AR5210_IMR_RXERR | AR5K_AR5210_IMR_RXORN; if (new_mask & HAL_INT_TX) int_mask |= AR5K_AR5210_IMR_TXOK | AR5K_AR5210_IMR_TXERR | AR5K_AR5210_IMR_TXURN; AR5K_REG_WRITE(AR5K_AR5210_IMR, int_mask); /* Store new interrupt mask */ hal->ah_imr = new_mask; /* ..re-enable interrupts */ if (int_mask) { AR5K_REG_WRITE(AR5K_AR5210_IER, AR5K_AR5210_IER_ENABLE); } return (old_mask);}/* * Misc internal functions */HAL_BOOLar5k_ar5210_get_capabilities(struct ath_hal *hal){ /* Set number of supported TX queues */ hal->ah_capabilities.cap_queues.q_tx_num = AR5K_AR5210_TX_NUM_QUEUES; /* * Set radio capabilities * (The AR5210 only supports the middle 5GHz band) */ hal->ah_capabilities.cap_range.range_5ghz_min = 5120; hal->ah_capabilities.cap_range.range_5ghz_max = 5430; hal->ah_capabilities.cap_range.range_2ghz_min = 0; hal->ah_capabilities.cap_range.range_2ghz_max = 0; /* Set supported modes */ hal->ah_capabilities.cap_mode = HAL_MODE_11A | HAL_MODE_TURBO; /* Set number of GPIO pins */ hal->ah_gpio_npins = AR5K_AR5210_NUM_GPIO; return (AH_TRUE);}voidar5k_ar5210_radar_alert(struct ath_hal *hal, HAL_BOOL enable){ /* * Set the RXPHY interrupt to be able to detect * possible radar activity. */ AR5K_REG_WRITE(AR5K_AR5210_IER, AR5K_AR5210_IER_DISABLE); if (enable == AH_TRUE) { AR5K_REG_ENABLE_BITS(AR5K_AR5210_IMR, AR5K_AR5210_IMR_RXPHY); } else { AR5K_REG_DISABLE_BITS(AR5K_AR5210_IMR, AR5K_AR5210_IMR_RXPHY); } AR5K_REG_WRITE(AR5K_AR5210_IER, AR5K_AR5210_IER_ENABLE);}/* * EEPROM access functions */HAL_BOOLar5k_ar5210_eeprom_is_busy(struct ath_hal *hal){ return (AR5K_REG_READ(AR5K_AR5210_CFG) & AR5K_AR5210_CFG_EEBS ? AH_TRUE : AH_FALSE);}intar5k_ar5210_eeprom_read(struct ath_hal *hal, u_int32_t offset, u_int16_t *data){ u_int32_t status, timeout; /* Enable eeprom access */ AR5K_REG_ENABLE_BITS(AR5K_AR5210_PCICFG, AR5K_AR5210_PCICFG_EEAE); /* * Prime read pump */ (void)AR5K_REG_READ(AR5K_AR5210_EEPROM_BASE + (4 * offset)); for (timeout = 10000; timeout > 0; timeout--) { AR5K_DELAY(1); status = AR5K_REG_READ(AR5K_AR5210_EEPROM_STATUS); if (status & AR5K_AR5210_EEPROM_STAT_RDDONE) { if (status & AR5K_AR5210_EEPROM_STAT_RDERR) return (EIO); *data = (u_int16_t) (AR5K_REG_READ(AR5K_AR5210_EEPROM_RDATA) & 0xffff); return (0); } } return (ETIMEDOUT);}intar5k_ar5210_eeprom_write(struct ath_hal *hal, u_int32_t offset, u_int16_t data){ u_int32_t status, timeout; /* Enable eeprom access */ AR5K_REG_ENABLE_BITS(AR5K_AR5210_PCICFG, AR5K_AR5210_PCICFG_EEAE); /* * Prime write pump */ AR5K_REG_WRITE(AR5K_AR5210_EEPROM_BASE + (4 * offset), data); for (timeout = 10000; timeout > 0; timeout--) { AR5K_DELAY(1); status = AR5K_REG_READ(AR5K_AR5210_EEPROM_STATUS); if (status & AR5K_AR5210_EEPROM_STAT_WRDONE) { if (status & AR5K_AR5210_EEPROM_STAT_WRERR) return (EIO); return (0); } } return (ETIMEDOUT);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -