alistair23-linux/drivers/staging/vt6656/card.c
Elise Lennion ce439c425b staging: vt6656: Compress return logic into one line.
Compress the return logic into one line avoids unnecessary variable
declarations. In this case it also makes it easier to understand the
function.

Coccinelle was used to find this return statement. However, additional
compressions were done to make the function clearer.

Semantic patch:
@@
local idexpression ret;
expression e;
@@

-ret =
+return
     e;
-return ret;

Signed-off-by: Elise Lennion <elise.lennion@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-10-17 10:27:55 +02:00

805 lines
17 KiB
C

/*
* Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* File: card.c
* Purpose: Provide functions to setup NIC operation mode
* Functions:
* vnt_set_rspinf - Set RSPINF
* vnt_update_ifs - Update slotTime,SIFS,DIFS, and EIFS
* vnt_update_top_rates - Update BasicTopRate
* vnt_add_basic_rate - Add to BasicRateSet
* vnt_ofdm_min_rate - Check if any OFDM rate is in BasicRateSet
* vnt_get_tsf_offset - Calculate TSFOffset
* vnt_get_current_tsf - Read Current NIC TSF counter
* vnt_get_next_tbtt - Calculate Next Beacon TSF counter
* vnt_reset_next_tbtt - Set NIC Beacon time
* vnt_update_next_tbtt - Sync. NIC Beacon time
* vnt_radio_power_off - Turn Off NIC Radio Power
* vnt_radio_power_on - Turn On NIC Radio Power
*
* Revision History:
* 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec.
* 08-26-2003 Kyle Hsu: Modify the definition type of dwIoBase.
* 09-01-2003 Bryan YC Fan: Add vnt_update_ifs().
*
*/
#include "device.h"
#include "card.h"
#include "baseband.h"
#include "mac.h"
#include "desc.h"
#include "rf.h"
#include "power.h"
#include "key.h"
#include "usbpipe.h"
/* const u16 cw_rxbcntsf_off[MAX_RATE] =
* {17, 34, 96, 192, 34, 23, 17, 11, 8, 5, 4, 3};
*/
static const u16 cw_rxbcntsf_off[MAX_RATE] = {
192, 96, 34, 17, 34, 23, 17, 11, 8, 5, 4, 3
};
/*
* Description: Set NIC media channel
*
* Parameters:
* In:
* pDevice - The adapter to be set
* connection_channel - Channel to be set
* Out:
* none
*/
void vnt_set_channel(struct vnt_private *priv, u32 connection_channel)
{
if (connection_channel > CB_MAX_CHANNEL || !connection_channel)
return;
/* clear NAV */
vnt_mac_reg_bits_on(priv, MAC_REG_MACCR, MACCR_CLRNAV);
/* Set Channel[7] = 0 to tell H/W channel is changing now. */
vnt_mac_reg_bits_off(priv, MAC_REG_CHANNEL, 0xb0);
vnt_control_out(priv, MESSAGE_TYPE_SELECT_CHANNEL,
connection_channel, 0, 0, NULL);
vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, MAC_REG_CHANNEL,
(u8)(connection_channel | 0x80));
}
/*
* Description: Get CCK mode basic rate
*
* Parameters:
* In:
* priv - The adapter to be set
* rate_idx - Receiving data rate
* Out:
* none
*
* Return Value: response Control frame rate
*
*/
static u16 vnt_get_cck_rate(struct vnt_private *priv, u16 rate_idx)
{
u16 ui = rate_idx;
while (ui > RATE_1M) {
if (priv->basic_rates & (1 << ui))
return ui;
ui--;
}
return RATE_1M;
}
/*
* Description: Get OFDM mode basic rate
*
* Parameters:
* In:
* priv - The adapter to be set
* rate_idx - Receiving data rate
* Out:
* none
*
* Return Value: response Control frame rate
*
*/
static u16 vnt_get_ofdm_rate(struct vnt_private *priv, u16 rate_idx)
{
u16 ui = rate_idx;
dev_dbg(&priv->usb->dev, "%s basic rate: %d\n",
__func__, priv->basic_rates);
if (!vnt_ofdm_min_rate(priv)) {
dev_dbg(&priv->usb->dev, "%s (NO OFDM) %d\n",
__func__, rate_idx);
if (rate_idx > RATE_24M)
rate_idx = RATE_24M;
return rate_idx;
}
while (ui > RATE_11M) {
if (priv->basic_rates & (1 << ui)) {
dev_dbg(&priv->usb->dev, "%s rate: %d\n",
__func__, ui);
return ui;
}
ui--;
}
dev_dbg(&priv->usb->dev, "%s basic rate: 24M\n", __func__);
return RATE_24M;
}
/*
* Description: Calculate TxRate and RsvTime fields for RSPINF in OFDM mode.
*
* Parameters:
* In:
* rate - Tx Rate
* bb_type - Tx Packet type
* Out:
* tx_rate - pointer to RSPINF TxRate field
* rsv_time- pointer to RSPINF RsvTime field
*
* Return Value: none
*
*/
static void vnt_calculate_ofdm_rate(u16 rate, u8 bb_type,
u8 *tx_rate, u8 *rsv_time)
{
switch (rate) {
case RATE_6M:
if (bb_type == BB_TYPE_11A) {
*tx_rate = 0x9b;
*rsv_time = 24;
} else {
*tx_rate = 0x8b;
*rsv_time = 30;
}
break;
case RATE_9M:
if (bb_type == BB_TYPE_11A) {
*tx_rate = 0x9f;
*rsv_time = 16;
} else {
*tx_rate = 0x8f;
*rsv_time = 22;
}
break;
case RATE_12M:
if (bb_type == BB_TYPE_11A) {
*tx_rate = 0x9a;
*rsv_time = 12;
} else {
*tx_rate = 0x8a;
*rsv_time = 18;
}
break;
case RATE_18M:
if (bb_type == BB_TYPE_11A) {
*tx_rate = 0x9e;
*rsv_time = 8;
} else {
*tx_rate = 0x8e;
*rsv_time = 14;
}
break;
case RATE_36M:
if (bb_type == BB_TYPE_11A) {
*tx_rate = 0x9d;
*rsv_time = 4;
} else {
*tx_rate = 0x8d;
*rsv_time = 10;
}
break;
case RATE_48M:
if (bb_type == BB_TYPE_11A) {
*tx_rate = 0x98;
*rsv_time = 4;
} else {
*tx_rate = 0x88;
*rsv_time = 10;
}
break;
case RATE_54M:
if (bb_type == BB_TYPE_11A) {
*tx_rate = 0x9c;
*rsv_time = 4;
} else {
*tx_rate = 0x8c;
*rsv_time = 10;
}
break;
case RATE_24M:
default:
if (bb_type == BB_TYPE_11A) {
*tx_rate = 0x99;
*rsv_time = 8;
} else {
*tx_rate = 0x89;
*rsv_time = 14;
}
break;
}
}
/*
* Description: Set RSPINF
*
* Parameters:
* In:
* pDevice - The adapter to be set
* Out:
* none
*
* Return Value: None.
*
*/
void vnt_set_rspinf(struct vnt_private *priv, u8 bb_type)
{
struct vnt_phy_field phy[4];
u8 tx_rate[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; /* For OFDM */
u8 rsv_time[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
u8 data[34];
int i;
/*RSPINF_b_1*/
vnt_get_phy_field(priv, 14, vnt_get_cck_rate(priv, RATE_1M),
PK_TYPE_11B, &phy[0]);
/*RSPINF_b_2*/
vnt_get_phy_field(priv, 14, vnt_get_cck_rate(priv, RATE_2M),
PK_TYPE_11B, &phy[1]);
/*RSPINF_b_5*/
vnt_get_phy_field(priv, 14, vnt_get_cck_rate(priv, RATE_5M),
PK_TYPE_11B, &phy[2]);
/*RSPINF_b_11*/
vnt_get_phy_field(priv, 14, vnt_get_cck_rate(priv, RATE_11M),
PK_TYPE_11B, &phy[3]);
/*RSPINF_a_6*/
vnt_calculate_ofdm_rate(RATE_6M, bb_type, &tx_rate[0], &rsv_time[0]);
/*RSPINF_a_9*/
vnt_calculate_ofdm_rate(RATE_9M, bb_type, &tx_rate[1], &rsv_time[1]);
/*RSPINF_a_12*/
vnt_calculate_ofdm_rate(RATE_12M, bb_type, &tx_rate[2], &rsv_time[2]);
/*RSPINF_a_18*/
vnt_calculate_ofdm_rate(RATE_18M, bb_type, &tx_rate[3], &rsv_time[3]);
/*RSPINF_a_24*/
vnt_calculate_ofdm_rate(RATE_24M, bb_type, &tx_rate[4], &rsv_time[4]);
/*RSPINF_a_36*/
vnt_calculate_ofdm_rate(vnt_get_ofdm_rate(priv, RATE_36M),
bb_type, &tx_rate[5], &rsv_time[5]);
/*RSPINF_a_48*/
vnt_calculate_ofdm_rate(vnt_get_ofdm_rate(priv, RATE_48M),
bb_type, &tx_rate[6], &rsv_time[6]);
/*RSPINF_a_54*/
vnt_calculate_ofdm_rate(vnt_get_ofdm_rate(priv, RATE_54M),
bb_type, &tx_rate[7], &rsv_time[7]);
/*RSPINF_a_72*/
vnt_calculate_ofdm_rate(vnt_get_ofdm_rate(priv, RATE_54M),
bb_type, &tx_rate[8], &rsv_time[8]);
put_unaligned(phy[0].len, (u16 *)&data[0]);
data[2] = phy[0].signal;
data[3] = phy[0].service;
put_unaligned(phy[1].len, (u16 *)&data[4]);
data[6] = phy[1].signal;
data[7] = phy[1].service;
put_unaligned(phy[2].len, (u16 *)&data[8]);
data[10] = phy[2].signal;
data[11] = phy[2].service;
put_unaligned(phy[3].len, (u16 *)&data[12]);
data[14] = phy[3].signal;
data[15] = phy[3].service;
for (i = 0; i < 9; i++) {
data[16 + i * 2] = tx_rate[i];
data[16 + i * 2 + 1] = rsv_time[i];
}
vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_RSPINF_B_1,
MESSAGE_REQUEST_MACREG, 34, &data[0]);
}
/*
* Description: Update IFS
*
* Parameters:
* In:
* priv - The adapter to be set
* Out:
* none
*
* Return Value: None.
*
*/
void vnt_update_ifs(struct vnt_private *priv)
{
u8 max_min = 0;
u8 data[4];
if (priv->packet_type == PK_TYPE_11A) {
priv->slot = C_SLOT_SHORT;
priv->sifs = C_SIFS_A;
priv->difs = C_SIFS_A + 2 * C_SLOT_SHORT;
max_min = 4;
} else if (priv->packet_type == PK_TYPE_11B) {
priv->slot = C_SLOT_LONG;
priv->sifs = C_SIFS_BG;
priv->difs = C_SIFS_BG + 2 * C_SLOT_LONG;
max_min = 5;
} else {/* PK_TYPE_11GA & PK_TYPE_11GB */
bool ofdm_rate = false;
unsigned int ii = 0;
priv->sifs = C_SIFS_BG;
if (priv->short_slot_time)
priv->slot = C_SLOT_SHORT;
else
priv->slot = C_SLOT_LONG;
priv->difs = C_SIFS_BG + 2 * priv->slot;
for (ii = RATE_54M; ii >= RATE_6M; ii--) {
if (priv->basic_rates & ((u32)(0x1 << ii))) {
ofdm_rate = true;
break;
}
}
if (ofdm_rate)
max_min = 4;
else
max_min = 5;
}
priv->eifs = C_EIFS;
switch (priv->rf_type) {
case RF_VT3226D0:
if (priv->bb_type != BB_TYPE_11B) {
priv->sifs -= 1;
priv->difs -= 1;
break;
}
case RF_AIROHA7230:
case RF_AL2230:
case RF_AL2230S:
if (priv->bb_type != BB_TYPE_11B)
break;
case RF_RFMD2959:
case RF_VT3226:
case RF_VT3342A0:
priv->sifs -= 3;
priv->difs -= 3;
break;
case RF_MAXIM2829:
if (priv->bb_type == BB_TYPE_11A) {
priv->sifs -= 5;
priv->difs -= 5;
} else {
priv->sifs -= 2;
priv->difs -= 2;
}
break;
}
data[0] = (u8)priv->sifs;
data[1] = (u8)priv->difs;
data[2] = (u8)priv->eifs;
data[3] = (u8)priv->slot;
vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_SIFS,
MESSAGE_REQUEST_MACREG, 4, &data[0]);
max_min |= 0xa0;
vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_CWMAXMIN0,
MESSAGE_REQUEST_MACREG, 1, &max_min);
}
void vnt_update_top_rates(struct vnt_private *priv)
{
u8 top_ofdm = RATE_24M, top_cck = RATE_1M;
u8 i;
/*Determines the highest basic rate.*/
for (i = RATE_54M; i >= RATE_6M; i--) {
if (priv->basic_rates & (u16)(1 << i)) {
top_ofdm = i;
break;
}
}
priv->top_ofdm_basic_rate = top_ofdm;
for (i = RATE_11M;; i--) {
if (priv->basic_rates & (u16)(1 << i)) {
top_cck = i;
break;
}
if (i == RATE_1M)
break;
}
priv->top_cck_basic_rate = top_cck;
}
int vnt_ofdm_min_rate(struct vnt_private *priv)
{
int ii;
for (ii = RATE_54M; ii >= RATE_6M; ii--) {
if ((priv->basic_rates) & ((u16)BIT(ii)))
return true;
}
return false;
}
u8 vnt_get_pkt_type(struct vnt_private *priv)
{
if (priv->bb_type == BB_TYPE_11A || priv->bb_type == BB_TYPE_11B)
return (u8)priv->bb_type;
else if (vnt_ofdm_min_rate(priv))
return PK_TYPE_11GA;
return PK_TYPE_11GB;
}
/*
* Description: Calculate TSF offset of two TSF input
* Get TSF Offset from RxBCN's TSF and local TSF
*
* Parameters:
* In:
* rx_rate - rx rate.
* tsf1 - Rx BCN's TSF
* tsf2 - Local TSF
* Out:
* none
*
* Return Value: TSF Offset value
*
*/
u64 vnt_get_tsf_offset(u8 rx_rate, u64 tsf1, u64 tsf2)
{
return tsf1 - tsf2 - (u64)cw_rxbcntsf_off[rx_rate % MAX_RATE];
}
/*
* Description: Sync. TSF counter to BSS
* Get TSF offset and write to HW
*
* Parameters:
* In:
* priv - The adapter to be sync.
* time_stamp - Rx BCN's TSF
* local_tsf - Local TSF
* Out:
* none
*
* Return Value: none
*
*/
void vnt_adjust_tsf(struct vnt_private *priv, u8 rx_rate,
u64 time_stamp, u64 local_tsf)
{
u64 tsf_offset = 0;
u8 data[8];
tsf_offset = vnt_get_tsf_offset(rx_rate, time_stamp, local_tsf);
data[0] = (u8)tsf_offset;
data[1] = (u8)(tsf_offset >> 8);
data[2] = (u8)(tsf_offset >> 16);
data[3] = (u8)(tsf_offset >> 24);
data[4] = (u8)(tsf_offset >> 32);
data[5] = (u8)(tsf_offset >> 40);
data[6] = (u8)(tsf_offset >> 48);
data[7] = (u8)(tsf_offset >> 56);
vnt_control_out(priv, MESSAGE_TYPE_SET_TSFTBTT,
MESSAGE_REQUEST_TSF, 0, 8, data);
}
/*
* Description: Read NIC TSF counter
* Get local TSF counter
*
* Parameters:
* In:
* priv - The adapter to be read
* Out:
* current_tsf - Current TSF counter
*
* Return Value: true if success; otherwise false
*
*/
bool vnt_get_current_tsf(struct vnt_private *priv, u64 *current_tsf)
{
*current_tsf = priv->current_tsf;
return true;
}
/*
* Description: Clear NIC TSF counter
* Clear local TSF counter
*
* Parameters:
* In:
* priv - The adapter to be read
*
* Return Value: true if success; otherwise false
*
*/
bool vnt_clear_current_tsf(struct vnt_private *priv)
{
vnt_mac_reg_bits_on(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTRST);
priv->current_tsf = 0;
return true;
}
/*
* Description: Read NIC TSF counter
* Get NEXTTBTT from adjusted TSF and Beacon Interval
*
* Parameters:
* In:
* tsf - Current TSF counter
* beacon_interval - Beacon Interval
* Out:
* tsf - Current TSF counter
*
* Return Value: TSF value of next Beacon
*
*/
u64 vnt_get_next_tbtt(u64 tsf, u16 beacon_interval)
{
u32 beacon_int;
beacon_int = beacon_interval * 1024;
/* Next TBTT =
* ((local_current_TSF / beacon_interval) + 1) * beacon_interval
*/
if (beacon_int) {
do_div(tsf, beacon_int);
tsf += 1;
tsf *= beacon_int;
}
return tsf;
}
/*
* Description: Set NIC TSF counter for first Beacon time
* Get NEXTTBTT from adjusted TSF and Beacon Interval
*
* Parameters:
* In:
* dwIoBase - IO Base
* beacon_interval - Beacon Interval
* Out:
* none
*
* Return Value: none
*
*/
void vnt_reset_next_tbtt(struct vnt_private *priv, u16 beacon_interval)
{
u64 next_tbtt = 0;
u8 data[8];
vnt_clear_current_tsf(priv);
next_tbtt = vnt_get_next_tbtt(next_tbtt, beacon_interval);
data[0] = (u8)next_tbtt;
data[1] = (u8)(next_tbtt >> 8);
data[2] = (u8)(next_tbtt >> 16);
data[3] = (u8)(next_tbtt >> 24);
data[4] = (u8)(next_tbtt >> 32);
data[5] = (u8)(next_tbtt >> 40);
data[6] = (u8)(next_tbtt >> 48);
data[7] = (u8)(next_tbtt >> 56);
vnt_control_out(priv, MESSAGE_TYPE_SET_TSFTBTT,
MESSAGE_REQUEST_TBTT, 0, 8, data);
}
/*
* Description: Sync NIC TSF counter for Beacon time
* Get NEXTTBTT and write to HW
*
* Parameters:
* In:
* priv - The adapter to be set
* tsf - Current TSF counter
* beacon_interval - Beacon Interval
* Out:
* none
*
* Return Value: none
*
*/
void vnt_update_next_tbtt(struct vnt_private *priv, u64 tsf,
u16 beacon_interval)
{
u8 data[8];
tsf = vnt_get_next_tbtt(tsf, beacon_interval);
data[0] = (u8)tsf;
data[1] = (u8)(tsf >> 8);
data[2] = (u8)(tsf >> 16);
data[3] = (u8)(tsf >> 24);
data[4] = (u8)(tsf >> 32);
data[5] = (u8)(tsf >> 40);
data[6] = (u8)(tsf >> 48);
data[7] = (u8)(tsf >> 56);
vnt_control_out(priv, MESSAGE_TYPE_SET_TSFTBTT,
MESSAGE_REQUEST_TBTT, 0, 8, data);
dev_dbg(&priv->usb->dev, "%s TBTT: %8llx\n", __func__, tsf);
}
/*
* Description: Turn off Radio power
*
* Parameters:
* In:
* priv - The adapter to be turned off
* Out:
* none
*
* Return Value: true if success; otherwise false
*
*/
int vnt_radio_power_off(struct vnt_private *priv)
{
int ret = true;
switch (priv->rf_type) {
case RF_AL2230:
case RF_AL2230S:
case RF_AIROHA7230:
case RF_VT3226:
case RF_VT3226D0:
case RF_VT3342A0:
vnt_mac_reg_bits_off(priv, MAC_REG_SOFTPWRCTL,
(SOFTPWRCTL_SWPE2 | SOFTPWRCTL_SWPE3));
break;
}
vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_RXON);
vnt_set_deep_sleep(priv);
vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1, GPIO3_INTMD);
return ret;
}
/*
* Description: Turn on Radio power
*
* Parameters:
* In:
* priv - The adapter to be turned on
* Out:
* none
*
* Return Value: true if success; otherwise false
*
*/
int vnt_radio_power_on(struct vnt_private *priv)
{
int ret = true;
vnt_exit_deep_sleep(priv);
vnt_mac_reg_bits_on(priv, MAC_REG_HOSTCR, HOSTCR_RXON);
switch (priv->rf_type) {
case RF_AL2230:
case RF_AL2230S:
case RF_AIROHA7230:
case RF_VT3226:
case RF_VT3226D0:
case RF_VT3342A0:
vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL,
(SOFTPWRCTL_SWPE2 | SOFTPWRCTL_SWPE3));
break;
}
vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1, GPIO3_INTMD);
return ret;
}
void vnt_set_bss_mode(struct vnt_private *priv)
{
if (priv->rf_type == RF_AIROHA7230 && priv->bb_type == BB_TYPE_11A)
vnt_mac_set_bb_type(priv, BB_TYPE_11G);
else
vnt_mac_set_bb_type(priv, priv->bb_type);
priv->packet_type = vnt_get_pkt_type(priv);
if (priv->bb_type == BB_TYPE_11A)
vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x88, 0x03);
else if (priv->bb_type == BB_TYPE_11B)
vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x88, 0x02);
else if (priv->bb_type == BB_TYPE_11G)
vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x88, 0x08);
vnt_update_ifs(priv);
vnt_set_rspinf(priv, (u8)priv->bb_type);
if (priv->bb_type == BB_TYPE_11A) {
if (priv->rf_type == RF_AIROHA7230) {
priv->bb_vga[0] = 0x20;
vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG,
0xe7, priv->bb_vga[0]);
}
priv->bb_vga[2] = 0x10;
priv->bb_vga[3] = 0x10;
} else {
if (priv->rf_type == RF_AIROHA7230) {
priv->bb_vga[0] = 0x1c;
vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG,
0xe7, priv->bb_vga[0]);
}
priv->bb_vga[2] = 0x0;
priv->bb_vga[3] = 0x0;
}
vnt_set_vga_gain_offset(priv, priv->bb_vga[0]);
}