diff options
author | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 12:17:53 -0700 |
---|---|---|
committer | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 15:44:42 -0700 |
commit | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (patch) | |
tree | 1c9cafbcd35f783a87880a10f85d1a060db1a563 /kernel/drivers/staging/vt6656 | |
parent | 98260f3884f4a202f9ca5eabed40b1354c489b29 (diff) |
Add the rt linux 4.1.3-rt3 as base
Import the rt linux 4.1.3-rt3 as OPNFV kvm base.
It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and
the base is:
commit 0917f823c59692d751951bf5ea699a2d1e2f26a2
Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Date: Sat Jul 25 12:13:34 2015 +0200
Prepare v4.1.3-rt3
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
We lose all the git history this way and it's not good. We
should apply another opnfv project repo in future.
Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Diffstat (limited to 'kernel/drivers/staging/vt6656')
32 files changed, 8322 insertions, 0 deletions
diff --git a/kernel/drivers/staging/vt6656/Kconfig b/kernel/drivers/staging/vt6656/Kconfig new file mode 100644 index 000000000..b602ef175 --- /dev/null +++ b/kernel/drivers/staging/vt6656/Kconfig @@ -0,0 +1,7 @@ +config VT6656 + tristate "VIA Technologies VT6656 support" + depends on MAC80211 && USB && WLAN && m + select FW_LOADER + ---help--- + This is a vendor-written driver for VIA VT6656. + diff --git a/kernel/drivers/staging/vt6656/Makefile b/kernel/drivers/staging/vt6656/Makefile new file mode 100644 index 000000000..3dbe1f89d --- /dev/null +++ b/kernel/drivers/staging/vt6656/Makefile @@ -0,0 +1,20 @@ +# TODO: all of these should be removed +ccflags-y := -DLINUX -D__KERNEL__ -DEXPORT_SYMTAB -D__NO_VERSION__ +ccflags-y += -DHOSTAP + +vt6656_stage-y += main_usb.o \ + card.o \ + mac.o \ + baseband.o \ + wcmd.o\ + rxtx.o \ + dpc.o \ + power.o \ + key.o \ + rf.o \ + usbpipe.o \ + channel.o \ + firmware.o \ + int.o + +obj-$(CONFIG_VT6656) += vt6656_stage.o diff --git a/kernel/drivers/staging/vt6656/TODO b/kernel/drivers/staging/vt6656/TODO new file mode 100644 index 000000000..e154b2f3b --- /dev/null +++ b/kernel/drivers/staging/vt6656/TODO @@ -0,0 +1,19 @@ +TODO: +- remove __cplusplus ifdefs -- done +- remove kernel version compatibility wrappers +- remove support for older wireless extensions +- prepare for merge with vt6655 driver: + - remove PRINT_K() macro + - split rf.c + - abstract VT3184 chipset specific code +- add common vt665x infrastructure +- kill ttype.h -- done +- switch to use LIB80211 +- switch to use MAC80211 +- use kernel coding style +- checkpatch.pl fixes +- sparse fixes +- integrate with drivers/net/wireless + +Please send any patches to Greg Kroah-Hartman <greg@kroah.com> +and Forest Bond <forest@alittletooquiet.net>. diff --git a/kernel/drivers/staging/vt6656/baseband.c b/kernel/drivers/staging/vt6656/baseband.c new file mode 100644 index 000000000..26b16772f --- /dev/null +++ b/kernel/drivers/staging/vt6656/baseband.c @@ -0,0 +1,831 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: baseband.c + * + * Purpose: Implement functions to access baseband + * + * Author: Jerry Chen + * + * Date: Jun. 5, 2002 + * + * Functions: + * vnt_get_frame_time - Calculate data frame transmitting time + * vnt_get_phy_field - Calculate PhyLength, PhyService and Phy + * Signal parameter for baseband Tx + * vnt_vt3184_init - VIA VT3184 baseband chip init code + * + * Revision History: + * + * + */ + +#include "mac.h" +#include "baseband.h" +#include "rf.h" +#include "usbpipe.h" + +static u8 vnt_vt3184_agc[] = { + 0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x06, 0x06, + 0x08, 0x08, 0x0a, 0x0a, 0x0c, 0x0c, 0x0e, 0x0e, /* 0x0f */ + 0x10, 0x10, 0x12, 0x12, 0x14, 0x14, 0x16, 0x16, + 0x18, 0x18, 0x1a, 0x1a, 0x1c, 0x1c, 0x1e, 0x1e, /* 0x1f */ + 0x20, 0x20, 0x22, 0x22, 0x24, 0x24, 0x26, 0x26, + 0x28, 0x28, 0x2a, 0x2a, 0x2c, 0x2c, 0x2e, 0x2e, /* 0x2f */ + 0x30, 0x30, 0x32, 0x32, 0x34, 0x34, 0x36, 0x36, + 0x38, 0x38, 0x3a, 0x3a, 0x3c, 0x3c, 0x3e, 0x3e /* 0x3f */ +}; + +static u8 vnt_vt3184_al2230[] = { + 0x31, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x70, 0x45, 0x2a, 0x76, 0x00, 0x00, 0x80, 0x00, /* 0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8e, 0x0a, 0x00, 0x00, 0x00, /* 0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x0c, /* 0x2f */ + 0x26, 0x5b, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, + 0xff, 0xff, 0x79, 0x00, 0x00, 0x0b, 0x48, 0x04, /* 0x3f */ + 0x00, 0x08, 0x00, 0x08, 0x08, 0x14, 0x05, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x73, 0x00, 0xc5, /* 0x4f */ + 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5f */ + 0xe4, 0x80, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* 0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7f */ + 0x8c, 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x1f, 0xb7, 0x88, 0x47, 0xaa, 0x00, /* 0x8f */ + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x18, /* 0xaf */ + 0x38, 0x30, 0x00, 0x00, 0xff, 0x0f, 0xe4, 0xe2, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, /* 0xbf */ + 0x18, 0x20, 0x07, 0x18, 0xff, 0xff, 0x0e, 0x0a, + 0x0e, 0x00, 0x82, 0xa7, 0x3c, 0x10, 0x30, 0x05, /* 0xcf */ + 0x40, 0x12, 0x00, 0x00, 0x10, 0x28, 0x80, 0x2a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xdf */ + 0x00, 0xf3, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, + 0x00, 0xf4, 0x00, 0xff, 0x79, 0x20, 0x30, 0x05, /* 0xef */ + 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xff */ +}; + +/* {{RobertYu:20060515, new BB setting for VT3226D0 */ +static u8 vnt_vt3184_vt3226d0[] = { + 0x31, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x70, 0x45, 0x2a, 0x76, 0x00, 0x00, 0x80, 0x00, /* 0x0f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8e, 0x0a, 0x00, 0x00, 0x00, /* 0x1f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x0c, /* 0x2f */ + 0x26, 0x5b, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, + 0xff, 0xff, 0x79, 0x00, 0x00, 0x0b, 0x48, 0x04, /* 0x3f */ + 0x00, 0x08, 0x00, 0x08, 0x08, 0x14, 0x05, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x73, 0x00, 0xc5, /* 0x4f */ + 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5f */ + 0xe4, 0x80, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* 0x6f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7f */ + 0x8c, 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x1f, 0xb7, 0x88, 0x47, 0xaa, 0x00, /* 0x8f */ + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, /* 0xaf */ + 0x38, 0x30, 0x00, 0x00, 0xff, 0x0f, 0xe4, 0xe2, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, /* 0xbf */ + 0x18, 0x20, 0x07, 0x18, 0xff, 0xff, 0x10, 0x0a, + 0x0e, 0x00, 0x84, 0xa7, 0x3c, 0x10, 0x24, 0x05, /* 0xcf */ + 0x40, 0x12, 0x00, 0x00, 0x10, 0x28, 0x80, 0x2a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xdf */ + 0x00, 0xf3, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, + 0x00, 0xf4, 0x00, 0xff, 0x79, 0x20, 0x30, 0x08, /* 0xef */ + 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xff */ +}; + +static const u16 vnt_frame_time[MAX_RATE] = { + 10, 20, 55, 110, 24, 36, 48, 72, 96, 144, 192, 216 +}; + +/* + * Description: Calculate data frame transmitting time + * + * Parameters: + * In: + * preamble_type - Preamble Type + * pkt_type - PK_TYPE_11A, PK_TYPE_11B, PK_TYPE_11GB, PK_TYPE_11GA + * frame_length - Baseband Type + * tx_rate - Tx Rate + * Out: + * + * Return Value: FrameTime + * + */ +unsigned int vnt_get_frame_time(u8 preamble_type, u8 pkt_type, + unsigned int frame_length, u16 tx_rate) +{ + unsigned int frame_time; + unsigned int preamble; + unsigned int tmp; + unsigned int rate = 0; + + if (tx_rate > RATE_54M) + return 0; + + rate = (unsigned int)vnt_frame_time[tx_rate]; + + if (tx_rate <= 3) { + if (preamble_type == 1) + preamble = 96; + else + preamble = 192; + + frame_time = (frame_length * 80) / rate; + tmp = (frame_time * rate) / 80; + + if (frame_length != tmp) + frame_time++; + + return preamble + frame_time; + } + frame_time = (frame_length * 8 + 22) / rate; + tmp = ((frame_time * rate) - 22) / 8; + + if (frame_length != tmp) + frame_time++; + + frame_time = frame_time * 4; + + if (pkt_type != PK_TYPE_11A) + frame_time += 6; + return 20 + frame_time; +} + +/* + * Description: Calculate Length, Service, and Signal fields of Phy for Tx + * + * Parameters: + * In: + * priv - Device Structure + * frame_length - Tx Frame Length + * tx_rate - Tx Rate + * Out: + * struct vnt_phy_field *phy + * - pointer to Phy Length field + * - pointer to Phy Service field + * - pointer to Phy Signal field + * + * Return Value: none + * + */ +void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length, + u16 tx_rate, u8 pkt_type, struct vnt_phy_field *phy) +{ + u32 bit_count; + u32 count = 0; + u32 tmp; + int ext_bit; + u8 preamble_type = priv->preamble_type; + + bit_count = frame_length * 8; + ext_bit = false; + + switch (tx_rate) { + case RATE_1M: + count = bit_count; + + phy->signal = 0x00; + + break; + case RATE_2M: + count = bit_count / 2; + + if (preamble_type == 1) + phy->signal = 0x09; + else + phy->signal = 0x01; + + break; + case RATE_5M: + count = (bit_count * 10) / 55; + tmp = (count * 55) / 10; + + if (tmp != bit_count) + count++; + + if (preamble_type == 1) + phy->signal = 0x0a; + else + phy->signal = 0x02; + + break; + case RATE_11M: + count = bit_count / 11; + tmp = count * 11; + + if (tmp != bit_count) { + count++; + + if ((bit_count - tmp) <= 3) + ext_bit = true; + } + + if (preamble_type == 1) + phy->signal = 0x0b; + else + phy->signal = 0x03; + + break; + case RATE_6M: + if (pkt_type == PK_TYPE_11A) + phy->signal = 0x9b; + else + phy->signal = 0x8b; + + break; + case RATE_9M: + if (pkt_type == PK_TYPE_11A) + phy->signal = 0x9f; + else + phy->signal = 0x8f; + + break; + case RATE_12M: + if (pkt_type == PK_TYPE_11A) + phy->signal = 0x9a; + else + phy->signal = 0x8a; + + break; + case RATE_18M: + if (pkt_type == PK_TYPE_11A) + phy->signal = 0x9e; + else + phy->signal = 0x8e; + + break; + case RATE_24M: + if (pkt_type == PK_TYPE_11A) + phy->signal = 0x99; + else + phy->signal = 0x89; + + break; + case RATE_36M: + if (pkt_type == PK_TYPE_11A) + phy->signal = 0x9d; + else + phy->signal = 0x8d; + + break; + case RATE_48M: + if (pkt_type == PK_TYPE_11A) + phy->signal = 0x98; + else + phy->signal = 0x88; + + break; + case RATE_54M: + if (pkt_type == PK_TYPE_11A) + phy->signal = 0x9c; + else + phy->signal = 0x8c; + break; + default: + if (pkt_type == PK_TYPE_11A) + phy->signal = 0x9c; + else + phy->signal = 0x8c; + break; + } + + if (pkt_type == PK_TYPE_11B) { + phy->service = 0x00; + if (ext_bit) + phy->service |= 0x80; + phy->len = cpu_to_le16((u16)count); + } else { + phy->service = 0x00; + phy->len = cpu_to_le16((u16)frame_length); + } +} + +/* + * Description: Set Antenna mode + * + * Parameters: + * In: + * priv - Device Structure + * antenna_mode - Antenna Mode + * Out: + * none + * + * Return Value: none + * + */ +void vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode) +{ + switch (antenna_mode) { + case ANT_TXA: + case ANT_TXB: + break; + case ANT_RXA: + priv->bb_rx_conf &= 0xFC; + break; + case ANT_RXB: + priv->bb_rx_conf &= 0xFE; + priv->bb_rx_conf |= 0x02; + break; + } + + vnt_control_out(priv, MESSAGE_TYPE_SET_ANTMD, + (u16)antenna_mode, 0, 0, NULL); +} + +/* + * Description: Set Antenna mode + * + * Parameters: + * In: + * pDevice - Device Structure + * byAntennaMode - Antenna Mode + * Out: + * none + * + * Return Value: none + * + */ + +int vnt_vt3184_init(struct vnt_private *priv) +{ + int status; + u16 length; + u8 *addr; + u8 *agc; + u16 length_agc; + u8 array[256]; + u8 data; + + status = vnt_control_in(priv, MESSAGE_TYPE_READ, 0, + MESSAGE_REQUEST_EEPROM, EEP_MAX_CONTEXT_SIZE, + priv->eeprom); + if (status != STATUS_SUCCESS) + return false; + + priv->rf_type = priv->eeprom[EEP_OFS_RFTYPE]; + + dev_dbg(&priv->usb->dev, "RF Type %d\n", priv->rf_type); + + if ((priv->rf_type == RF_AL2230) || + (priv->rf_type == RF_AL2230S)) { + priv->bb_rx_conf = vnt_vt3184_al2230[10]; + length = sizeof(vnt_vt3184_al2230); + addr = vnt_vt3184_al2230; + agc = vnt_vt3184_agc; + length_agc = sizeof(vnt_vt3184_agc); + + priv->bb_vga[0] = 0x1C; + priv->bb_vga[1] = 0x10; + priv->bb_vga[2] = 0x0; + priv->bb_vga[3] = 0x0; + + } else if (priv->rf_type == RF_AIROHA7230) { + priv->bb_rx_conf = vnt_vt3184_al2230[10]; + length = sizeof(vnt_vt3184_al2230); + addr = vnt_vt3184_al2230; + agc = vnt_vt3184_agc; + length_agc = sizeof(vnt_vt3184_agc); + + addr[0xd7] = 0x06; + + priv->bb_vga[0] = 0x1c; + priv->bb_vga[1] = 0x10; + priv->bb_vga[2] = 0x0; + priv->bb_vga[3] = 0x0; + + } else if ((priv->rf_type == RF_VT3226) || + (priv->rf_type == RF_VT3226D0)) { + priv->bb_rx_conf = vnt_vt3184_vt3226d0[10]; + length = sizeof(vnt_vt3184_vt3226d0); + addr = vnt_vt3184_vt3226d0; + agc = vnt_vt3184_agc; + length_agc = sizeof(vnt_vt3184_agc); + + priv->bb_vga[0] = 0x20; + priv->bb_vga[1] = 0x10; + priv->bb_vga[2] = 0x0; + priv->bb_vga[3] = 0x0; + + /* Fix VT3226 DFC system timing issue */ + vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2, + SOFTPWRCTL_RFLEOPT); + } else if (priv->rf_type == RF_VT3342A0) { + priv->bb_rx_conf = vnt_vt3184_vt3226d0[10]; + length = sizeof(vnt_vt3184_vt3226d0); + addr = vnt_vt3184_vt3226d0; + agc = vnt_vt3184_agc; + length_agc = sizeof(vnt_vt3184_agc); + + priv->bb_vga[0] = 0x20; + priv->bb_vga[1] = 0x10; + priv->bb_vga[2] = 0x0; + priv->bb_vga[3] = 0x0; + + /* Fix VT3226 DFC system timing issue */ + vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2, + SOFTPWRCTL_RFLEOPT); + } else { + return true; + } + + memcpy(array, addr, length); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0, + MESSAGE_REQUEST_BBREG, length, array); + + memcpy(array, agc, length_agc); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0, + MESSAGE_REQUEST_BBAGC, length_agc, array); + + if ((priv->rf_type == RF_VT3226) || + (priv->rf_type == RF_VT3342A0)) { + vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, + MAC_REG_ITRTMSET, 0x23); + vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01); + } else if (priv->rf_type == RF_VT3226D0) { + vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, + MAC_REG_ITRTMSET, 0x11); + vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01); + } + + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x04, 0x7f); + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01); + + vnt_rf_table_download(priv); + + /* Fix for TX USB resets from vendors driver */ + vnt_control_in(priv, MESSAGE_TYPE_READ, USB_REG4, + MESSAGE_REQUEST_MEM, sizeof(data), &data); + + data |= 0x2; + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, USB_REG4, + MESSAGE_REQUEST_MEM, sizeof(data), &data); + + return true; +} + +/* + * Description: Set ShortSlotTime mode + * + * Parameters: + * In: + * priv - Device Structure + * Out: + * none + * + * Return Value: none + * + */ +void vnt_set_short_slot_time(struct vnt_private *priv) +{ + u8 bb_vga = 0; + + if (priv->short_slot_time) + priv->bb_rx_conf &= 0xdf; + else + priv->bb_rx_conf |= 0x20; + + vnt_control_in_u8(priv, MESSAGE_REQUEST_BBREG, 0xe7, &bb_vga); + + if (bb_vga == priv->bb_vga[0]) + priv->bb_rx_conf |= 0x20; + + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0a, priv->bb_rx_conf); +} + +void vnt_set_vga_gain_offset(struct vnt_private *priv, u8 data) +{ + + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0xE7, data); + + /* patch for 3253B0 Baseband with Cardbus module */ + if (priv->short_slot_time) + priv->bb_rx_conf &= 0xdf; /* 1101 1111 */ + else + priv->bb_rx_conf |= 0x20; /* 0010 0000 */ + + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0a, priv->bb_rx_conf); +} + +/* + * Description: vnt_set_deep_sleep + * + * Parameters: + * In: + * priv - Device Structure + * Out: + * none + * + * Return Value: none + * + */ +void vnt_set_deep_sleep(struct vnt_private *priv) +{ + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x17);/* CR12 */ + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0xB9);/* CR13 */ +} + +void vnt_exit_deep_sleep(struct vnt_private *priv) +{ + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x00);/* CR12 */ + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01);/* CR13 */ +} + +void vnt_update_pre_ed_threshold(struct vnt_private *priv, int scanning) +{ + u8 cr_201 = 0x0, cr_206 = 0x0; + u8 ed_inx = priv->bb_pre_ed_index; + + switch (priv->rf_type) { + case RF_AL2230: + case RF_AL2230S: + case RF_AIROHA7230: + if (scanning) { /* Max sensitivity */ + ed_inx = 0; + cr_206 = 0x30; + break; + } + + if (priv->bb_pre_ed_rssi <= 45) { + ed_inx = 20; + cr_201 = 0xff; + } else if (priv->bb_pre_ed_rssi <= 46) { + ed_inx = 19; + cr_201 = 0x1a; + } else if (priv->bb_pre_ed_rssi <= 47) { + ed_inx = 18; + cr_201 = 0x15; + } else if (priv->bb_pre_ed_rssi <= 49) { + ed_inx = 17; + cr_201 = 0xe; + } else if (priv->bb_pre_ed_rssi <= 51) { + ed_inx = 16; + cr_201 = 0x9; + } else if (priv->bb_pre_ed_rssi <= 53) { + ed_inx = 15; + cr_201 = 0x6; + } else if (priv->bb_pre_ed_rssi <= 55) { + ed_inx = 14; + cr_201 = 0x3; + } else if (priv->bb_pre_ed_rssi <= 56) { + ed_inx = 13; + cr_201 = 0x2; + cr_206 = 0xa0; + } else if (priv->bb_pre_ed_rssi <= 57) { + ed_inx = 12; + cr_201 = 0x2; + cr_206 = 0x20; + } else if (priv->bb_pre_ed_rssi <= 58) { + ed_inx = 11; + cr_201 = 0x1; + cr_206 = 0xa0; + } else if (priv->bb_pre_ed_rssi <= 59) { + ed_inx = 10; + cr_201 = 0x1; + cr_206 = 0x54; + } else if (priv->bb_pre_ed_rssi <= 60) { + ed_inx = 9; + cr_201 = 0x1; + cr_206 = 0x18; + } else if (priv->bb_pre_ed_rssi <= 61) { + ed_inx = 8; + cr_206 = 0xe3; + } else if (priv->bb_pre_ed_rssi <= 62) { + ed_inx = 7; + cr_206 = 0xb9; + } else if (priv->bb_pre_ed_rssi <= 63) { + ed_inx = 6; + cr_206 = 0x93; + } else if (priv->bb_pre_ed_rssi <= 64) { + ed_inx = 5; + cr_206 = 0x79; + } else if (priv->bb_pre_ed_rssi <= 65) { + ed_inx = 4; + cr_206 = 0x62; + } else if (priv->bb_pre_ed_rssi <= 66) { + ed_inx = 3; + cr_206 = 0x51; + } else if (priv->bb_pre_ed_rssi <= 67) { + ed_inx = 2; + cr_206 = 0x43; + } else if (priv->bb_pre_ed_rssi <= 68) { + ed_inx = 1; + cr_206 = 0x36; + } else { + ed_inx = 0; + cr_206 = 0x30; + } + break; + + case RF_VT3226: + case RF_VT3226D0: + if (scanning) { /* Max sensitivity */ + ed_inx = 0; + cr_206 = 0x24; + break; + } + + if (priv->bb_pre_ed_rssi <= 41) { + ed_inx = 22; + cr_201 = 0xff; + } else if (priv->bb_pre_ed_rssi <= 42) { + ed_inx = 21; + cr_201 = 0x36; + } else if (priv->bb_pre_ed_rssi <= 43) { + ed_inx = 20; + cr_201 = 0x26; + } else if (priv->bb_pre_ed_rssi <= 45) { + ed_inx = 19; + cr_201 = 0x18; + } else if (priv->bb_pre_ed_rssi <= 47) { + ed_inx = 18; + cr_201 = 0x11; + } else if (priv->bb_pre_ed_rssi <= 49) { + ed_inx = 17; + cr_201 = 0xa; + } else if (priv->bb_pre_ed_rssi <= 51) { + ed_inx = 16; + cr_201 = 0x7; + } else if (priv->bb_pre_ed_rssi <= 53) { + ed_inx = 15; + cr_201 = 0x4; + } else if (priv->bb_pre_ed_rssi <= 55) { + ed_inx = 14; + cr_201 = 0x2; + cr_206 = 0xc0; + } else if (priv->bb_pre_ed_rssi <= 56) { + ed_inx = 13; + cr_201 = 0x2; + cr_206 = 0x30; + } else if (priv->bb_pre_ed_rssi <= 57) { + ed_inx = 12; + cr_201 = 0x1; + cr_206 = 0xb0; + } else if (priv->bb_pre_ed_rssi <= 58) { + ed_inx = 11; + cr_201 = 0x1; + cr_206 = 0x70; + } else if (priv->bb_pre_ed_rssi <= 59) { + ed_inx = 10; + cr_201 = 0x1; + cr_206 = 0x30; + } else if (priv->bb_pre_ed_rssi <= 60) { + ed_inx = 9; + cr_206 = 0xea; + } else if (priv->bb_pre_ed_rssi <= 61) { + ed_inx = 8; + cr_206 = 0xc0; + } else if (priv->bb_pre_ed_rssi <= 62) { + ed_inx = 7; + cr_206 = 0x9c; + } else if (priv->bb_pre_ed_rssi <= 63) { + ed_inx = 6; + cr_206 = 0x80; + } else if (priv->bb_pre_ed_rssi <= 64) { + ed_inx = 5; + cr_206 = 0x68; + } else if (priv->bb_pre_ed_rssi <= 65) { + ed_inx = 4; + cr_206 = 0x52; + } else if (priv->bb_pre_ed_rssi <= 66) { + ed_inx = 3; + cr_206 = 0x43; + } else if (priv->bb_pre_ed_rssi <= 67) { + ed_inx = 2; + cr_206 = 0x36; + } else if (priv->bb_pre_ed_rssi <= 68) { + ed_inx = 1; + cr_206 = 0x2d; + } else { + ed_inx = 0; + cr_206 = 0x24; + } + break; + + case RF_VT3342A0: + if (scanning) { /* need Max sensitivity */ + ed_inx = 0; + cr_206 = 0x38; + break; + } + + if (priv->bb_pre_ed_rssi <= 41) { + ed_inx = 20; + cr_201 = 0xff; + } else if (priv->bb_pre_ed_rssi <= 42) { + ed_inx = 19; + cr_201 = 0x36; + } else if (priv->bb_pre_ed_rssi <= 43) { + ed_inx = 18; + cr_201 = 0x26; + } else if (priv->bb_pre_ed_rssi <= 45) { + ed_inx = 17; + cr_201 = 0x18; + } else if (priv->bb_pre_ed_rssi <= 47) { + ed_inx = 16; + cr_201 = 0x11; + } else if (priv->bb_pre_ed_rssi <= 49) { + ed_inx = 15; + cr_201 = 0xa; + } else if (priv->bb_pre_ed_rssi <= 51) { + ed_inx = 14; + cr_201 = 0x7; + } else if (priv->bb_pre_ed_rssi <= 53) { + ed_inx = 13; + cr_201 = 0x4; + } else if (priv->bb_pre_ed_rssi <= 55) { + ed_inx = 12; + cr_201 = 0x2; + cr_206 = 0xc0; + } else if (priv->bb_pre_ed_rssi <= 56) { + ed_inx = 11; + cr_201 = 0x2; + cr_206 = 0x30; + } else if (priv->bb_pre_ed_rssi <= 57) { + ed_inx = 10; + cr_201 = 0x1; + cr_206 = 0xb0; + } else if (priv->bb_pre_ed_rssi <= 58) { + ed_inx = 9; + cr_201 = 0x1; + cr_206 = 0x70; + } else if (priv->bb_pre_ed_rssi <= 59) { + ed_inx = 8; + cr_201 = 0x1; + cr_206 = 0x30; + } else if (priv->bb_pre_ed_rssi <= 60) { + ed_inx = 7; + cr_206 = 0xea; + } else if (priv->bb_pre_ed_rssi <= 61) { + ed_inx = 6; + cr_206 = 0xc0; + } else if (priv->bb_pre_ed_rssi <= 62) { + ed_inx = 5; + cr_206 = 0x9c; + } else if (priv->bb_pre_ed_rssi <= 63) { + ed_inx = 4; + cr_206 = 0x80; + } else if (priv->bb_pre_ed_rssi <= 64) { + ed_inx = 3; + cr_206 = 0x68; + } else if (priv->bb_pre_ed_rssi <= 65) { + ed_inx = 2; + cr_206 = 0x52; + } else if (priv->bb_pre_ed_rssi <= 66) { + ed_inx = 1; + cr_206 = 0x43; + } else { + ed_inx = 0; + cr_206 = 0x38; + } + break; + + } + + if (ed_inx == priv->bb_pre_ed_index && !scanning) + return; + + priv->bb_pre_ed_index = ed_inx; + + dev_dbg(&priv->usb->dev, "%s bb_pre_ed_rssi %d\n", + __func__, priv->bb_pre_ed_rssi); + + if (!cr_201 && !cr_206) + return; + + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0xc9, cr_201); + vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0xce, cr_206); +} + diff --git a/kernel/drivers/staging/vt6656/baseband.h b/kernel/drivers/staging/vt6656/baseband.h new file mode 100644 index 000000000..771ea4054 --- /dev/null +++ b/kernel/drivers/staging/vt6656/baseband.h @@ -0,0 +1,104 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: baseband.h + * + * Purpose: Implement functions to access baseband + * + * Author: Jerry Chen + * + * Date: Jun. 5, 2002 + * + * Revision History: + * 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. + * 08-26-2003 Kyle Hsu : Add defines of packet type and TX rate. + */ + +#ifndef __BASEBAND_H__ +#define __BASEBAND_H__ + +#include "device.h" + +#define PREAMBLE_LONG 0 +#define PREAMBLE_SHORT 1 + +/* + * Registers in the BASEBAND + */ +#define BB_MAX_CONTEXT_SIZE 256 + +#define C_SIFS_A 16 /* usec */ +#define C_SIFS_BG 10 + +#define C_EIFS 80 /* usec */ + +#define C_SLOT_SHORT 9 /* usec */ +#define C_SLOT_LONG 20 + +#define C_CWMIN_A 15 /* slot time */ +#define C_CWMIN_B 31 + +#define C_CWMAX 1023 /* slot time */ + +/* 0:11A 1:11B 2:11G */ +#define BB_TYPE_11A 0 +#define BB_TYPE_11B 1 +#define BB_TYPE_11G 2 + +/* 0:11a, 1:11b, 2:11gb (only CCK in BasicRate), 3:11ga (OFDM in BasicRate) */ +#define PK_TYPE_11A 0 +#define PK_TYPE_11B 1 +#define PK_TYPE_11GB 2 +#define PK_TYPE_11GA 3 + +#define TOP_RATE_54M 0x80000000 +#define TOP_RATE_48M 0x40000000 +#define TOP_RATE_36M 0x20000000 +#define TOP_RATE_24M 0x10000000 +#define TOP_RATE_18M 0x08000000 +#define TOP_RATE_12M 0x04000000 +#define TOP_RATE_11M 0x02000000 +#define TOP_RATE_9M 0x01000000 +#define TOP_RATE_6M 0x00800000 +#define TOP_RATE_55M 0x00400000 +#define TOP_RATE_2M 0x00200000 +#define TOP_RATE_1M 0x00100000 + +/* Length, Service, and Signal fields of Phy for Tx */ +struct vnt_phy_field { + u8 signal; + u8 service; + __le16 len; +} __packed; + +unsigned int vnt_get_frame_time(u8 preamble_type, u8 pkt_type, + unsigned int frame_length, u16 tx_rate); + +void vnt_get_phy_field(struct vnt_private *, u32 frame_length, + u16 tx_rate, u8 pkt_type, struct vnt_phy_field *); + +void vnt_set_short_slot_time(struct vnt_private *); +void vnt_set_vga_gain_offset(struct vnt_private *, u8); +void vnt_set_antenna_mode(struct vnt_private *, u8); +int vnt_vt3184_init(struct vnt_private *); +void vnt_set_deep_sleep(struct vnt_private *); +void vnt_exit_deep_sleep(struct vnt_private *); +void vnt_update_pre_ed_threshold(struct vnt_private *, int scanning); + +#endif /* __BASEBAND_H__ */ diff --git a/kernel/drivers/staging/vt6656/card.c b/kernel/drivers/staging/vt6656/card.c new file mode 100644 index 000000000..67ff13f4f --- /dev/null +++ b/kernel/drivers/staging/vt6656/card.c @@ -0,0 +1,820 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * 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 cwRXBCNTSFOff[MAX_RATE] = + {17, 34, 96, 192, 34, 23, 17, 11, 8, 5, 4, 3}; */ + +static const u16 cwRXBCNTSFOff[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 == true) + 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)(1 << 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) +{ + u64 tsf_offset = 0; + u16 rx_bcn_offset = 0; + + rx_bcn_offset = cwRXBCNTSFOff[rx_rate % MAX_RATE]; + + tsf2 += (u64)rx_bcn_offset; + + tsf_offset = tsf1 - tsf2; + + return tsf_offset; +} + +/* + * 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]); +} diff --git a/kernel/drivers/staging/vt6656/card.h b/kernel/drivers/staging/vt6656/card.h new file mode 100644 index 000000000..03fc16788 --- /dev/null +++ b/kernel/drivers/staging/vt6656/card.h @@ -0,0 +1,58 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: card.h + * + * Purpose: Provide functions to setup NIC operation mode + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + */ + +#ifndef __CARD_H__ +#define __CARD_H__ +#include "device.h" + +/* init card type */ + +#define CB_MAX_CHANNEL_24G 14 +#define CB_MAX_CHANNEL_5G 42 /* add channel9(5045MHz), 41==>42 */ +#define CB_MAX_CHANNEL (CB_MAX_CHANNEL_24G + CB_MAX_CHANNEL_5G) + +struct vnt_private; + +void vnt_set_channel(struct vnt_private *, u32); +void vnt_set_rspinf(struct vnt_private *, u8); +void vnt_update_ifs(struct vnt_private *); +void vnt_update_top_rates(struct vnt_private *); +int vnt_ofdm_min_rate(struct vnt_private *); +void vnt_adjust_tsf(struct vnt_private *, u8, u64, u64); +bool vnt_get_current_tsf(struct vnt_private *, u64 *); +bool vnt_clear_current_tsf(struct vnt_private *); +void vnt_reset_next_tbtt(struct vnt_private *, u16); +void vnt_update_next_tbtt(struct vnt_private *, u64, u16); +u64 vnt_get_next_tbtt(u64, u16); +u64 vnt_get_tsf_offset(u8 byRxRate, u64 qwTSF1, u64 qwTSF2); +int vnt_radio_power_off(struct vnt_private *); +int vnt_radio_power_on(struct vnt_private *); +u8 vnt_get_pkt_type(struct vnt_private *); +void vnt_set_bss_mode(struct vnt_private *); + +#endif /* __CARD_H__ */ diff --git a/kernel/drivers/staging/vt6656/channel.c b/kernel/drivers/staging/vt6656/channel.c new file mode 100644 index 000000000..8412d0532 --- /dev/null +++ b/kernel/drivers/staging/vt6656/channel.c @@ -0,0 +1,178 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: channel.c + * + * Purpose: Channel number mapping + * + * Author: Lucas Lin + * + * Date: Dec 24, 2004 + * + * + * + * Revision History: + * 01-18-2005 RobertYu: remove the for loop searching in + * ChannelValid, change ChannelRuleTab + * to lookup-type, reorder table items. + * + * + */ + +#include "device.h" +#include "channel.h" +#include "rf.h" + +static struct ieee80211_rate vnt_rates_bg[] = { + { .bitrate = 10, .hw_value = RATE_1M }, + { .bitrate = 20, .hw_value = RATE_2M }, + { .bitrate = 55, .hw_value = RATE_5M }, + { .bitrate = 110, .hw_value = RATE_11M }, + { .bitrate = 60, .hw_value = RATE_6M }, + { .bitrate = 90, .hw_value = RATE_9M }, + { .bitrate = 120, .hw_value = RATE_12M }, + { .bitrate = 180, .hw_value = RATE_18M }, + { .bitrate = 240, .hw_value = RATE_24M }, + { .bitrate = 360, .hw_value = RATE_36M }, + { .bitrate = 480, .hw_value = RATE_48M }, + { .bitrate = 540, .hw_value = RATE_54M }, +}; + +static struct ieee80211_rate vnt_rates_a[] = { + { .bitrate = 60, .hw_value = RATE_6M }, + { .bitrate = 90, .hw_value = RATE_9M }, + { .bitrate = 120, .hw_value = RATE_12M }, + { .bitrate = 180, .hw_value = RATE_18M }, + { .bitrate = 240, .hw_value = RATE_24M }, + { .bitrate = 360, .hw_value = RATE_36M }, + { .bitrate = 480, .hw_value = RATE_48M }, + { .bitrate = 540, .hw_value = RATE_54M }, +}; + +static struct ieee80211_channel vnt_channels_2ghz[] = { + { .center_freq = 2412, .hw_value = 1 }, + { .center_freq = 2417, .hw_value = 2 }, + { .center_freq = 2422, .hw_value = 3 }, + { .center_freq = 2427, .hw_value = 4 }, + { .center_freq = 2432, .hw_value = 5 }, + { .center_freq = 2437, .hw_value = 6 }, + { .center_freq = 2442, .hw_value = 7 }, + { .center_freq = 2447, .hw_value = 8 }, + { .center_freq = 2452, .hw_value = 9 }, + { .center_freq = 2457, .hw_value = 10 }, + { .center_freq = 2462, .hw_value = 11 }, + { .center_freq = 2467, .hw_value = 12 }, + { .center_freq = 2472, .hw_value = 13 }, + { .center_freq = 2484, .hw_value = 14 } +}; + +static struct ieee80211_channel vnt_channels_5ghz[] = { + { .center_freq = 4915, .hw_value = 15 }, + { .center_freq = 4920, .hw_value = 16 }, + { .center_freq = 4925, .hw_value = 17 }, + { .center_freq = 4935, .hw_value = 18 }, + { .center_freq = 4940, .hw_value = 19 }, + { .center_freq = 4945, .hw_value = 20 }, + { .center_freq = 4960, .hw_value = 21 }, + { .center_freq = 4980, .hw_value = 22 }, + { .center_freq = 5035, .hw_value = 23 }, + { .center_freq = 5040, .hw_value = 24 }, + { .center_freq = 5045, .hw_value = 25 }, + { .center_freq = 5055, .hw_value = 26 }, + { .center_freq = 5060, .hw_value = 27 }, + { .center_freq = 5080, .hw_value = 28 }, + { .center_freq = 5170, .hw_value = 29 }, + { .center_freq = 5180, .hw_value = 30 }, + { .center_freq = 5190, .hw_value = 31 }, + { .center_freq = 5200, .hw_value = 32 }, + { .center_freq = 5210, .hw_value = 33 }, + { .center_freq = 5220, .hw_value = 34 }, + { .center_freq = 5230, .hw_value = 35 }, + { .center_freq = 5240, .hw_value = 36 }, + { .center_freq = 5260, .hw_value = 37 }, + { .center_freq = 5280, .hw_value = 38 }, + { .center_freq = 5300, .hw_value = 39 }, + { .center_freq = 5320, .hw_value = 40 }, + { .center_freq = 5500, .hw_value = 41 }, + { .center_freq = 5520, .hw_value = 42 }, + { .center_freq = 5540, .hw_value = 43 }, + { .center_freq = 5560, .hw_value = 44 }, + { .center_freq = 5580, .hw_value = 45 }, + { .center_freq = 5600, .hw_value = 46 }, + { .center_freq = 5620, .hw_value = 47 }, + { .center_freq = 5640, .hw_value = 48 }, + { .center_freq = 5660, .hw_value = 49 }, + { .center_freq = 5680, .hw_value = 50 }, + { .center_freq = 5700, .hw_value = 51 }, + { .center_freq = 5745, .hw_value = 52 }, + { .center_freq = 5765, .hw_value = 53 }, + { .center_freq = 5785, .hw_value = 54 }, + { .center_freq = 5805, .hw_value = 55 }, + { .center_freq = 5825, .hw_value = 56 } +}; + +static struct ieee80211_supported_band vnt_supported_2ghz_band = { + .channels = vnt_channels_2ghz, + .n_channels = ARRAY_SIZE(vnt_channels_2ghz), + .bitrates = vnt_rates_bg, + .n_bitrates = ARRAY_SIZE(vnt_rates_bg), +}; + +static struct ieee80211_supported_band vnt_supported_5ghz_band = { + .channels = vnt_channels_5ghz, + .n_channels = ARRAY_SIZE(vnt_channels_5ghz), + .bitrates = vnt_rates_a, + .n_bitrates = ARRAY_SIZE(vnt_rates_a), +}; + +void vnt_init_bands(struct vnt_private *priv) +{ + struct ieee80211_channel *ch; + int i; + + switch (priv->rf_type) { + case RF_AIROHA7230: + case RF_VT3342A0: + default: + ch = vnt_channels_5ghz; + + for (i = 0; i < ARRAY_SIZE(vnt_channels_5ghz); i++) { + ch[i].max_power = VNT_RF_MAX_POWER; + ch[i].flags = IEEE80211_CHAN_NO_HT40; + } + + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &vnt_supported_5ghz_band; + /* fallthrough */ + case RF_AL2230: + case RF_AL2230S: + case RF_VT3226: + case RF_VT3226D0: + ch = vnt_channels_2ghz; + + for (i = 0; i < ARRAY_SIZE(vnt_channels_2ghz); i++) { + ch[i].max_power = VNT_RF_MAX_POWER; + ch[i].flags = IEEE80211_CHAN_NO_HT40; + } + + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &vnt_supported_2ghz_band; + break; + } +} diff --git a/kernel/drivers/staging/vt6656/channel.h b/kernel/drivers/staging/vt6656/channel.h new file mode 100644 index 000000000..21c080803 --- /dev/null +++ b/kernel/drivers/staging/vt6656/channel.h @@ -0,0 +1,37 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: channel.h + * + * Purpose: Country Regulation Rules header file + * + * Author: Lucas Lin + * + * Date: Dec 23, 2004 + * + */ + +#ifndef _CHANNEL_H_ +#define _CHANNEL_H_ + +#include "device.h" + +void vnt_init_bands(struct vnt_private *); + +#endif /* _CHANNEL_H_ */ diff --git a/kernel/drivers/staging/vt6656/desc.h b/kernel/drivers/staging/vt6656/desc.h new file mode 100644 index 000000000..f79af8513 --- /dev/null +++ b/kernel/drivers/staging/vt6656/desc.h @@ -0,0 +1,105 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: desc.h + * + * Purpose:The header file of descriptor + * + * Revision History: + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + */ + +#ifndef __DESC_H__ +#define __DESC_H__ + +#include <linux/types.h> +#include <linux/mm.h> + +/* max transmit or receive buffer size */ +#define CB_MAX_BUF_SIZE 2900U /* NOTE: must be multiple of 4 */ + +#define MAX_TOTAL_SIZE_WITH_ALL_HEADERS CB_MAX_BUF_SIZE + +#define MAX_INTERRUPT_SIZE 32 + +#define CB_MAX_RX_DESC 128 /* max # of descriptors */ +#define CB_MIN_RX_DESC 16 /* min # of RX descriptors */ +#define CB_MAX_TX_DESC 128 /* max # of descriptors */ +#define CB_MIN_TX_DESC 16 /* min # of TX descriptors */ + +/* + * bits in the RSR register + */ +#define RSR_ADDRBROAD 0x80 +#define RSR_ADDRMULTI 0x40 +#define RSR_ADDRUNI 0x00 +#define RSR_IVLDTYP 0x20 /* invalid packet type */ +#define RSR_IVLDLEN 0x10 /* invalid len (> 2312 byte) */ +#define RSR_BSSIDOK 0x08 +#define RSR_CRCOK 0x04 +#define RSR_BCNSSIDOK 0x02 +#define RSR_ADDROK 0x01 + +/* + * bits in the new RSR register + */ +#define NEWRSR_DECRYPTOK 0x10 +#define NEWRSR_CFPIND 0x08 +#define NEWRSR_HWUTSF 0x04 +#define NEWRSR_BCNHITAID 0x02 +#define NEWRSR_BCNHITAID0 0x01 + +/* + * bits in the TSR register + */ +#define TSR_RETRYTMO 0x08 +#define TSR_TMO 0x04 +#define TSR_ACKDATA 0x02 +#define TSR_VALID 0x01 + +#define FIFOCTL_AUTO_FB_1 0x1000 +#define FIFOCTL_AUTO_FB_0 0x0800 +#define FIFOCTL_GRPACK 0x0400 +#define FIFOCTL_11GA 0x0300 +#define FIFOCTL_11GB 0x0200 +#define FIFOCTL_11B 0x0100 +#define FIFOCTL_11A 0x0000 +#define FIFOCTL_RTS 0x0080 +#define FIFOCTL_ISDMA0 0x0040 +#define FIFOCTL_GENINT 0x0020 +#define FIFOCTL_TMOEN 0x0010 +#define FIFOCTL_LRETRY 0x0008 +#define FIFOCTL_CRCDIS 0x0004 +#define FIFOCTL_NEEDACK 0x0002 +#define FIFOCTL_LHEAD 0x0001 + +/* WMAC definition Frag Control */ +#define FRAGCTL_AES 0x0300 +#define FRAGCTL_TKIP 0x0200 +#define FRAGCTL_LEGACY 0x0100 +#define FRAGCTL_NONENCRYPT 0x0000 +#define FRAGCTL_ENDFRAG 0x0003 +#define FRAGCTL_MIDFRAG 0x0002 +#define FRAGCTL_STAFRAG 0x0001 +#define FRAGCTL_NONFRAG 0x0000 + +#endif /* __DESC_H__ */ diff --git a/kernel/drivers/staging/vt6656/device.h b/kernel/drivers/staging/vt6656/device.h new file mode 100644 index 000000000..f71d59fa3 --- /dev/null +++ b/kernel/drivers/staging/vt6656/device.h @@ -0,0 +1,407 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: device.h + * + * Purpose: MAC Data structure + * + * Author: Tevin Chen + * + * Date: Mar 17, 1997 + * + */ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/firmware.h> +#include <linux/suspend.h> +#include <linux/if_arp.h> +#include <linux/wireless.h> +#include <linux/timer.h> +#include <linux/usb.h> +#include <linux/crc32.h> +#include <net/mac80211.h> + +#ifdef SIOCETHTOOL +#define DEVICE_ETHTOOL_IOCTL_SUPPORT +#include <linux/ethtool.h> +#else +#undef DEVICE_ETHTOOL_IOCTL_SUPPORT +#endif + +#define RATE_1M 0 +#define RATE_2M 1 +#define RATE_5M 2 +#define RATE_11M 3 +#define RATE_6M 4 +#define RATE_9M 5 +#define RATE_12M 6 +#define RATE_18M 7 +#define RATE_24M 8 +#define RATE_36M 9 +#define RATE_48M 10 +#define RATE_54M 11 +#define RATE_AUTO 12 + +#define MAX_RATE 12 + +/* + * device specific + */ + +#include "wcmd.h" +#include "desc.h" +#include "key.h" +#include "card.h" + +#define VNT_USB_VENDOR_ID 0x160a +#define VNT_USB_PRODUCT_ID 0x3184 + +#define DEVICE_NAME "vt6656" +#define DEVICE_FULL_DRV_NAM "VIA Networking Wireless LAN USB Driver" + +#define DEVICE_VERSION "mac80211" + +#define CONFIG_PATH "/etc/vntconfiguration.dat" + +#define MAX_UINTS 8 +#define OPTION_DEFAULT { [0 ... MAX_UINTS-1] = -1} + +#define DUPLICATE_RX_CACHE_LENGTH 5 + +#define AUTO_FB_NONE 0 +#define AUTO_FB_0 1 +#define AUTO_FB_1 2 + +#define FB_RATE0 0 +#define FB_RATE1 1 + +/* Antenna Mode */ +#define ANT_A 0 +#define ANT_B 1 +#define ANT_DIVERSITY 2 +#define ANT_RXD_TXA 3 +#define ANT_RXD_TXB 4 +#define ANT_UNKNOWN 0xFF +#define ANT_TXA 0 +#define ANT_TXB 1 +#define ANT_RXA 2 +#define ANT_RXB 3 + +#define BB_VGA_LEVEL 4 +#define BB_VGA_CHANGE_THRESHOLD 3 + +#define EEP_MAX_CONTEXT_SIZE 256 + +/* Contents in the EEPROM */ +#define EEP_OFS_PAR 0x0 +#define EEP_OFS_ANTENNA 0x17 +#define EEP_OFS_RADIOCTL 0x18 +#define EEP_OFS_RFTYPE 0x1b +#define EEP_OFS_MINCHANNEL 0x1c +#define EEP_OFS_MAXCHANNEL 0x1d +#define EEP_OFS_SIGNATURE 0x1e +#define EEP_OFS_ZONETYPE 0x1f +#define EEP_OFS_RFTABLE 0x20 +#define EEP_OFS_PWR_CCK 0x20 +#define EEP_OFS_SETPT_CCK 0x21 +#define EEP_OFS_PWR_OFDMG 0x23 + +#define EEP_OFS_CALIB_TX_IQ 0x24 +#define EEP_OFS_CALIB_TX_DC 0x25 +#define EEP_OFS_CALIB_RX_IQ 0x26 + +#define EEP_OFS_MAJOR_VER 0x2e +#define EEP_OFS_MINOR_VER 0x2f + +#define EEP_OFS_CCK_PWR_TBL 0x30 +#define EEP_OFS_OFDM_PWR_TBL 0x40 +#define EEP_OFS_OFDMA_PWR_TBL 0x50 + +/* Bits in EEP_OFS_ANTENNA */ +#define EEP_ANTENNA_MAIN 0x1 +#define EEP_ANTENNA_AUX 0x2 +#define EEP_ANTINV 0x4 + +/* Bits in EEP_OFS_RADIOCTL */ +#define EEP_RADIOCTL_ENABLE 0x80 + +/* control commands */ +#define MESSAGE_TYPE_READ 0x1 +#define MESSAGE_TYPE_WRITE 0x0 +#define MESSAGE_TYPE_LOCK_OR 0x2 +#define MESSAGE_TYPE_LOCK_AND 0x3 +#define MESSAGE_TYPE_WRITE_MASK 0x4 +#define MESSAGE_TYPE_CARDINIT 0x5 +#define MESSAGE_TYPE_INIT_RSP 0x6 +#define MESSAGE_TYPE_MACSHUTDOWN 0x7 +#define MESSAGE_TYPE_SETKEY 0x8 +#define MESSAGE_TYPE_CLRKEYENTRY 0x9 +#define MESSAGE_TYPE_WRITE_MISCFF 0xa +#define MESSAGE_TYPE_SET_ANTMD 0xb +#define MESSAGE_TYPE_SELECT_CHANNEL 0xc +#define MESSAGE_TYPE_SET_TSFTBTT 0xd +#define MESSAGE_TYPE_SET_SSTIFS 0xe +#define MESSAGE_TYPE_CHANGE_BBTYPE 0xf +#define MESSAGE_TYPE_DISABLE_PS 0x10 +#define MESSAGE_TYPE_WRITE_IFRF 0x11 + +/* command read/write(index) */ +#define MESSAGE_REQUEST_MEM 0x1 +#define MESSAGE_REQUEST_BBREG 0x2 +#define MESSAGE_REQUEST_MACREG 0x3 +#define MESSAGE_REQUEST_EEPROM 0x4 +#define MESSAGE_REQUEST_TSF 0x5 +#define MESSAGE_REQUEST_TBTT 0x6 +#define MESSAGE_REQUEST_BBAGC 0x7 +#define MESSAGE_REQUEST_VERSION 0x8 +#define MESSAGE_REQUEST_RF_INIT 0x9 +#define MESSAGE_REQUEST_RF_INIT2 0xa +#define MESSAGE_REQUEST_RF_CH0 0xb +#define MESSAGE_REQUEST_RF_CH1 0xc +#define MESSAGE_REQUEST_RF_CH2 0xd + +/* USB registers */ +#define USB_REG4 0x604 + +#define DEVICE_INIT_COLD 0x0 /* cold init */ +#define DEVICE_INIT_RESET 0x1 /* reset init or Dx to D0 power remain */ +#define DEVICE_INIT_DXPL 0x2 /* Dx to D0 power lost init */ + +/* Device init */ +struct vnt_cmd_card_init { + u8 init_class; + u8 exist_sw_net_addr; + u8 sw_net_addr[6]; + u8 short_retry_limit; + u8 long_retry_limit; +}; + +struct vnt_rsp_card_init { + u8 status; + u8 net_addr[6]; + u8 rf_type; + u8 min_channel; + u8 max_channel; +}; + +/* USB */ + +/* + * Enum of context types for SendPacket + */ +enum { + CONTEXT_DATA_PACKET = 1, + CONTEXT_MGMT_PACKET, + CONTEXT_BEACON_PACKET +}; + +/* RCB (Receive Control Block) */ +struct vnt_rcb { + void *priv; + struct urb *urb; + struct sk_buff *skb; + int in_use; +}; + +/* used to track bulk out irps */ +struct vnt_usb_send_context { + void *priv; + struct sk_buff *skb; + struct urb *urb; + struct ieee80211_hdr *hdr; + unsigned int buf_len; + u32 frame_len; + u16 tx_hdr_size; + u16 tx_rate; + u8 type; + u8 pkt_no; + u8 pkt_type; + u8 need_ack; + u8 fb_option; + bool in_use; + unsigned char data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS]; +}; + +/* + * Structure to keep track of USB interrupt packets + */ +struct vnt_interrupt_buffer { + u8 *data_buf; + bool in_use; +}; + +/*++ NDIS related */ + +enum { + STATUS_SUCCESS = 0, + STATUS_FAILURE, + STATUS_RESOURCES, + STATUS_PENDING, +}; + +/* flags for options */ +#define DEVICE_FLAGS_UNPLUG BIT(0) +#define DEVICE_FLAGS_DISCONNECTED BIT(1) + +struct vnt_private { + /* mac80211 */ + struct ieee80211_hw *hw; + struct ieee80211_vif *vif; + u8 mac_hw; + /* netdev */ + struct usb_device *usb; + + u64 tsf_time; + u8 rx_rate; + + u32 rx_buf_sz; + int mc_list_count; + + spinlock_t lock; + struct mutex usb_lock; + + unsigned long flags; + + /* USB */ + struct urb *interrupt_urb; + u32 int_interval; + + /* Variables to track resources for the BULK In Pipe */ + struct vnt_rcb *rcb[CB_MAX_RX_DESC]; + u32 num_rcb; + + /* Variables to track resources for the BULK Out Pipe */ + struct vnt_usb_send_context *tx_context[CB_MAX_TX_DESC]; + u32 num_tx_context; + + /* Variables to track resources for the Interrupt In Pipe */ + struct vnt_interrupt_buffer int_buf; + + /* Version control */ + u16 firmware_version; + u8 local_id; + u8 rf_type; + u8 bb_rx_conf; + + struct vnt_cmd_card_init init_command; + struct vnt_rsp_card_init init_response; + u8 current_net_addr[ETH_ALEN] __aligned(2); + u8 permanent_net_addr[ETH_ALEN] __aligned(2); + + u8 exist_sw_net_addr; + + u64 current_tsf; + + /* 802.11 MAC specific */ + u32 current_rssi; + + /* Antenna Diversity */ + int tx_rx_ant_inv; + u32 rx_antenna_sel; + u8 rx_antenna_mode; + u8 tx_antenna_mode; + u8 radio_ctl; + + /* IFS & Cw */ + u32 sifs; /* Current SIFS */ + u32 difs; /* Current DIFS */ + u32 eifs; /* Current EIFS */ + u32 slot; /* Current SlotTime */ + + /* Rate */ + u8 bb_type; /* 0: 11A, 1:11B, 2:11G */ + u8 packet_type; /* 0:11a 1:11b 2:11gb 3:11ga */ + u32 basic_rates; + u8 top_ofdm_basic_rate; + u8 top_cck_basic_rate; + + u8 eeprom[EEP_MAX_CONTEXT_SIZE]; /*u32 alignment */ + + u8 preamble_type; + + /* For RF Power table */ + u8 cck_pwr; + u8 ofdm_pwr_g; + u8 ofdm_pwr_a; + u8 power; + u8 cck_pwr_tbl[14]; + u8 ofdm_pwr_tbl[14]; + u8 ofdm_a_pwr_tbl[42]; + + u16 current_rate; + u16 tx_rate_fb0; + u16 tx_rate_fb1; + + u8 short_retry_limit; + u8 long_retry_limit; + + enum nl80211_iftype op_mode; + + int short_slot_time; + + /* Power save */ + u16 current_aid; + + /* Beacon releated */ + u16 seq_counter; + + enum vnt_cmd_state command_state; + + enum vnt_cmd command; + + /* 802.11 counter */ + + enum vnt_cmd cmd_queue[CMD_Q_SIZE]; + u32 cmd_dequeue_idx; + u32 cmd_enqueue_idx; + u32 free_cmd_queue; + int cmd_running; + + unsigned long key_entry_inuse; + + u8 auto_fb_ctrl; + + /* For Update BaseBand VGA Gain Offset */ + u8 bb_vga[BB_VGA_LEVEL]; + + u8 bb_pre_ed_rssi; + u8 bb_pre_ed_index; + + /* command timer */ + struct delayed_work run_command_work; + + struct ieee80211_low_level_stats low_stats; +}; + +#define ADD_ONE_WITH_WRAP_AROUND(uVar, uModulo) { \ + if ((uVar) >= ((uModulo) - 1)) \ + (uVar) = 0; \ + else \ + (uVar)++; \ +} + +int vnt_init(struct vnt_private *priv); + +#endif diff --git a/kernel/drivers/staging/vt6656/dpc.c b/kernel/drivers/staging/vt6656/dpc.c new file mode 100644 index 000000000..e6367ed3b --- /dev/null +++ b/kernel/drivers/staging/vt6656/dpc.c @@ -0,0 +1,186 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: dpc.c + * + * Purpose: handle dpc rx functions + * + * Author: Lyndon Chen + * + * Date: May 20, 2003 + * + * Functions: + * + * Revision History: + * + */ + +#include "dpc.h" +#include "device.h" +#include "mac.h" +#include "baseband.h" +#include "rf.h" + +int vnt_rx_data(struct vnt_private *priv, struct vnt_rcb *ptr_rcb, + unsigned long bytes_received) +{ + struct ieee80211_hw *hw = priv->hw; + struct ieee80211_supported_band *sband; + struct sk_buff *skb; + struct ieee80211_rx_status rx_status = { 0 }; + struct ieee80211_hdr *hdr; + __le16 fc; + u8 *rsr, *new_rsr, *rssi, *frame; + __le64 *tsf_time; + u32 frame_size; + int ii, r; + u8 *rx_sts, *rx_rate, *sq, *sq_3; + u32 wbk_status; + u8 *skb_data; + u16 *pay_load_len; + u16 pay_load_with_padding; + u8 rate_idx = 0; + u8 rate[MAX_RATE] = {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108}; + long rx_dbm; + + skb = ptr_rcb->skb; + + /* [31:16]RcvByteCount ( not include 4-byte Status ) */ + wbk_status = *((u32 *)(skb->data)); + frame_size = wbk_status >> 16; + frame_size += 4; + + if (bytes_received != frame_size) { + dev_dbg(&priv->usb->dev, "------- WRONG Length 1\n"); + return false; + } + + if ((bytes_received > 2372) || (bytes_received <= 40)) { + /* Frame Size error drop this packet.*/ + dev_dbg(&priv->usb->dev, "------ WRONG Length 2\n"); + return false; + } + + skb_data = (u8 *)skb->data; + + rx_sts = skb_data+4; + rx_rate = skb_data+5; + + /* real Frame Size = USBframe_size -4WbkStatus - 4RxStatus */ + /* -8TSF - 4RSR - 4SQ3 - ?Padding */ + + /* if SQ3 the range is 24~27, if no SQ3 the range is 20~23 */ + + pay_load_len = (u16 *) (skb_data + 6); + + /*Fix hardware bug => PLCP_Length error */ + if (((bytes_received - (*pay_load_len)) > 27) || + ((bytes_received - (*pay_load_len)) < 24) || + (bytes_received < (*pay_load_len))) { + dev_dbg(&priv->usb->dev, "Wrong PLCP Length %x\n", + *pay_load_len); + return false; + } + + sband = hw->wiphy->bands[hw->conf.chandef.chan->band]; + + for (r = RATE_1M; r < MAX_RATE; r++) { + if (*rx_rate == rate[r]) + break; + } + + priv->rx_rate = r; + + for (ii = 0; ii < sband->n_bitrates; ii++) { + if (sband->bitrates[ii].hw_value == r) { + rate_idx = ii; + break; + } + } + + if (ii == sband->n_bitrates) { + dev_dbg(&priv->usb->dev, "Wrong RxRate %x\n", *rx_rate); + return false; + } + + pay_load_with_padding = ((*pay_load_len / 4) + + ((*pay_load_len % 4) ? 1 : 0)) * 4; + + tsf_time = (__le64 *)(skb_data + 8 + pay_load_with_padding); + + priv->tsf_time = le64_to_cpu(*tsf_time); + + if (priv->bb_type == BB_TYPE_11G) { + sq_3 = skb_data + 8 + pay_load_with_padding + 12; + sq = sq_3; + } else { + sq = skb_data + 8 + pay_load_with_padding + 8; + sq_3 = sq; + } + + new_rsr = skb_data + 8 + pay_load_with_padding + 9; + rssi = skb_data + 8 + pay_load_with_padding + 10; + + rsr = skb_data + 8 + pay_load_with_padding + 11; + if (*rsr & (RSR_IVLDTYP | RSR_IVLDLEN)) + return false; + + frame_size = *pay_load_len; + + vnt_rf_rssi_to_dbm(priv, *rssi, &rx_dbm); + + priv->bb_pre_ed_rssi = (u8)rx_dbm + 1; + priv->current_rssi = priv->bb_pre_ed_rssi; + + frame = skb_data + 8; + + skb_pull(skb, 8); + skb_trim(skb, frame_size); + + rx_status.mactime = priv->tsf_time; + rx_status.band = hw->conf.chandef.chan->band; + rx_status.signal = rx_dbm; + rx_status.flag = 0; + rx_status.freq = hw->conf.chandef.chan->center_freq; + + if (!(*rsr & RSR_CRCOK)) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + + hdr = (struct ieee80211_hdr *)(skb->data); + fc = hdr->frame_control; + + rx_status.rate_idx = rate_idx; + + if (ieee80211_has_protected(fc)) { + if (priv->local_id > REV_ID_VT3253_A1) { + rx_status.flag |= RX_FLAG_DECRYPTED; + + /* Drop packet */ + if (!(*new_rsr & NEWRSR_DECRYPTOK)) { + dev_kfree_skb(skb); + return true; + } + } + } + + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + + ieee80211_rx_irqsafe(priv->hw, skb); + + return true; +} diff --git a/kernel/drivers/staging/vt6656/dpc.h b/kernel/drivers/staging/vt6656/dpc.h new file mode 100644 index 000000000..95e0e83a4 --- /dev/null +++ b/kernel/drivers/staging/vt6656/dpc.h @@ -0,0 +1,37 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: dpc.h + * + * Purpose: + * + * Author: Jerry Chen + * + * Date: Jun. 27, 2002 + * + */ + +#ifndef __DPC_H__ +#define __DPC_H__ + +#include "device.h" + +int vnt_rx_data(struct vnt_private *, struct vnt_rcb *, + unsigned long bytes_received); + +#endif /* __RXTX_H__ */ diff --git a/kernel/drivers/staging/vt6656/firmware.c b/kernel/drivers/staging/vt6656/firmware.c new file mode 100644 index 000000000..d440f284b --- /dev/null +++ b/kernel/drivers/staging/vt6656/firmware.c @@ -0,0 +1,141 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: baseband.c + * + * Purpose: Implement functions to access baseband + * + * Author: Yiching Chen + * + * Date: May 20, 2004 + * + * Functions: + * + * Revision History: + * + */ + +#include <linux/compiler.h> +#include "firmware.h" +#include "usbpipe.h" + +#define FIRMWARE_VERSION 0x133 /* version 1.51 */ +#define FIRMWARE_NAME "vntwusb.fw" + +#define FIRMWARE_CHUNK_SIZE 0x400 + +int vnt_download_firmware(struct vnt_private *priv) +{ + struct device *dev = &priv->usb->dev; + const struct firmware *fw; + int status; + void *buffer = NULL; + bool result = false; + u16 length; + int ii, rc; + + dev_dbg(dev, "---->Download firmware\n"); + + rc = request_firmware(&fw, FIRMWARE_NAME, dev); + if (rc) { + dev_err(dev, "firmware file %s request failed (%d)\n", + FIRMWARE_NAME, rc); + goto out; + } + + buffer = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL); + if (!buffer) + goto free_fw; + + for (ii = 0; ii < fw->size; ii += FIRMWARE_CHUNK_SIZE) { + length = min_t(int, fw->size - ii, FIRMWARE_CHUNK_SIZE); + memcpy(buffer, fw->data + ii, length); + + status = vnt_control_out(priv, + 0, + 0x1200+ii, + 0x0000, + length, + buffer); + + dev_dbg(dev, "Download firmware...%d %zu\n", ii, fw->size); + + if (status != STATUS_SUCCESS) + goto free_fw; + } + + result = true; +free_fw: + release_firmware(fw); + +out: + kfree(buffer); + + return result; +} +MODULE_FIRMWARE(FIRMWARE_NAME); + +int vnt_firmware_branch_to_sram(struct vnt_private *priv) +{ + int status; + + dev_dbg(&priv->usb->dev, "---->Branch to Sram\n"); + + status = vnt_control_out(priv, + 1, + 0x1200, + 0x0000, + 0, + NULL); + return status == STATUS_SUCCESS; +} + +int vnt_check_firmware_version(struct vnt_private *priv) +{ + int status; + + status = vnt_control_in(priv, + MESSAGE_TYPE_READ, + 0, + MESSAGE_REQUEST_VERSION, + 2, + (u8 *)&priv->firmware_version); + + dev_dbg(&priv->usb->dev, "Firmware Version [%04x]\n", + priv->firmware_version); + + if (status != STATUS_SUCCESS) { + dev_dbg(&priv->usb->dev, "Firmware Invalid.\n"); + return false; + } + if (priv->firmware_version == 0xFFFF) { + dev_dbg(&priv->usb->dev, "In Loader.\n"); + return false; + } + + dev_dbg(&priv->usb->dev, "Firmware Version [%04x]\n", + priv->firmware_version); + + if (priv->firmware_version < FIRMWARE_VERSION) { + /* branch to loader for download new firmware */ + vnt_firmware_branch_to_sram(priv); + return false; + } + return true; +} diff --git a/kernel/drivers/staging/vt6656/firmware.h b/kernel/drivers/staging/vt6656/firmware.h new file mode 100644 index 000000000..d594dbe1c --- /dev/null +++ b/kernel/drivers/staging/vt6656/firmware.h @@ -0,0 +1,39 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: firmware.h + * + * Purpose: Version and Release Information + * + * Author: Yiching Chen + * + * Date: May 20, 2004 + * + */ + +#ifndef __FIRMWARE_H__ +#define __FIRMWARE_H__ + +#include "device.h" + +int vnt_download_firmware(struct vnt_private *); +int vnt_firmware_branch_to_sram(struct vnt_private *); +int vnt_check_firmware_version(struct vnt_private *); + +#endif /* __FIRMWARE_H__ */ diff --git a/kernel/drivers/staging/vt6656/int.c b/kernel/drivers/staging/vt6656/int.c new file mode 100644 index 000000000..2ef70e470 --- /dev/null +++ b/kernel/drivers/staging/vt6656/int.c @@ -0,0 +1,166 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: int.c + * + * Purpose: Handle USB interrupt endpoint + * + * Author: Jerry Chen + * + * Date: Apr. 2, 2004 + * + * Functions: + * + * Revision History: + * 04-02-2004 Jerry Chen: Initial release + * + */ + +#include "int.h" +#include "mac.h" +#include "power.h" +#include "usbpipe.h" + +static const u8 fallback_rate0[5][5] = { + {RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M}, + {RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M}, + {RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M}, + {RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M}, + {RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M} +}; + +static const u8 fallback_rate1[5][5] = { + {RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M}, + {RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M}, + {RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M}, + {RATE_48M, RATE_48M, RATE_24M, RATE_12M, RATE_12M}, + {RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M} +}; + +void vnt_int_start_interrupt(struct vnt_private *priv) +{ + unsigned long flags; + int status; + + dev_dbg(&priv->usb->dev, "---->Interrupt Polling Thread\n"); + + spin_lock_irqsave(&priv->lock, flags); + + status = vnt_start_interrupt_urb(priv); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int vnt_int_report_rate(struct vnt_private *priv, u8 pkt_no, u8 tsr) +{ + struct vnt_usb_send_context *context; + struct ieee80211_tx_info *info; + struct ieee80211_rate *rate; + u8 tx_retry = (tsr & 0xf0) >> 4; + s8 idx; + + if (pkt_no >= priv->num_tx_context) + return -EINVAL; + + context = priv->tx_context[pkt_no]; + + if (!context->skb) + return -EINVAL; + + info = IEEE80211_SKB_CB(context->skb); + idx = info->control.rates[0].idx; + + if (context->fb_option && !(tsr & (TSR_TMO | TSR_RETRYTMO))) { + u8 tx_rate; + u8 retry = tx_retry; + + rate = ieee80211_get_tx_rate(priv->hw, info); + tx_rate = rate->hw_value - RATE_18M; + + if (retry > 4) + retry = 4; + + if (context->fb_option == AUTO_FB_0) + tx_rate = fallback_rate0[tx_rate][retry]; + else if (context->fb_option == AUTO_FB_1) + tx_rate = fallback_rate1[tx_rate][retry]; + + if (info->band == IEEE80211_BAND_5GHZ) + idx = tx_rate - RATE_6M; + else + idx = tx_rate; + } + + ieee80211_tx_info_clear_status(info); + + info->status.rates[0].count = tx_retry; + + if (!(tsr & (TSR_TMO | TSR_RETRYTMO))) { + info->status.rates[0].idx = idx; + info->flags |= IEEE80211_TX_STAT_ACK; + } + + ieee80211_tx_status_irqsafe(priv->hw, context->skb); + + context->in_use = false; + + return 0; +} + +void vnt_int_process_data(struct vnt_private *priv) +{ + struct vnt_interrupt_data *int_data; + struct ieee80211_low_level_stats *low_stats = &priv->low_stats; + + dev_dbg(&priv->usb->dev, "---->s_nsInterruptProcessData\n"); + + int_data = (struct vnt_interrupt_data *)priv->int_buf.data_buf; + + if (int_data->tsr0 & TSR_VALID) + vnt_int_report_rate(priv, int_data->pkt0, int_data->tsr0); + + if (int_data->tsr1 & TSR_VALID) + vnt_int_report_rate(priv, int_data->pkt1, int_data->tsr1); + + if (int_data->tsr2 & TSR_VALID) + vnt_int_report_rate(priv, int_data->pkt2, int_data->tsr2); + + if (int_data->tsr3 & TSR_VALID) + vnt_int_report_rate(priv, int_data->pkt3, int_data->tsr3); + + if (int_data->isr0 != 0) { + if (int_data->isr0 & ISR_BNTX && + priv->op_mode == NL80211_IFTYPE_AP) + vnt_schedule_command(priv, WLAN_CMD_BECON_SEND); + + if (int_data->isr0 & ISR_TBTT) { + if (priv->hw->conf.flags & IEEE80211_CONF_PS) + vnt_schedule_command(priv, + WLAN_CMD_TBTT_WAKEUP); + } + priv->current_tsf = le64_to_cpu(int_data->tsf); + + low_stats->dot11RTSSuccessCount += int_data->rts_success; + low_stats->dot11RTSFailureCount += int_data->rts_fail; + low_stats->dot11ACKFailureCount += int_data->ack_fail; + low_stats->dot11FCSErrorCount += int_data->fcs_err; + } + + priv->int_buf.in_use = false; +} diff --git a/kernel/drivers/staging/vt6656/int.h b/kernel/drivers/staging/vt6656/int.h new file mode 100644 index 000000000..154605c63 --- /dev/null +++ b/kernel/drivers/staging/vt6656/int.h @@ -0,0 +1,61 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: int.h + * + * Purpose: + * + * Author: Jerry Chen + * + * Date: Apr. 2, 2004 + * + */ + +#ifndef __INT_H__ +#define __INT_H__ + +#include "device.h" + +struct vnt_interrupt_data { + u8 tsr0; + u8 pkt0; + u16 time0; + u8 tsr1; + u8 pkt1; + u16 time1; + u8 tsr2; + u8 pkt2; + u16 time2; + u8 tsr3; + u8 pkt3; + u16 time3; + __le64 tsf; + u8 isr0; + u8 isr1; + u8 rts_success; + u8 rts_fail; + u8 ack_fail; + u8 fcs_err; + u8 sw[2]; +} __packed; + +void vnt_int_start_interrupt(struct vnt_private *); +void vnt_int_process_data(struct vnt_private *); + +#endif /* __INT_H__ */ diff --git a/kernel/drivers/staging/vt6656/key.c b/kernel/drivers/staging/vt6656/key.c new file mode 100644 index 000000000..181745d8e --- /dev/null +++ b/kernel/drivers/staging/vt6656/key.c @@ -0,0 +1,179 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: key.c + * + * Purpose: Implement functions for 802.11i Key management + * + * Author: Jerry Chen + * + * Date: May 29, 2003 + * + * Functions: + * + * Revision History: + * + */ + +#include "mac.h" +#include "key.h" +#include "usbpipe.h" + +int vnt_key_init_table(struct vnt_private *priv) +{ + u8 i; + u8 data[MAX_KEY_TABLE]; + + for (i = 0; i < MAX_KEY_TABLE; i++) + data[i] = i; + + return vnt_control_out(priv, MESSAGE_TYPE_CLRKEYENTRY, + 0, 0, ARRAY_SIZE(data), data); +} + +static int vnt_set_keymode(struct ieee80211_hw *hw, u8 *mac_addr, + struct ieee80211_key_conf *key, u32 key_type, u32 mode, + bool onfly_latch) +{ + struct vnt_private *priv = hw->priv; + u8 broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u16 key_mode = 0; + u32 entry = 0; + u8 *bssid; + u8 key_inx = key->keyidx; + u8 i; + + if (mac_addr) + bssid = mac_addr; + else + bssid = &broadcast[0]; + + if (key_type != VNT_KEY_DEFAULTKEY) { + for (i = 0; i < (MAX_KEY_TABLE - 1); i++) { + if (!test_bit(i, &priv->key_entry_inuse)) { + set_bit(i, &priv->key_entry_inuse); + + key->hw_key_idx = i; + entry = key->hw_key_idx; + break; + } + } + } + + switch (key_type) { + /* fallthrough */ + case VNT_KEY_DEFAULTKEY: + /* default key last entry */ + entry = MAX_KEY_TABLE - 1; + key->hw_key_idx = entry; + case VNT_KEY_ALLGROUP: + key_mode |= VNT_KEY_ALLGROUP; + if (onfly_latch) + key_mode |= VNT_KEY_ONFLY_ALL; + case VNT_KEY_GROUP_ADDRESS: + key_mode |= mode; + case VNT_KEY_GROUP: + key_mode |= (mode << 4); + key_mode |= VNT_KEY_GROUP; + break; + case VNT_KEY_PAIRWISE: + key_mode |= mode; + key_inx = 4; + /* Don't save entry for pairwise key for station mode */ + if (priv->op_mode == NL80211_IFTYPE_STATION) + clear_bit(entry, &priv->key_entry_inuse); + break; + default: + return -EINVAL; + } + + if (onfly_latch) + key_mode |= VNT_KEY_ONFLY; + + if (mode == KEY_CTL_WEP) { + if (key->keylen == WLAN_KEY_LEN_WEP40) + key->key[15] &= 0x7f; + if (key->keylen == WLAN_KEY_LEN_WEP104) + key->key[15] |= 0x80; + } + + vnt_mac_set_keyentry(priv, key_mode, entry, key_inx, bssid, key->key); + + return 0; +} + +int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + struct ieee80211_vif *vif, struct ieee80211_key_conf *key) +{ + struct ieee80211_bss_conf *conf = &vif->bss_conf; + struct vnt_private *priv = hw->priv; + u8 *mac_addr = NULL; + u8 key_dec_mode = 0; + int ret = 0, u; + + if (sta) + mac_addr = &sta->addr[0]; + + switch (key->cipher) { + case 0: + for (u = 0 ; u < MAX_KEY_TABLE; u++) + vnt_mac_disable_keyentry(priv, u); + return ret; + + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + for (u = 0; u < MAX_KEY_TABLE; u++) + vnt_mac_disable_keyentry(priv, u); + + vnt_set_keymode(hw, mac_addr, key, VNT_KEY_DEFAULTKEY, + KEY_CTL_WEP, true); + + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + + return ret; + case WLAN_CIPHER_SUITE_TKIP: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + + key_dec_mode = KEY_CTL_TKIP; + + break; + case WLAN_CIPHER_SUITE_CCMP: + if (priv->local_id <= MAC_REVISION_A1) + return -EINVAL; + + key_dec_mode = KEY_CTL_CCMP; + + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + vnt_set_keymode(hw, mac_addr, key, VNT_KEY_PAIRWISE, + key_dec_mode, true); + } else { + vnt_set_keymode(hw, mac_addr, key, VNT_KEY_DEFAULTKEY, + key_dec_mode, true); + + vnt_set_keymode(hw, (u8 *)conf->bssid, key, + VNT_KEY_GROUP_ADDRESS, key_dec_mode, true); + } + + return 0; +} diff --git a/kernel/drivers/staging/vt6656/key.h b/kernel/drivers/staging/vt6656/key.h new file mode 100644 index 000000000..3cb129105 --- /dev/null +++ b/kernel/drivers/staging/vt6656/key.h @@ -0,0 +1,55 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: key.h + * + * Purpose: Implement functions for 802.11i Key management + * + * Author: Jerry Chen + * + * Date: May 29, 2003 + * + */ + +#ifndef __KEY_H__ +#define __KEY_H__ + +#include "device.h" + +#define MAX_KEY_TABLE 11 + +#define KEY_CTL_WEP 0x00 +#define KEY_CTL_NONE 0x01 +#define KEY_CTL_TKIP 0x02 +#define KEY_CTL_CCMP 0x03 + +#define VNT_KEY_DEFAULTKEY 0x1 +#define VNT_KEY_GROUP_ADDRESS 0x2 +#define VNT_KEY_ALLGROUP 0x4 +#define VNT_KEY_GROUP 0x40 +#define VNT_KEY_PAIRWISE 0x00 +#define VNT_KEY_ONFLY 0x8000 +#define VNT_KEY_ONFLY_ALL 0x4000 + +int vnt_key_init_table(struct vnt_private *); + +int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + struct ieee80211_vif *vif, struct ieee80211_key_conf *key); + +#endif /* __KEY_H__ */ diff --git a/kernel/drivers/staging/vt6656/mac.c b/kernel/drivers/staging/vt6656/mac.c new file mode 100644 index 000000000..5dfac05b9 --- /dev/null +++ b/kernel/drivers/staging/vt6656/mac.c @@ -0,0 +1,248 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: mac.c + * + * Purpose: MAC routines + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + * Functions: + * + * Revision History: + */ + +#include <linux/etherdevice.h> + +#include "desc.h" +#include "mac.h" +#include "usbpipe.h" + +/* + * Description: + * Write MAC Multicast Address Mask + * + * Parameters: + * In: + * mc_filter (mac filter) + * Out: + * none + * + * Return Value: none + * + */ +void vnt_mac_set_filter(struct vnt_private *priv, u64 mc_filter) +{ + __le64 le_mc = cpu_to_le64(mc_filter); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_MAR0, + MESSAGE_REQUEST_MACREG, sizeof(le_mc), (u8 *)&le_mc); +} + +/* + * Description: + * Shut Down MAC + * + * Parameters: + * In: + * Out: + * none + * + * + */ +void vnt_mac_shutdown(struct vnt_private *priv) +{ + vnt_control_out(priv, MESSAGE_TYPE_MACSHUTDOWN, 0, 0, 0, NULL); +} + +void vnt_mac_set_bb_type(struct vnt_private *priv, u8 type) +{ + u8 data[2]; + + data[0] = type; + data[1] = EnCFG_BBType_MASK; + + vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG0, + MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} + +/* + * Description: + * Disable the Key Entry by MISCFIFO + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * + * Out: + * none + * + * Return Value: none + * + */ +void vnt_mac_disable_keyentry(struct vnt_private *priv, u8 entry_idx) +{ + vnt_control_out(priv, MESSAGE_TYPE_CLRKEYENTRY, 0, 0, + sizeof(entry_idx), &entry_idx); +} + +/* + * Description: + * Set the Key by MISCFIFO + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * + * Out: + * none + * + * Return Value: none + * + */ +void vnt_mac_set_keyentry(struct vnt_private *priv, u16 key_ctl, u32 entry_idx, + u32 key_idx, u8 *addr, u8 *key) +{ + struct vnt_mac_set_key set_key; + u16 offset; + + offset = MISCFIFO_KEYETRY0; + offset += (entry_idx * MISCFIFO_KEYENTRYSIZE); + + set_key.u.write.key_ctl = cpu_to_le16(key_ctl); + ether_addr_copy(set_key.u.write.addr, addr); + + /* swap over swap[0] and swap[1] to get correct write order */ + swap(set_key.u.swap[0], set_key.u.swap[1]); + + memcpy(set_key.key, key, WLAN_KEY_LEN_CCMP); + + dev_dbg(&priv->usb->dev, "offset %d key ctl %d set key %24ph\n", + offset, key_ctl, (u8 *)&set_key); + + vnt_control_out(priv, MESSAGE_TYPE_SETKEY, offset, + (u16)key_idx, sizeof(struct vnt_mac_set_key), (u8 *)&set_key); +} + +void vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits) +{ + u8 data[2]; + + data[0] = 0; + data[1] = bits; + + vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, + reg_ofs, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} + +void vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits) +{ + u8 data[2]; + + data[0] = bits; + data[1] = bits; + + vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, + reg_ofs, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} + +void vnt_mac_write_word(struct vnt_private *priv, u8 reg_ofs, u16 word) +{ + u8 data[2]; + + data[0] = (u8)(word & 0xff); + data[1] = (u8)(word >> 8); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, + reg_ofs, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} + +void vnt_mac_set_bssid_addr(struct vnt_private *priv, u8 *addr) +{ + vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_BSSID0, + MESSAGE_REQUEST_MACREG, ETH_ALEN, addr); +} + +void vnt_mac_enable_protect_mode(struct vnt_private *priv) +{ + u8 data[2]; + + data[0] = EnCFG_ProtectMd; + data[1] = EnCFG_ProtectMd; + + vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, + MAC_REG_ENCFG0, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} + +void vnt_mac_disable_protect_mode(struct vnt_private *priv) +{ + u8 data[2]; + + data[0] = 0; + data[1] = EnCFG_ProtectMd; + + vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, + MAC_REG_ENCFG0, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} + +void vnt_mac_enable_barker_preamble_mode(struct vnt_private *priv) +{ + u8 data[2]; + + data[0] = EnCFG_BarkerPream; + data[1] = EnCFG_BarkerPream; + + vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, + MAC_REG_ENCFG2, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} + +void vnt_mac_disable_barker_preamble_mode(struct vnt_private *priv) +{ + u8 data[2]; + + data[0] = 0; + data[1] = EnCFG_BarkerPream; + + vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, + MAC_REG_ENCFG2, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} + +void vnt_mac_set_beacon_interval(struct vnt_private *priv, u16 interval) +{ + u8 data[2]; + + data[0] = (u8)(interval & 0xff); + data[1] = (u8)(interval >> 8); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, + MAC_REG_BI, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} + +void vnt_mac_set_led(struct vnt_private *priv, u8 state, u8 led) +{ + u8 data[2]; + + data[0] = led; + data[1] = state; + + vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_PAPEDELAY, + MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); +} diff --git a/kernel/drivers/staging/vt6656/mac.h b/kernel/drivers/staging/vt6656/mac.h new file mode 100644 index 000000000..d53fcef87 --- /dev/null +++ b/kernel/drivers/staging/vt6656/mac.h @@ -0,0 +1,387 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: mac.h + * + * Purpose: MAC routines + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + * Revision History: + * 07-01-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. + * 08-25-2003 Kyle Hsu: Porting MAC functions from sim53. + * 09-03-2003 Bryan YC Fan: Add MACvDisableProtectMD & MACvEnableProtectMD + */ + +#ifndef __MAC_H__ +#define __MAC_H__ + +#include "device.h" + +#define REV_ID_VT3253_A0 0x00 +#define REV_ID_VT3253_A1 0x01 +#define REV_ID_VT3253_B0 0x08 +#define REV_ID_VT3253_B1 0x09 + +/* Registers in the MAC */ +#define MAC_REG_BISTCMD 0x04 +#define MAC_REG_BISTSR0 0x05 +#define MAC_REG_BISTSR1 0x06 +#define MAC_REG_BISTSR2 0x07 +#define MAC_REG_I2MCSR 0x08 +#define MAC_REG_I2MTGID 0x09 +#define MAC_REG_I2MTGAD 0x0a +#define MAC_REG_I2MCFG 0x0b +#define MAC_REG_I2MDIPT 0x0c +#define MAC_REG_I2MDOPT 0x0e +#define MAC_REG_USBSUS 0x0f + +#define MAC_REG_LOCALID 0x14 +#define MAC_REG_TESTCFG 0x15 +#define MAC_REG_JUMPER0 0x16 +#define MAC_REG_JUMPER1 0x17 +#define MAC_REG_TMCTL 0x18 +#define MAC_REG_TMDATA0 0x1c +#define MAC_REG_TMDATA1 0x1d +#define MAC_REG_TMDATA2 0x1e +#define MAC_REG_TMDATA3 0x1f + +/* MAC Parameter related */ +#define MAC_REG_LRT 0x20 +#define MAC_REG_SRT 0x21 +#define MAC_REG_SIFS 0x22 +#define MAC_REG_DIFS 0x23 +#define MAC_REG_EIFS 0x24 +#define MAC_REG_SLOT 0x25 +#define MAC_REG_BI 0x26 +#define MAC_REG_CWMAXMIN0 0x28 +#define MAC_REG_LINKOFFTOTM 0x2a +#define MAC_REG_SWTMOT 0x2b +#define MAC_REG_RTSOKCNT 0x2c +#define MAC_REG_RTSFAILCNT 0x2d +#define MAC_REG_ACKFAILCNT 0x2e +#define MAC_REG_FCSERRCNT 0x2f + +/* TSF Related */ +#define MAC_REG_TSFCNTR 0x30 +#define MAC_REG_NEXTTBTT 0x38 +#define MAC_REG_TSFOFST 0x40 +#define MAC_REG_TFTCTL 0x48 + +/* WMAC Control/Status Related */ +#define MAC_REG_ENCFG0 0x4c +#define MAC_REG_ENCFG1 0x4d +#define MAC_REG_ENCFG2 0x4e + +#define MAC_REG_CFG 0x50 +#define MAC_REG_TEST 0x52 +#define MAC_REG_HOSTCR 0x54 +#define MAC_REG_MACCR 0x55 +#define MAC_REG_RCR 0x56 +#define MAC_REG_TCR 0x57 +#define MAC_REG_IMR 0x58 +#define MAC_REG_ISR 0x5c +#define MAC_REG_ISR1 0x5d + +/* Power Saving Related */ +#define MAC_REG_PSCFG 0x60 +#define MAC_REG_PSCTL 0x61 +#define MAC_REG_PSPWRSIG 0x62 +#define MAC_REG_BBCR13 0x63 +#define MAC_REG_AIDATIM 0x64 +#define MAC_REG_PWBT 0x66 +#define MAC_REG_WAKEOKTMR 0x68 +#define MAC_REG_CALTMR 0x69 +#define MAC_REG_SYNSPACCNT 0x6a +#define MAC_REG_WAKSYNOPT 0x6b + +/* Baseband/IF Control Group */ +#define MAC_REG_BBREGCTL 0x6c +#define MAC_REG_CHANNEL 0x6d +#define MAC_REG_BBREGADR 0x6e +#define MAC_REG_BBREGDATA 0x6f +#define MAC_REG_IFREGCTL 0x70 +#define MAC_REG_IFDATA 0x71 +#define MAC_REG_ITRTMSET 0x74 +#define MAC_REG_PAPEDELAY 0x77 +#define MAC_REG_SOFTPWRCTL 0x78 +#define MAC_REG_SOFTPWRCTL2 0x79 +#define MAC_REG_GPIOCTL0 0x7a +#define MAC_REG_GPIOCTL1 0x7b + +/* MiscFF PIO related */ +#define MAC_REG_MISCFFNDEX 0xbc +#define MAC_REG_MISCFFCTL 0xbe +#define MAC_REG_MISCFFDATA 0xc0 + +/* MAC Configuration Group */ +#define MAC_REG_PAR0 0xc4 +#define MAC_REG_PAR4 0xc8 +#define MAC_REG_BSSID0 0xcc +#define MAC_REG_BSSID4 0xd0 +#define MAC_REG_MAR0 0xd4 +#define MAC_REG_MAR4 0xd8 + +/* MAC RSPPKT INFO Group */ +#define MAC_REG_RSPINF_B_1 0xdC +#define MAC_REG_RSPINF_B_2 0xe0 +#define MAC_REG_RSPINF_B_5 0xe4 +#define MAC_REG_RSPINF_B_11 0xe8 +#define MAC_REG_RSPINF_A_6 0xec +#define MAC_REG_RSPINF_A_9 0xee +#define MAC_REG_RSPINF_A_12 0xf0 +#define MAC_REG_RSPINF_A_18 0xf2 +#define MAC_REG_RSPINF_A_24 0xf4 +#define MAC_REG_RSPINF_A_36 0xf6 +#define MAC_REG_RSPINF_A_48 0xf8 +#define MAC_REG_RSPINF_A_54 0xfa +#define MAC_REG_RSPINF_A_72 0xfc + +/* Bits in the I2MCFG EEPROM register */ +#define I2MCFG_BOUNDCTL 0x80 +#define I2MCFG_WAITCTL 0x20 +#define I2MCFG_SCLOECTL 0x10 +#define I2MCFG_WBUSYCTL 0x08 +#define I2MCFG_NORETRY 0x04 +#define I2MCFG_I2MLDSEQ 0x02 +#define I2MCFG_I2CMFAST 0x01 + +/* Bits in the I2MCSR EEPROM register */ +#define I2MCSR_EEMW 0x80 +#define I2MCSR_EEMR 0x40 +#define I2MCSR_AUTOLD 0x08 +#define I2MCSR_NACK 0x02 +#define I2MCSR_DONE 0x01 + +/* Bits in the TMCTL register */ +#define TMCTL_TSUSP 0x04 +#define TMCTL_TMD 0x02 +#define TMCTL_TE 0x01 + +/* Bits in the TFTCTL register */ +#define TFTCTL_HWUTSF 0x80 +#define TFTCTL_TBTTSYNC 0x40 +#define TFTCTL_HWUTSFEN 0x20 +#define TFTCTL_TSFCNTRRD 0x10 +#define TFTCTL_TBTTSYNCEN 0x08 +#define TFTCTL_TSFSYNCEN 0x04 +#define TFTCTL_TSFCNTRST 0x02 +#define TFTCTL_TSFCNTREN 0x01 + +/* Bits in the EnhanceCFG_0 register */ +#define EnCFG_BBType_a 0x00 +#define EnCFG_BBType_b 0x01 +#define EnCFG_BBType_g 0x02 +#define EnCFG_BBType_MASK 0x03 +#define EnCFG_ProtectMd 0x20 + +/* Bits in the EnhanceCFG_1 register */ +#define EnCFG_BcnSusInd 0x01 +#define EnCFG_BcnSusClr 0x02 + +/* Bits in the EnhanceCFG_2 register */ +#define EnCFG_NXTBTTCFPSTR 0x01 +#define EnCFG_BarkerPream 0x02 +#define EnCFG_PktBurstMode 0x04 + +/* Bits in the CFG register */ +#define CFG_TKIPOPT 0x80 +#define CFG_RXDMAOPT 0x40 +#define CFG_TMOT_SW 0x20 +#define CFG_TMOT_HWLONG 0x10 +#define CFG_TMOT_HW 0x00 +#define CFG_CFPENDOPT 0x08 +#define CFG_BCNSUSEN 0x04 +#define CFG_NOTXTIMEOUT 0x02 +#define CFG_NOBUFOPT 0x01 + +/* Bits in the TEST register */ +#define TEST_LBEXT 0x80 +#define TEST_LBINT 0x40 +#define TEST_LBNONE 0x00 +#define TEST_SOFTINT 0x20 +#define TEST_CONTTX 0x10 +#define TEST_TXPE 0x08 +#define TEST_NAVDIS 0x04 +#define TEST_NOCTS 0x02 +#define TEST_NOACK 0x01 + +/* Bits in the HOSTCR register */ +#define HOSTCR_TXONST 0x80 +#define HOSTCR_RXONST 0x40 +#define HOSTCR_ADHOC 0x20 +#define HOSTCR_AP 0x10 +#define HOSTCR_TXON 0x08 +#define HOSTCR_RXON 0x04 +#define HOSTCR_MACEN 0x02 +#define HOSTCR_SOFTRST 0x01 + +/* Bits in the MACCR register */ +#define MACCR_SYNCFLUSHOK 0x04 +#define MACCR_SYNCFLUSH 0x02 +#define MACCR_CLRNAV 0x01 + +/* Bits in the RCR register */ +#define RCR_SSID 0x80 +#define RCR_RXALLTYPE 0x40 +#define RCR_UNICAST 0x20 +#define RCR_BROADCAST 0x10 +#define RCR_MULTICAST 0x08 +#define RCR_WPAERR 0x04 +#define RCR_ERRCRC 0x02 +#define RCR_BSSID 0x01 + +/* Bits in the TCR register */ +#define TCR_SYNCDCFOPT 0x02 +#define TCR_AUTOBCNTX 0x01 + +/* ISR1 */ +#define ISR_GPIO3 0x40 +#define ISR_RXNOBUF 0x08 +#define ISR_MIBNEARFULL 0x04 +#define ISR_SOFTINT 0x02 +#define ISR_FETALERR 0x01 + +#define LEDSTS_STS 0x06 +#define LEDSTS_TMLEN 0x78 +#define LEDSTS_OFF 0x00 +#define LEDSTS_ON 0x02 +#define LEDSTS_SLOW 0x04 +#define LEDSTS_INTER 0x06 + +/* ISR0 */ +#define ISR_WATCHDOG 0x80 +#define ISR_SOFTTIMER 0x40 +#define ISR_GPIO0 0x20 +#define ISR_TBTT 0x10 +#define ISR_RXDMA0 0x08 +#define ISR_BNTX 0x04 +#define ISR_ACTX 0x01 + +/* Bits in the PSCFG register */ +#define PSCFG_PHILIPMD 0x40 +#define PSCFG_WAKECALEN 0x20 +#define PSCFG_WAKETMREN 0x10 +#define PSCFG_BBPSPROG 0x08 +#define PSCFG_WAKESYN 0x04 +#define PSCFG_SLEEPSYN 0x02 +#define PSCFG_AUTOSLEEP 0x01 + +/* Bits in the PSCTL register */ +#define PSCTL_WAKEDONE 0x20 +#define PSCTL_PS 0x10 +#define PSCTL_GO2DOZE 0x08 +#define PSCTL_LNBCN 0x04 +#define PSCTL_ALBCN 0x02 +#define PSCTL_PSEN 0x01 + +/* Bits in the PSPWSIG register */ +#define PSSIG_WPE3 0x80 +#define PSSIG_WPE2 0x40 +#define PSSIG_WPE1 0x20 +#define PSSIG_WRADIOPE 0x10 +#define PSSIG_SPE3 0x08 +#define PSSIG_SPE2 0x04 +#define PSSIG_SPE1 0x02 +#define PSSIG_SRADIOPE 0x01 + +/* Bits in the BBREGCTL register */ +#define BBREGCTL_DONE 0x04 +#define BBREGCTL_REGR 0x02 +#define BBREGCTL_REGW 0x01 + +/* Bits in the IFREGCTL register */ +#define IFREGCTL_DONE 0x04 +#define IFREGCTL_IFRF 0x02 +#define IFREGCTL_REGW 0x01 + +/* Bits in the SOFTPWRCTL register */ +#define SOFTPWRCTL_RFLEOPT 0x08 +#define SOFTPWRCTL_TXPEINV 0x02 +#define SOFTPWRCTL_SWPECTI 0x01 +#define SOFTPWRCTL_SWPAPE 0x20 +#define SOFTPWRCTL_SWCALEN 0x10 +#define SOFTPWRCTL_SWRADIO_PE 0x08 +#define SOFTPWRCTL_SWPE2 0x04 +#define SOFTPWRCTL_SWPE1 0x02 +#define SOFTPWRCTL_SWPE3 0x01 + +/* Bits in the GPIOCTL1 register */ +#define GPIO3_MD 0x20 +#define GPIO3_DATA 0x40 +#define GPIO3_INTMD 0x80 + +/* Bits in the MISCFFCTL register */ +#define MISCFFCTL_WRITE 0x0001 + +/* Loopback mode */ +#define MAC_LB_EXT 0x02 +#define MAC_LB_INTERNAL 0x01 +#define MAC_LB_NONE 0x00 + +/* Ethernet address filter type */ +#define PKT_TYPE_NONE 0x00 /* turn off receiver */ +#define PKT_TYPE_ALL_MULTICAST 0x80 +#define PKT_TYPE_PROMISCUOUS 0x40 +#define PKT_TYPE_DIRECTED 0x20 /* obselete */ +#define PKT_TYPE_BROADCAST 0x10 +#define PKT_TYPE_MULTICAST 0x08 +#define PKT_TYPE_ERROR_WPA 0x04 +#define PKT_TYPE_ERROR_CRC 0x02 +#define PKT_TYPE_BSSID 0x01 + +#define Default_BI 0x200 + +/* MiscFIFO Offset */ +#define MISCFIFO_KEYETRY0 32 +#define MISCFIFO_KEYENTRYSIZE 22 + +#define MAC_REVISION_A0 0x00 +#define MAC_REVISION_A1 0x01 + +struct vnt_mac_set_key { + union { + struct { + u8 addr[ETH_ALEN]; + __le16 key_ctl; + } write __packed; + u32 swap[2]; + } u; + u8 key[WLAN_KEY_LEN_CCMP]; +} __packed; + +void vnt_mac_set_filter(struct vnt_private *, u64); +void vnt_mac_shutdown(struct vnt_private *); +void vnt_mac_set_bb_type(struct vnt_private *, u8); +void vnt_mac_disable_keyentry(struct vnt_private *, u8); +void vnt_mac_set_keyentry(struct vnt_private *, u16, u32, u32, u8 *, u8 *); +void vnt_mac_reg_bits_off(struct vnt_private *, u8, u8); +void vnt_mac_reg_bits_on(struct vnt_private *, u8, u8); +void vnt_mac_write_word(struct vnt_private *, u8, u16); +void vnt_mac_set_bssid_addr(struct vnt_private *, u8 *); +void vnt_mac_enable_protect_mode(struct vnt_private *); +void vnt_mac_disable_protect_mode(struct vnt_private *); +void vnt_mac_enable_barker_preamble_mode(struct vnt_private *); +void vnt_mac_disable_barker_preamble_mode(struct vnt_private *); +void vnt_mac_set_beacon_interval(struct vnt_private *, u16); +void vnt_mac_set_led(struct vnt_private *priv, u8, u8); + +#endif /* __MAC_H__ */ diff --git a/kernel/drivers/staging/vt6656/main_usb.c b/kernel/drivers/staging/vt6656/main_usb.c new file mode 100644 index 000000000..ab3ab84cb --- /dev/null +++ b/kernel/drivers/staging/vt6656/main_usb.c @@ -0,0 +1,1059 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: main_usb.c + * + * Purpose: driver entry for initial, open, close, tx and rx. + * + * Author: Lyndon Chen + * + * Date: Dec 8, 2005 + * + * Functions: + * + * vt6656_probe - module initial (insmod) driver entry + * vnt_free_tx_bufs - free tx buffer function + * vnt_init_registers- initial MAC & BBP & RF internal registers. + * + * Revision History: + */ +#undef __NO_VERSION__ + +#include <linux/etherdevice.h> +#include <linux/file.h> +#include "device.h" +#include "card.h" +#include "baseband.h" +#include "mac.h" +#include "power.h" +#include "wcmd.h" +#include "rxtx.h" +#include "dpc.h" +#include "rf.h" +#include "firmware.h" +#include "usbpipe.h" +#include "channel.h" +#include "int.h" + +/* + * define module options + */ + +/* version information */ +#define DRIVER_AUTHOR \ + "VIA Networking Technologies, Inc., <lyndonchen@vntek.com.tw>" +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DEVICE_FULL_DRV_NAM); + +#define RX_DESC_DEF0 64 +static int vnt_rx_buffers = RX_DESC_DEF0; +module_param_named(rx_buffers, vnt_rx_buffers, int, 0644); +MODULE_PARM_DESC(rx_buffers, "Number of receive usb rx buffers"); + +#define TX_DESC_DEF0 64 +static int vnt_tx_buffers = TX_DESC_DEF0; +module_param_named(tx_buffers, vnt_tx_buffers, int, 0644); +MODULE_PARM_DESC(tx_buffers, "Number of receive usb tx buffers"); + +#define RTS_THRESH_DEF 2347 +#define FRAG_THRESH_DEF 2346 +#define SHORT_RETRY_DEF 8 +#define LONG_RETRY_DEF 4 + +/* BasebandType[] baseband type selected + 0: indicate 802.11a type + 1: indicate 802.11b type + 2: indicate 802.11g type +*/ + +#define BBP_TYPE_DEF 2 + +/* + * Static vars definitions + */ + +static struct usb_device_id vt6656_table[] = { + {USB_DEVICE(VNT_USB_VENDOR_ID, VNT_USB_PRODUCT_ID)}, + {} +}; + +static void vnt_set_options(struct vnt_private *priv) +{ + /* Set number of TX buffers */ + if (vnt_tx_buffers < CB_MIN_TX_DESC || vnt_tx_buffers > CB_MAX_TX_DESC) + priv->num_tx_context = TX_DESC_DEF0; + else + priv->num_tx_context = vnt_tx_buffers; + + /* Set number of RX buffers */ + if (vnt_rx_buffers < CB_MIN_RX_DESC || vnt_rx_buffers > CB_MAX_RX_DESC) + priv->num_rcb = RX_DESC_DEF0; + else + priv->num_rcb = vnt_rx_buffers; + + priv->short_retry_limit = SHORT_RETRY_DEF; + priv->long_retry_limit = LONG_RETRY_DEF; + priv->op_mode = NL80211_IFTYPE_UNSPECIFIED; + priv->bb_type = BBP_TYPE_DEF; + priv->packet_type = priv->bb_type; + priv->auto_fb_ctrl = AUTO_FB_0; + priv->preamble_type = 0; + priv->exist_sw_net_addr = false; +} + +/* + * initialization of MAC & BBP registers + */ +static int vnt_init_registers(struct vnt_private *priv) +{ + struct vnt_cmd_card_init *init_cmd = &priv->init_command; + struct vnt_rsp_card_init *init_rsp = &priv->init_response; + u8 antenna; + int ii; + int status = STATUS_SUCCESS; + u8 tmp; + u8 calib_tx_iq = 0, calib_tx_dc = 0, calib_rx_iq = 0; + + dev_dbg(&priv->usb->dev, "---->INIbInitAdapter. [%d][%d]\n", + DEVICE_INIT_COLD, priv->packet_type); + + if (!vnt_check_firmware_version(priv)) { + if (vnt_download_firmware(priv) == true) { + if (vnt_firmware_branch_to_sram(priv) == false) { + dev_dbg(&priv->usb->dev, + " vnt_firmware_branch_to_sram fail\n"); + return false; + } + } else { + dev_dbg(&priv->usb->dev, "FIRMWAREbDownload fail\n"); + return false; + } + } + + if (!vnt_vt3184_init(priv)) { + dev_dbg(&priv->usb->dev, "vnt_vt3184_init fail\n"); + return false; + } + + init_cmd->init_class = DEVICE_INIT_COLD; + init_cmd->exist_sw_net_addr = priv->exist_sw_net_addr; + for (ii = 0; ii < 6; ii++) + init_cmd->sw_net_addr[ii] = priv->current_net_addr[ii]; + init_cmd->short_retry_limit = priv->short_retry_limit; + init_cmd->long_retry_limit = priv->long_retry_limit; + + /* issue card_init command to device */ + status = vnt_control_out(priv, + MESSAGE_TYPE_CARDINIT, 0, 0, + sizeof(struct vnt_cmd_card_init), (u8 *)init_cmd); + if (status != STATUS_SUCCESS) { + dev_dbg(&priv->usb->dev, "Issue Card init fail\n"); + return false; + } + + status = vnt_control_in(priv, MESSAGE_TYPE_INIT_RSP, 0, 0, + sizeof(struct vnt_rsp_card_init), (u8 *)init_rsp); + if (status != STATUS_SUCCESS) { + dev_dbg(&priv->usb->dev, + "Cardinit request in status fail!\n"); + return false; + } + + /* local ID for AES functions */ + status = vnt_control_in(priv, MESSAGE_TYPE_READ, + MAC_REG_LOCALID, MESSAGE_REQUEST_MACREG, 1, + &priv->local_id); + if (status != STATUS_SUCCESS) + return false; + + /* do MACbSoftwareReset in MACvInitialize */ + + priv->top_ofdm_basic_rate = RATE_24M; + priv->top_cck_basic_rate = RATE_1M; + + /* target to IF pin while programming to RF chip */ + priv->power = 0xFF; + + priv->cck_pwr = priv->eeprom[EEP_OFS_PWR_CCK]; + priv->ofdm_pwr_g = priv->eeprom[EEP_OFS_PWR_OFDMG]; + /* load power table */ + for (ii = 0; ii < 14; ii++) { + priv->cck_pwr_tbl[ii] = + priv->eeprom[ii + EEP_OFS_CCK_PWR_TBL]; + if (priv->cck_pwr_tbl[ii] == 0) + priv->cck_pwr_tbl[ii] = priv->cck_pwr; + + priv->ofdm_pwr_tbl[ii] = + priv->eeprom[ii + EEP_OFS_OFDM_PWR_TBL]; + if (priv->ofdm_pwr_tbl[ii] == 0) + priv->ofdm_pwr_tbl[ii] = priv->ofdm_pwr_g; + } + + /* + * original zonetype is USA, but custom zonetype is Europe, + * then need to recover 12, 13, 14 channels with 11 channel + */ + for (ii = 11; ii < 14; ii++) { + priv->cck_pwr_tbl[ii] = priv->cck_pwr_tbl[10]; + priv->ofdm_pwr_tbl[ii] = priv->ofdm_pwr_tbl[10]; + } + + priv->ofdm_pwr_a = 0x34; /* same as RFbMA2829SelectChannel */ + + /* load OFDM A power table */ + for (ii = 0; ii < CB_MAX_CHANNEL_5G; ii++) { + priv->ofdm_a_pwr_tbl[ii] = + priv->eeprom[ii + EEP_OFS_OFDMA_PWR_TBL]; + + if (priv->ofdm_a_pwr_tbl[ii] == 0) + priv->ofdm_a_pwr_tbl[ii] = priv->ofdm_pwr_a; + } + + antenna = priv->eeprom[EEP_OFS_ANTENNA]; + + if (antenna & EEP_ANTINV) + priv->tx_rx_ant_inv = true; + else + priv->tx_rx_ant_inv = false; + + antenna &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); + + if (antenna == 0) /* if not set default is both */ + antenna = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); + + if (antenna == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) { + priv->tx_antenna_mode = ANT_B; + priv->rx_antenna_sel = 1; + + if (priv->tx_rx_ant_inv == true) + priv->rx_antenna_mode = ANT_A; + else + priv->rx_antenna_mode = ANT_B; + } else { + priv->rx_antenna_sel = 0; + + if (antenna & EEP_ANTENNA_AUX) { + priv->tx_antenna_mode = ANT_A; + + if (priv->tx_rx_ant_inv == true) + priv->rx_antenna_mode = ANT_B; + else + priv->rx_antenna_mode = ANT_A; + } else { + priv->tx_antenna_mode = ANT_B; + + if (priv->tx_rx_ant_inv == true) + priv->rx_antenna_mode = ANT_A; + else + priv->rx_antenna_mode = ANT_B; + } + } + + /* Set initial antenna mode */ + vnt_set_antenna_mode(priv, priv->rx_antenna_mode); + + /* get Auto Fall Back type */ + priv->auto_fb_ctrl = AUTO_FB_0; + + /* default Auto Mode */ + priv->bb_type = BB_TYPE_11G; + + /* get RFType */ + priv->rf_type = init_rsp->rf_type; + + /* load vt3266 calibration parameters in EEPROM */ + if (priv->rf_type == RF_VT3226D0) { + if ((priv->eeprom[EEP_OFS_MAJOR_VER] == 0x1) && + (priv->eeprom[EEP_OFS_MINOR_VER] >= 0x4)) { + + calib_tx_iq = priv->eeprom[EEP_OFS_CALIB_TX_IQ]; + calib_tx_dc = priv->eeprom[EEP_OFS_CALIB_TX_DC]; + calib_rx_iq = priv->eeprom[EEP_OFS_CALIB_RX_IQ]; + if (calib_tx_iq || calib_tx_dc || calib_rx_iq) { + /* CR255, enable TX/RX IQ and + DC compensation mode */ + vnt_control_out_u8(priv, + MESSAGE_REQUEST_BBREG, + 0xff, + 0x03); + /* CR251, TX I/Q Imbalance Calibration */ + vnt_control_out_u8(priv, + MESSAGE_REQUEST_BBREG, + 0xfb, + calib_tx_iq); + /* CR252, TX DC-Offset Calibration */ + vnt_control_out_u8(priv, + MESSAGE_REQUEST_BBREG, + 0xfC, + calib_tx_dc); + /* CR253, RX I/Q Imbalance Calibration */ + vnt_control_out_u8(priv, + MESSAGE_REQUEST_BBREG, + 0xfd, + calib_rx_iq); + } else { + /* CR255, turn off + BB Calibration compensation */ + vnt_control_out_u8(priv, + MESSAGE_REQUEST_BBREG, + 0xff, + 0x0); + } + } + } + + /* get permanent network address */ + memcpy(priv->permanent_net_addr, init_rsp->net_addr, 6); + ether_addr_copy(priv->current_net_addr, priv->permanent_net_addr); + + /* if exist SW network address, use it */ + dev_dbg(&priv->usb->dev, "Network address = %pM\n", + priv->current_net_addr); + + /* + * set BB and packet type at the same time + * set Short Slot Time, xIFS, and RSPINF + */ + if (priv->bb_type == BB_TYPE_11A) + priv->short_slot_time = true; + else + priv->short_slot_time = false; + + vnt_set_short_slot_time(priv); + + priv->radio_ctl = priv->eeprom[EEP_OFS_RADIOCTL]; + + if ((priv->radio_ctl & EEP_RADIOCTL_ENABLE) != 0) { + status = vnt_control_in(priv, MESSAGE_TYPE_READ, + MAC_REG_GPIOCTL1, MESSAGE_REQUEST_MACREG, 1, &tmp); + + if (status != STATUS_SUCCESS) + return false; + + if ((tmp & GPIO3_DATA) == 0) + vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1, + GPIO3_INTMD); + else + vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1, + GPIO3_INTMD); + } + + vnt_mac_set_led(priv, LEDSTS_TMLEN, 0x38); + + vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW); + + vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL0, 0x01); + + vnt_radio_power_on(priv); + + dev_dbg(&priv->usb->dev, "<----INIbInitAdapter Exit\n"); + + return true; +} + +static void vnt_free_tx_bufs(struct vnt_private *priv) +{ + struct vnt_usb_send_context *tx_context; + int ii; + + for (ii = 0; ii < priv->num_tx_context; ii++) { + tx_context = priv->tx_context[ii]; + /* deallocate URBs */ + if (tx_context->urb) { + usb_kill_urb(tx_context->urb); + usb_free_urb(tx_context->urb); + } + + kfree(tx_context); + } +} + +static void vnt_free_rx_bufs(struct vnt_private *priv) +{ + struct vnt_rcb *rcb; + int ii; + + for (ii = 0; ii < priv->num_rcb; ii++) { + rcb = priv->rcb[ii]; + if (!rcb) + continue; + + /* deallocate URBs */ + if (rcb->urb) { + usb_kill_urb(rcb->urb); + usb_free_urb(rcb->urb); + } + + /* deallocate skb */ + if (rcb->skb) + dev_kfree_skb(rcb->skb); + + kfree(rcb); + } +} + +static void usb_device_reset(struct vnt_private *priv) +{ + int status; + + status = usb_reset_device(priv->usb); + if (status) + dev_warn(&priv->usb->dev, + "usb_device_reset fail status=%d\n", status); +} + +static void vnt_free_int_bufs(struct vnt_private *priv) +{ + kfree(priv->int_buf.data_buf); +} + +static bool vnt_alloc_bufs(struct vnt_private *priv) +{ + struct vnt_usb_send_context *tx_context; + struct vnt_rcb *rcb; + int ii; + + for (ii = 0; ii < priv->num_tx_context; ii++) { + tx_context = kmalloc(sizeof(struct vnt_usb_send_context), + GFP_KERNEL); + if (tx_context == NULL) + goto free_tx; + + priv->tx_context[ii] = tx_context; + tx_context->priv = priv; + tx_context->pkt_no = ii; + + /* allocate URBs */ + tx_context->urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!tx_context->urb) { + dev_err(&priv->usb->dev, "alloc tx urb failed\n"); + goto free_tx; + } + + tx_context->in_use = false; + } + + for (ii = 0; ii < priv->num_rcb; ii++) { + priv->rcb[ii] = kzalloc(sizeof(struct vnt_rcb), GFP_KERNEL); + if (!priv->rcb[ii]) { + dev_err(&priv->usb->dev, + "failed to allocate rcb no %d\n", ii); + goto free_rx_tx; + } + + rcb = priv->rcb[ii]; + + rcb->priv = priv; + + /* allocate URBs */ + rcb->urb = usb_alloc_urb(0, GFP_ATOMIC); + if (rcb->urb == NULL) { + dev_err(&priv->usb->dev, "Failed to alloc rx urb\n"); + goto free_rx_tx; + } + + rcb->skb = dev_alloc_skb(priv->rx_buf_sz); + if (rcb->skb == NULL) + goto free_rx_tx; + + rcb->in_use = false; + + /* submit rx urb */ + if (vnt_submit_rx_urb(priv, rcb)) + goto free_rx_tx; + } + + priv->interrupt_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (priv->interrupt_urb == NULL) { + dev_err(&priv->usb->dev, "Failed to alloc int urb\n"); + goto free_rx_tx; + } + + priv->int_buf.data_buf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL); + if (priv->int_buf.data_buf == NULL) { + usb_free_urb(priv->interrupt_urb); + goto free_rx_tx; + } + + return true; + +free_rx_tx: + vnt_free_rx_bufs(priv); + +free_tx: + vnt_free_tx_bufs(priv); + + return false; +} + +static void vnt_tx_80211(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, struct sk_buff *skb) +{ + struct vnt_private *priv = hw->priv; + + ieee80211_stop_queues(hw); + + if (vnt_tx_packet(priv, skb)) { + ieee80211_free_txskb(hw, skb); + + ieee80211_wake_queues(hw); + } +} + +static int vnt_start(struct ieee80211_hw *hw) +{ + struct vnt_private *priv = hw->priv; + + priv->rx_buf_sz = MAX_TOTAL_SIZE_WITH_ALL_HEADERS; + + if (vnt_alloc_bufs(priv) == false) { + dev_dbg(&priv->usb->dev, "vnt_alloc_bufs fail...\n"); + return -ENOMEM; + } + + clear_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags); + + if (vnt_init_registers(priv) == false) { + dev_dbg(&priv->usb->dev, " init register fail\n"); + goto free_all; + } + + priv->int_interval = 1; /* bInterval is set to 1 */ + + vnt_int_start_interrupt(priv); + + ieee80211_wake_queues(hw); + + return 0; + +free_all: + vnt_free_rx_bufs(priv); + vnt_free_tx_bufs(priv); + vnt_free_int_bufs(priv); + + usb_kill_urb(priv->interrupt_urb); + usb_free_urb(priv->interrupt_urb); + + return -ENOMEM; +} + +static void vnt_stop(struct ieee80211_hw *hw) +{ + struct vnt_private *priv = hw->priv; + int i; + + if (!priv) + return; + + for (i = 0; i < MAX_KEY_TABLE; i++) + vnt_mac_disable_keyentry(priv, i); + + /* clear all keys */ + priv->key_entry_inuse = 0; + + if (!test_bit(DEVICE_FLAGS_UNPLUG, &priv->flags)) + vnt_mac_shutdown(priv); + + ieee80211_stop_queues(hw); + + set_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags); + + cancel_delayed_work_sync(&priv->run_command_work); + + priv->cmd_running = false; + + vnt_free_tx_bufs(priv); + vnt_free_rx_bufs(priv); + vnt_free_int_bufs(priv); + + usb_kill_urb(priv->interrupt_urb); + usb_free_urb(priv->interrupt_urb); +} + +static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct vnt_private *priv = hw->priv; + + priv->vif = vif; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + break; + case NL80211_IFTYPE_ADHOC: + vnt_mac_reg_bits_off(priv, MAC_REG_RCR, RCR_UNICAST); + + vnt_mac_reg_bits_on(priv, MAC_REG_HOSTCR, HOSTCR_ADHOC); + + break; + case NL80211_IFTYPE_AP: + vnt_mac_reg_bits_off(priv, MAC_REG_RCR, RCR_UNICAST); + + vnt_mac_reg_bits_on(priv, MAC_REG_HOSTCR, HOSTCR_AP); + + break; + default: + return -EOPNOTSUPP; + } + + priv->op_mode = vif->type; + + vnt_set_bss_mode(priv); + + /* LED blink on TX */ + vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_INTER); + + return 0; +} + +static void vnt_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct vnt_private *priv = hw->priv; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + break; + case NL80211_IFTYPE_ADHOC: + vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX); + vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_ADHOC); + break; + case NL80211_IFTYPE_AP: + vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX); + vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_AP); + break; + default: + break; + } + + vnt_radio_power_off(priv); + + priv->op_mode = NL80211_IFTYPE_UNSPECIFIED; + + /* LED slow blink */ + vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW); +} + +static int vnt_config(struct ieee80211_hw *hw, u32 changed) +{ + struct vnt_private *priv = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + u8 bb_type; + + if (changed & IEEE80211_CONF_CHANGE_PS) { + if (conf->flags & IEEE80211_CONF_PS) + vnt_enable_power_saving(priv, conf->listen_interval); + else + vnt_disable_power_saving(priv); + } + + if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || + (conf->flags & IEEE80211_CONF_OFFCHANNEL)) { + vnt_set_channel(priv, conf->chandef.chan->hw_value); + + if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ) + bb_type = BB_TYPE_11A; + else + bb_type = BB_TYPE_11G; + + if (priv->bb_type != bb_type) { + priv->bb_type = bb_type; + + vnt_set_bss_mode(priv); + } + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + if (priv->bb_type == BB_TYPE_11B) + priv->current_rate = RATE_1M; + else + priv->current_rate = RATE_54M; + + vnt_rf_setpower(priv, priv->current_rate, + conf->chandef.chan->hw_value); + } + + return 0; +} + +static void vnt_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, + u32 changed) +{ + struct vnt_private *priv = hw->priv; + + priv->current_aid = conf->aid; + + if (changed & BSS_CHANGED_BSSID) + vnt_mac_set_bssid_addr(priv, (u8 *)conf->bssid); + + + if (changed & BSS_CHANGED_BASIC_RATES) { + priv->basic_rates = conf->basic_rates; + + vnt_update_top_rates(priv); + + dev_dbg(&priv->usb->dev, "basic rates %x\n", conf->basic_rates); + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (conf->use_short_preamble) { + vnt_mac_enable_barker_preamble_mode(priv); + priv->preamble_type = true; + } else { + vnt_mac_disable_barker_preamble_mode(priv); + priv->preamble_type = false; + } + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (conf->use_cts_prot) + vnt_mac_enable_protect_mode(priv); + else + vnt_mac_disable_protect_mode(priv); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (conf->use_short_slot) + priv->short_slot_time = true; + else + priv->short_slot_time = false; + + vnt_set_short_slot_time(priv); + vnt_set_vga_gain_offset(priv, priv->bb_vga[0]); + vnt_update_pre_ed_threshold(priv, false); + } + + if (changed & BSS_CHANGED_TXPOWER) + vnt_rf_setpower(priv, priv->current_rate, + conf->chandef.chan->hw_value); + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + dev_dbg(&priv->usb->dev, + "Beacon enable %d\n", conf->enable_beacon); + + if (conf->enable_beacon) { + vnt_beacon_enable(priv, vif, conf); + + vnt_mac_reg_bits_on(priv, MAC_REG_TCR, TCR_AUTOBCNTX); + } else { + vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX); + } + } +} + +static u64 vnt_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) +{ + struct vnt_private *priv = hw->priv; + struct netdev_hw_addr *ha; + u64 mc_filter = 0; + u32 bit_nr = 0; + + netdev_hw_addr_list_for_each(ha, mc_list) { + bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; + + mc_filter |= 1ULL << (bit_nr & 0x3f); + } + + priv->mc_list_count = mc_list->count; + + return mc_filter; +} + +static void vnt_configure(struct ieee80211_hw *hw, + unsigned int changed_flags, unsigned int *total_flags, u64 multicast) +{ + struct vnt_private *priv = hw->priv; + u8 rx_mode = 0; + int rc; + + *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS | + FIF_BCN_PRBRESP_PROMISC; + + rc = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_RCR, + MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode); + + if (!rc) + rx_mode = RCR_MULTICAST | RCR_BROADCAST; + + dev_dbg(&priv->usb->dev, "rx mode in = %x\n", rx_mode); + + if (changed_flags & FIF_PROMISC_IN_BSS) { + /* unconditionally log net taps */ + if (*total_flags & FIF_PROMISC_IN_BSS) + rx_mode |= RCR_UNICAST; + else + rx_mode &= ~RCR_UNICAST; + } + + if (changed_flags & FIF_ALLMULTI) { + if (*total_flags & FIF_ALLMULTI) { + if (priv->mc_list_count > 2) + vnt_mac_set_filter(priv, ~0); + else + vnt_mac_set_filter(priv, multicast); + + rx_mode |= RCR_MULTICAST | RCR_BROADCAST; + } else { + rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST); + } + + } + + if (changed_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) { + if (*total_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) + rx_mode &= ~RCR_BSSID; + else + rx_mode |= RCR_BSSID; + } + + vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, MAC_REG_RCR, rx_mode); + + dev_dbg(&priv->usb->dev, "rx mode out= %x\n", rx_mode); +} + +static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct vnt_private *priv = hw->priv; + + switch (cmd) { + case SET_KEY: + if (vnt_set_keys(hw, sta, vif, key)) + return -EOPNOTSUPP; + break; + case DISABLE_KEY: + if (test_bit(key->hw_key_idx, &priv->key_entry_inuse)) + clear_bit(key->hw_key_idx, &priv->key_entry_inuse); + default: + break; + } + + return 0; +} + +static void vnt_sw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *addr) +{ + struct vnt_private *priv = hw->priv; + + vnt_set_bss_mode(priv); + /* Set max sensitivity*/ + vnt_update_pre_ed_threshold(priv, true); +} + +static void vnt_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct vnt_private *priv = hw->priv; + + /* Return sensitivity to channel level*/ + vnt_update_pre_ed_threshold(priv, false); +} + +static int vnt_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct vnt_private *priv = hw->priv; + + memcpy(stats, &priv->low_stats, sizeof(*stats)); + + return 0; +} + +static u64 vnt_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct vnt_private *priv = hw->priv; + + return priv->current_tsf; +} + +static void vnt_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 tsf) +{ + struct vnt_private *priv = hw->priv; + + vnt_update_next_tbtt(priv, tsf, vif->bss_conf.beacon_int); +} + +static void vnt_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct vnt_private *priv = hw->priv; + + vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + + vnt_clear_current_tsf(priv); +} + +static const struct ieee80211_ops vnt_mac_ops = { + .tx = vnt_tx_80211, + .start = vnt_start, + .stop = vnt_stop, + .add_interface = vnt_add_interface, + .remove_interface = vnt_remove_interface, + .config = vnt_config, + .bss_info_changed = vnt_bss_info_changed, + .prepare_multicast = vnt_prepare_multicast, + .configure_filter = vnt_configure, + .set_key = vnt_set_key, + .sw_scan_start = vnt_sw_scan_start, + .sw_scan_complete = vnt_sw_scan_complete, + .get_stats = vnt_get_stats, + .get_tsf = vnt_get_tsf, + .set_tsf = vnt_set_tsf, + .reset_tsf = vnt_reset_tsf, +}; + +int vnt_init(struct vnt_private *priv) +{ + + if (!(vnt_init_registers(priv))) + return -EAGAIN; + + SET_IEEE80211_PERM_ADDR(priv->hw, priv->permanent_net_addr); + + vnt_init_bands(priv); + + if (ieee80211_register_hw(priv->hw)) + return -ENODEV; + + priv->mac_hw = true; + + vnt_radio_power_off(priv); + + return 0; +} + +static int +vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev; + struct vnt_private *priv; + struct ieee80211_hw *hw; + struct wiphy *wiphy; + int rc = 0; + + udev = usb_get_dev(interface_to_usbdev(intf)); + + dev_notice(&udev->dev, "%s Ver. %s\n", + DEVICE_FULL_DRV_NAM, DEVICE_VERSION); + dev_notice(&udev->dev, + "Copyright (c) 2004 VIA Networking Technologies, Inc.\n"); + + hw = ieee80211_alloc_hw(sizeof(struct vnt_private), &vnt_mac_ops); + if (!hw) { + dev_err(&udev->dev, "could not register ieee80211_hw\n"); + rc = -ENOMEM; + goto err_nomem; + } + + priv = hw->priv; + priv->hw = hw; + priv->usb = udev; + + vnt_set_options(priv); + + spin_lock_init(&priv->lock); + mutex_init(&priv->usb_lock); + + INIT_DELAYED_WORK(&priv->run_command_work, vnt_run_command); + + usb_set_intfdata(intf, priv); + + wiphy = priv->hw->wiphy; + + wiphy->frag_threshold = FRAG_THRESH_DEF; + wiphy->rts_threshold = RTS_THRESH_DEF; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); + + priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_TIMING_BEACON_ONLY; + + priv->hw->max_signal = 100; + + SET_IEEE80211_DEV(priv->hw, &intf->dev); + + usb_device_reset(priv); + + clear_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags); + vnt_reset_command_timer(priv); + + vnt_schedule_command(priv, WLAN_CMD_INIT_MAC80211); + + return 0; + +err_nomem: + usb_put_dev(udev); + + return rc; +} + +static void vt6656_disconnect(struct usb_interface *intf) +{ + struct vnt_private *priv = usb_get_intfdata(intf); + + if (!priv) + return; + + if (priv->mac_hw) + ieee80211_unregister_hw(priv->hw); + + usb_set_intfdata(intf, NULL); + usb_put_dev(interface_to_usbdev(intf)); + + set_bit(DEVICE_FLAGS_UNPLUG, &priv->flags); + + ieee80211_free_hw(priv->hw); +} + +#ifdef CONFIG_PM + +static int vt6656_suspend(struct usb_interface *intf, pm_message_t message) +{ + return 0; +} + +static int vt6656_resume(struct usb_interface *intf) +{ + return 0; +} + +#endif /* CONFIG_PM */ + +MODULE_DEVICE_TABLE(usb, vt6656_table); + +static struct usb_driver vt6656_driver = { + .name = DEVICE_NAME, + .probe = vt6656_probe, + .disconnect = vt6656_disconnect, + .id_table = vt6656_table, +#ifdef CONFIG_PM + .suspend = vt6656_suspend, + .resume = vt6656_resume, +#endif /* CONFIG_PM */ +}; + +module_usb_driver(vt6656_driver); diff --git a/kernel/drivers/staging/vt6656/power.c b/kernel/drivers/staging/vt6656/power.c new file mode 100644 index 000000000..0ffbaed5d --- /dev/null +++ b/kernel/drivers/staging/vt6656/power.c @@ -0,0 +1,144 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: power.c + * + * Purpose: Handles 802.11 power management functions + * + * Author: Lyndon Chen + * + * Date: July 17, 2002 + * + * Functions: + * vnt_enable_power_saving - Enable Power Saving Mode + * PSvDiasblePowerSaving - Disable Power Saving Mode + * vnt_next_tbtt_wakeup - Decide if we need to wake up at next Beacon + * + * Revision History: + * + */ + +#include "mac.h" +#include "device.h" +#include "power.h" +#include "wcmd.h" +#include "rxtx.h" +#include "card.h" +#include "usbpipe.h" + +/* + * + * Routine Description: + * Enable hw power saving functions + * + * Return Value: + * None. + * + */ + +void vnt_enable_power_saving(struct vnt_private *priv, u16 listen_interval) +{ + u16 aid = priv->current_aid | BIT(14) | BIT(15); + + /* set period of power up before TBTT */ + vnt_mac_write_word(priv, MAC_REG_PWBT, C_PWBT); + + if (priv->op_mode != NL80211_IFTYPE_ADHOC) { + /* set AID */ + vnt_mac_write_word(priv, MAC_REG_AIDATIM, aid); + } + + /* Warren:06-18-2004,the sequence must follow + * PSEN->AUTOSLEEP->GO2DOZE + */ + /* enable power saving hw function */ + vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_PSEN); + + /* Set AutoSleep */ + vnt_mac_reg_bits_on(priv, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); + + /* Warren:MUST turn on this once before turn on AUTOSLEEP ,or the + * AUTOSLEEP doesn't work + */ + vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_GO2DOZE); + + if (listen_interval >= 2) { + + /* clear always listen beacon */ + vnt_mac_reg_bits_off(priv, MAC_REG_PSCTL, PSCTL_ALBCN); + + /* first time set listen next beacon */ + vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_LNBCN); + } else { + + /* always listen beacon */ + vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_ALBCN); + } + + dev_dbg(&priv->usb->dev, "PS:Power Saving Mode Enable...\n"); +} + +/* + * + * Routine Description: + * Disable hw power saving functions + * + * Return Value: + * None. + * + */ + +void vnt_disable_power_saving(struct vnt_private *priv) +{ + + /* disable power saving hw function */ + vnt_control_out(priv, MESSAGE_TYPE_DISABLE_PS, 0, + 0, 0, NULL); + + /* clear AutoSleep */ + vnt_mac_reg_bits_off(priv, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); + + /* set always listen beacon */ + vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_ALBCN); +} + +/* + * + * Routine Description: + * Check if Next TBTT must wake up + * + * Return Value: + * None. + * + */ + +int vnt_next_tbtt_wakeup(struct vnt_private *priv) +{ + struct ieee80211_hw *hw = priv->hw; + struct ieee80211_conf *conf = &hw->conf; + int wake_up = false; + + if (conf->listen_interval == 1) { + /* Turn on wake up to listen next beacon */ + vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_LNBCN); + wake_up = true; + } + + return wake_up; +} diff --git a/kernel/drivers/staging/vt6656/power.h b/kernel/drivers/staging/vt6656/power.h new file mode 100644 index 000000000..7696b7148 --- /dev/null +++ b/kernel/drivers/staging/vt6656/power.h @@ -0,0 +1,38 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: power.h + * + * Purpose: Handles 802.11 power management functions + * + * Author: Lyndon Chen + * + * Date: July 17, 2002 + * + */ + +#ifndef __POWER_H__ +#define __POWER_H__ + +#define C_PWBT 1000 /* micro sec. power up before TBTT */ + +void vnt_disable_power_saving(struct vnt_private *); +void vnt_enable_power_saving(struct vnt_private *, u16); +int vnt_next_tbtt_wakeup(struct vnt_private *); + +#endif /* __POWER_H__ */ diff --git a/kernel/drivers/staging/vt6656/rf.c b/kernel/drivers/staging/vt6656/rf.c new file mode 100644 index 000000000..c4286ccac --- /dev/null +++ b/kernel/drivers/staging/vt6656/rf.c @@ -0,0 +1,951 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: rf.c + * + * Purpose: rf function code + * + * Author: Jerry Chen + * + * Date: Feb. 19, 2004 + * + * Functions: + * vnt_rf_write_embedded - Embedded write RF register via MAC + * + * Revision History: + * RF_VT3226: RobertYu:20051111, VT3226C0 and before + * RF_VT3226D0: RobertYu:20051228 + * RF_VT3342A0: RobertYu:20060609 + * + */ + +#include "mac.h" +#include "rf.h" +#include "baseband.h" +#include "usbpipe.h" + +#define CB_AL2230_INIT_SEQ 15 +#define AL2230_PWR_IDX_LEN 64 + +#define CB_AL7230_INIT_SEQ 16 +#define AL7230_PWR_IDX_LEN 64 + +#define CB_VT3226_INIT_SEQ 11 +#define VT3226_PWR_IDX_LEN 64 + +#define CB_VT3342_INIT_SEQ 13 +#define VT3342_PWR_IDX_LEN 64 + +static u8 al2230_init_table[CB_AL2230_INIT_SEQ][3] = { + {0x03, 0xf7, 0x90}, + {0x03, 0x33, 0x31}, + {0x01, 0xb8, 0x02}, + {0x00, 0xff, 0xf3}, + {0x00, 0x05, 0xa4}, + {0x0f, 0x4d, 0xc5}, + {0x08, 0x05, 0xb6}, + {0x01, 0x47, 0xc7}, + {0x00, 0x06, 0x88}, + {0x04, 0x03, 0xb9}, + {0x00, 0xdb, 0xba}, + {0x00, 0x09, 0x9b}, + {0x0b, 0xdf, 0xfc}, + {0x00, 0x00, 0x0d}, + {0x00, 0x58, 0x0f} +}; + +static u8 al2230_channel_table0[CB_MAX_CHANNEL_24G][3] = { + {0x03, 0xf7, 0x90}, + {0x03, 0xf7, 0x90}, + {0x03, 0xe7, 0x90}, + {0x03, 0xe7, 0x90}, + {0x03, 0xf7, 0xa0}, + {0x03, 0xf7, 0xa0}, + {0x03, 0xe7, 0xa0}, + {0x03, 0xe7, 0xa0}, + {0x03, 0xf7, 0xb0}, + {0x03, 0xf7, 0xb0}, + {0x03, 0xe7, 0xb0}, + {0x03, 0xe7, 0xb0}, + {0x03, 0xf7, 0xc0}, + {0x03, 0xe7, 0xc0} +}; + +static u8 al2230_channel_table1[CB_MAX_CHANNEL_24G][3] = { + {0x03, 0x33, 0x31}, + {0x0b, 0x33, 0x31}, + {0x03, 0x33, 0x31}, + {0x0b, 0x33, 0x31}, + {0x03, 0x33, 0x31}, + {0x0b, 0x33, 0x31}, + {0x03, 0x33, 0x31}, + {0x0b, 0x33, 0x31}, + {0x03, 0x33, 0x31}, + {0x0b, 0x33, 0x31}, + {0x03, 0x33, 0x31}, + {0x0b, 0x33, 0x31}, + {0x03, 0x33, 0x31}, + {0x06, 0x66, 0x61} +}; + +static u8 al7230_init_table[CB_AL7230_INIT_SEQ][3] = { + {0x20, 0x37, 0x90}, + {0x13, 0x33, 0x31}, + {0x84, 0x1f, 0xf2}, + {0x3f, 0xdf, 0xa3}, + {0x7f, 0xd7, 0x84}, + {0x80, 0x2b, 0x55}, + {0x56, 0xaf, 0x36}, + {0xce, 0x02, 0x07}, + {0x6e, 0xbc, 0x98}, + {0x22, 0x1b, 0xb9}, + {0xe0, 0x00, 0x0a}, + {0x08, 0x03, 0x1b}, + {0x00, 0x0a, 0x3c}, + {0xff, 0xff, 0xfd}, + {0x00, 0x00, 0x0e}, + {0x1a, 0xba, 0x8f} +}; + +static u8 al7230_init_table_amode[CB_AL7230_INIT_SEQ][3] = { + {0x2f, 0xf5, 0x20}, + {0x00, 0x00, 0x01}, + {0x45, 0x1f, 0xe2}, + {0x5f, 0xdf, 0xa3}, + {0x6f, 0xd7, 0x84}, + {0x85, 0x3f, 0x55}, + {0x56, 0xaf, 0x36}, + {0xce, 0x02, 0x07}, + {0x6e, 0xbc, 0x98}, + {0x22, 0x1b, 0xb9}, + {0xe0, 0x60, 0x0a}, + {0x08, 0x03, 0x1b}, + {0x00, 0x14, 0x7c}, + {0xff, 0xff, 0xfd}, + {0x00, 0x00, 0x0e}, + {0x12, 0xba, 0xcf} +}; + +static u8 al7230_channel_table0[CB_MAX_CHANNEL][3] = { + {0x20, 0x37, 0x90}, + {0x20, 0x37, 0x90}, + {0x20, 0x37, 0x90}, + {0x20, 0x37, 0x90}, + {0x20, 0x37, 0xa0}, + {0x20, 0x37, 0xa0}, + {0x20, 0x37, 0xa0}, + {0x20, 0x37, 0xa0}, + {0x20, 0x37, 0xb0}, + {0x20, 0x37, 0xb0}, + {0x20, 0x37, 0xb0}, + {0x20, 0x37, 0xb0}, + {0x20, 0x37, 0xc0}, + {0x20, 0x37, 0xc0}, + {0x0f, 0xf5, 0x20}, /* channel 15 Tf = 4915MHz */ + {0x2f, 0xf5, 0x20}, + {0x0f, 0xf5, 0x20}, + {0x0f, 0xf5, 0x20}, + {0x2f, 0xf5, 0x20}, + {0x0f, 0xf5, 0x20}, + {0x2f, 0xf5, 0x30}, + {0x2f, 0xf5, 0x30}, + {0x0f, 0xf5, 0x40}, + {0x2f, 0xf5, 0x40}, + {0x0f, 0xf5, 0x40}, + {0x0f, 0xf5, 0x40}, + {0x2f, 0xf5, 0x40}, + {0x2f, 0xf5, 0x50}, + {0x2f, 0xf5, 0x60}, + {0x2f, 0xf5, 0x60}, + {0x2f, 0xf5, 0x70}, + {0x2f, 0xf5, 0x70}, + {0x2f, 0xf5, 0x70}, + {0x2f, 0xf5, 0x70}, + {0x2f, 0xf5, 0x70}, + {0x2f, 0xf5, 0x70}, + {0x2f, 0xf5, 0x80}, + {0x2f, 0xf5, 0x80}, + {0x2f, 0xf5, 0x80}, + {0x2f, 0xf5, 0x90}, + {0x2f, 0xf5, 0xc0}, + {0x2f, 0xf5, 0xc0}, + {0x2f, 0xf5, 0xc0}, + {0x2f, 0xf5, 0xd0}, + {0x2f, 0xf5, 0xd0}, + {0x2f, 0xf5, 0xd0}, + {0x2f, 0xf5, 0xe0}, + {0x2f, 0xf5, 0xe0}, + {0x2f, 0xf5, 0xe0}, + {0x2f, 0xf5, 0xf0}, + {0x2f, 0xf5, 0xf0}, + {0x2f, 0xf6, 0x00}, + {0x2f, 0xf6, 0x00}, + {0x2f, 0xf6, 0x00}, + {0x2f, 0xf6, 0x10}, + {0x2f, 0xf6, 0x10} +}; + +static u8 al7230_channel_table1[CB_MAX_CHANNEL][3] = { + {0x13, 0x33, 0x31}, + {0x1b, 0x33, 0x31}, + {0x03, 0x33, 0x31}, + {0x0b, 0x33, 0x31}, + {0x13, 0x33, 0x31}, + {0x1b, 0x33, 0x31}, + {0x03, 0x33, 0x31}, + {0x0b, 0x33, 0x31}, + {0x13, 0x33, 0x31}, + {0x1b, 0x33, 0x31}, + {0x03, 0x33, 0x31}, + {0x0b, 0x33, 0x31}, + {0x13, 0x33, 0x31}, + {0x06, 0x66, 0x61}, + {0x1d, 0x55, 0x51}, /* channel = 15, Tf = 4915MHz */ + {0x00, 0x00, 0x01}, + {0x02, 0xaa, 0xa1}, + {0x08, 0x00, 0x01}, + {0x0a, 0xaa, 0xa1}, + {0x0d, 0x55, 0x51}, + {0x15, 0x55, 0x51}, + {0x00, 0x00, 0x01}, + {0x1d, 0x55, 0x51}, + {0x00, 0x00, 0x01}, + {0x02, 0xaa, 0xa1}, + {0x08, 0x00, 0x01}, + {0x0a, 0xaa, 0xa1}, + {0x15, 0x55, 0x51}, + {0x05, 0x55, 0x51}, + {0x0a, 0xaa, 0xa1}, + {0x10, 0x00, 0x01}, + {0x15, 0x55, 0x51}, + {0x1a, 0xaa, 0xa1}, + {0x00, 0x00, 0x01}, + {0x05, 0x55, 0x51}, + {0x0a, 0xaa, 0xa1}, + {0x15, 0x55, 0x51}, + {0x00, 0x00, 0x01}, + {0x0a, 0xaa, 0xa1}, + {0x15, 0x55, 0x51}, + {0x15, 0x55, 0x51}, + {0x00, 0x00, 0x01}, + {0x0a, 0xaa, 0xa1}, + {0x15, 0x55, 0x51}, + {0x00, 0x00, 0x01}, + {0x0a, 0xaa, 0xa1}, + {0x15, 0x55, 0x51}, + {0x00, 0x00, 0x01}, + {0x0a, 0xaa, 0xa1}, + {0x15, 0x55, 0x51}, + {0x00, 0x00, 0x01}, + {0x18, 0x00, 0x01}, + {0x02, 0xaa, 0xa1}, + {0x0d, 0x55, 0x51}, + {0x18, 0x00, 0x01}, + {0x02, 0xaa, 0xb1} +}; + +static u8 al7230_channel_table2[CB_MAX_CHANNEL][3] = { + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, /* channel = 15 Tf = 4915MHz */ + {0x6f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x6f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x6f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x6f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x6f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x6f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x6f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x6f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x6f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84}, + {0x7f, 0xd7, 0x84} +}; + +static u8 vt3226_init_table[CB_VT3226_INIT_SEQ][3] = { + {0x03, 0xff, 0x80}, + {0x02, 0x82, 0xa1}, + {0x03, 0xc6, 0xa2}, + {0x01, 0x97, 0x93}, + {0x03, 0x66, 0x64}, + {0x00, 0x61, 0xa5}, + {0x01, 0x7b, 0xd6}, + {0x00, 0x80, 0x17}, + {0x03, 0xf8, 0x08}, + {0x00, 0x02, 0x39}, + {0x02, 0x00, 0x2a} +}; + +static u8 vt3226d0_init_table[CB_VT3226_INIT_SEQ][3] = { + {0x03, 0xff, 0x80}, + {0x03, 0x02, 0x21}, + {0x03, 0xc6, 0xa2}, + {0x01, 0x97, 0x93}, + {0x03, 0x66, 0x64}, + {0x00, 0x71, 0xa5}, + {0x01, 0x15, 0xc6}, + {0x01, 0x2e, 0x07}, + {0x00, 0x58, 0x08}, + {0x00, 0x02, 0x79}, + {0x02, 0x01, 0xaa} +}; + +static u8 vt3226_channel_table0[CB_MAX_CHANNEL_24G][3] = { + {0x01, 0x97, 0x83}, + {0x01, 0x97, 0x83}, + {0x01, 0x97, 0x93}, + {0x01, 0x97, 0x93}, + {0x01, 0x97, 0x93}, + {0x01, 0x97, 0x93}, + {0x01, 0x97, 0xa3}, + {0x01, 0x97, 0xa3}, + {0x01, 0x97, 0xa3}, + {0x01, 0x97, 0xa3}, + {0x01, 0x97, 0xb3}, + {0x01, 0x97, 0xb3}, + {0x01, 0x97, 0xb3}, + {0x03, 0x37, 0xc3} +}; + +static u8 vt3226_channel_table1[CB_MAX_CHANNEL_24G][3] = { + {0x02, 0x66, 0x64}, + {0x03, 0x66, 0x64}, + {0x00, 0x66, 0x64}, + {0x01, 0x66, 0x64}, + {0x02, 0x66, 0x64}, + {0x03, 0x66, 0x64}, + {0x00, 0x66, 0x64}, + {0x01, 0x66, 0x64}, + {0x02, 0x66, 0x64}, + {0x03, 0x66, 0x64}, + {0x00, 0x66, 0x64}, + {0x01, 0x66, 0x64}, + {0x02, 0x66, 0x64}, + {0x00, 0xcc, 0xc4} +}; + +static const u32 vt3226d0_lo_current_table[CB_MAX_CHANNEL_24G] = { + 0x0135c600, + 0x0135c600, + 0x0235c600, + 0x0235c600, + 0x0235c600, + 0x0335c600, + 0x0335c600, + 0x0335c600, + 0x0335c600, + 0x0335c600, + 0x0335c600, + 0x0335c600, + 0x0335c600, + 0x0135c600 +}; + +static u8 vt3342a0_init_table[CB_VT3342_INIT_SEQ][3] = { /* 11b/g mode */ + {0x03, 0xff, 0x80}, + {0x02, 0x08, 0x81}, + {0x00, 0xc6, 0x02}, + {0x03, 0xc5, 0x13}, + {0x00, 0xee, 0xe4}, + {0x00, 0x71, 0xa5}, + {0x01, 0x75, 0x46}, + {0x01, 0x40, 0x27}, + {0x01, 0x54, 0x08}, + {0x00, 0x01, 0x69}, + {0x02, 0x00, 0xaa}, + {0x00, 0x08, 0xcb}, + {0x01, 0x70, 0x0c} +}; + +static u8 vt3342_channel_table0[CB_MAX_CHANNEL][3] = { + {0x02, 0x05, 0x03}, + {0x01, 0x15, 0x03}, + {0x03, 0xc5, 0x03}, + {0x02, 0x65, 0x03}, + {0x01, 0x15, 0x13}, + {0x03, 0xc5, 0x13}, + {0x02, 0x05, 0x13}, + {0x01, 0x15, 0x13}, + {0x03, 0xc5, 0x13}, + {0x02, 0x65, 0x13}, + {0x01, 0x15, 0x23}, + {0x03, 0xc5, 0x23}, + {0x02, 0x05, 0x23}, + {0x00, 0xd5, 0x23}, + {0x01, 0x15, 0x13}, /* channel = 15 Tf = 4915MHz */ + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x15, 0x13}, + {0x01, 0x55, 0x63}, + {0x01, 0x55, 0x63}, + {0x02, 0xa5, 0x63}, + {0x02, 0xa5, 0x63}, + {0x00, 0x05, 0x73}, + {0x00, 0x05, 0x73}, + {0x01, 0x55, 0x73}, + {0x02, 0xa5, 0x73}, + {0x00, 0x05, 0x83}, + {0x01, 0x55, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x02, 0xa5, 0x83}, + {0x00, 0x05, 0xF3}, + {0x01, 0x56, 0x03}, + {0x02, 0xa6, 0x03}, + {0x00, 0x06, 0x03}, + {0x00, 0x06, 0x03} +}; + +static u8 vt3342_channel_table1[CB_MAX_CHANNEL][3] = { + {0x01, 0x99, 0x94}, + {0x02, 0x44, 0x44}, + {0x02, 0xee, 0xe4}, + {0x03, 0x99, 0x94}, + {0x00, 0x44, 0x44}, + {0x00, 0xee, 0xe4}, + {0x01, 0x99, 0x94}, + {0x02, 0x44, 0x44}, + {0x02, 0xee, 0xe4}, + {0x03, 0x99, 0x94}, + {0x00, 0x44, 0x44}, + {0x00, 0xee, 0xe4}, + {0x01, 0x99, 0x94}, + {0x03, 0x33, 0x34}, + {0x00, 0x44, 0x44}, /* channel = 15 Tf = 4915MHz */ + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x00, 0x44, 0x44}, + {0x01, 0x55, 0x54}, + {0x01, 0x55, 0x54}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x00, 0x00, 0x04}, + {0x00, 0x00, 0x04}, + {0x01, 0x55, 0x54}, + {0x02, 0xaa, 0xa4}, + {0x00, 0x00, 0x04}, + {0x01, 0x55, 0x54}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x02, 0xaa, 0xa4}, + {0x03, 0x00, 0x04}, + {0x00, 0x55, 0x54}, + {0x01, 0xaa, 0xa4}, + {0x03, 0x00, 0x04}, + {0x03, 0x00, 0x04} +}; + +/* Power Table */ +static const u32 al2230_power_table[AL2230_PWR_IDX_LEN] = { + 0x04040900, + 0x04041900, + 0x04042900, + 0x04043900, + 0x04044900, + 0x04045900, + 0x04046900, + 0x04047900, + 0x04048900, + 0x04049900, + 0x0404a900, + 0x0404b900, + 0x0404c900, + 0x0404d900, + 0x0404e900, + 0x0404f900, + 0x04050900, + 0x04051900, + 0x04052900, + 0x04053900, + 0x04054900, + 0x04055900, + 0x04056900, + 0x04057900, + 0x04058900, + 0x04059900, + 0x0405a900, + 0x0405b900, + 0x0405c900, + 0x0405d900, + 0x0405e900, + 0x0405f900, + 0x04060900, + 0x04061900, + 0x04062900, + 0x04063900, + 0x04064900, + 0x04065900, + 0x04066900, + 0x04067900, + 0x04068900, + 0x04069900, + 0x0406a900, + 0x0406b900, + 0x0406c900, + 0x0406d900, + 0x0406e900, + 0x0406f900, + 0x04070900, + 0x04071900, + 0x04072900, + 0x04073900, + 0x04074900, + 0x04075900, + 0x04076900, + 0x04077900, + 0x04078900, + 0x04079900, + 0x0407a900, + 0x0407b900, + 0x0407c900, + 0x0407d900, + 0x0407e900, + 0x0407f900 +}; + +/* + * Description: Write to IF/RF, by embedded programming + */ +int vnt_rf_write_embedded(struct vnt_private *priv, u32 data) +{ + u8 reg_data[4]; + + data |= (VNT_RF_REG_LEN << 3) | IFREGCTL_REGW; + + reg_data[0] = (u8)data; + reg_data[1] = (u8)(data >> 8); + reg_data[2] = (u8)(data >> 16); + reg_data[3] = (u8)(data >> 24); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE_IFRF, + 0, 0, ARRAY_SIZE(reg_data), reg_data); + + return true; +} + +/* Set Tx power by rate and channel number */ +int vnt_rf_setpower(struct vnt_private *priv, u32 rate, u32 channel) +{ + u8 power = priv->cck_pwr; + + if (channel == 0) + return -EINVAL; + + switch (rate) { + case RATE_1M: + case RATE_2M: + case RATE_5M: + case RATE_11M: + channel--; + + if (channel < sizeof(priv->cck_pwr_tbl)) + power = priv->cck_pwr_tbl[channel]; + break; + case RATE_6M: + case RATE_9M: + case RATE_12M: + case RATE_18M: + case RATE_24M: + case RATE_36M: + case RATE_48M: + case RATE_54M: + if (channel > CB_MAX_CHANNEL_24G) + power = priv->ofdm_a_pwr_tbl[channel-15]; + else + power = priv->ofdm_pwr_tbl[channel-1]; + break; + } + + return vnt_rf_set_txpower(priv, power, rate); +} + +static u8 vnt_rf_addpower(struct vnt_private *priv) +{ + s32 rssi = -priv->current_rssi; + + if (!rssi) + return 7; + + if (priv->rf_type == RF_VT3226D0) { + if (rssi < -70) + return 9; + else if (rssi < -65) + return 7; + else if (rssi < -60) + return 5; + } else { + if (rssi < -80) + return 9; + else if (rssi < -75) + return 7; + else if (rssi < -70) + return 5; + } + + return 0; +} + +/* Set Tx power by power level and rate */ +int vnt_rf_set_txpower(struct vnt_private *priv, u8 power, u32 rate) +{ + u32 power_setting = 0; + int ret = true; + + power += vnt_rf_addpower(priv); + if (power > VNT_RF_MAX_POWER) + power = VNT_RF_MAX_POWER; + + if (priv->power == power) + return true; + + priv->power = power; + + switch (priv->rf_type) { + case RF_AL2230: + if (power >= AL2230_PWR_IDX_LEN) + return false; + + ret &= vnt_rf_write_embedded(priv, al2230_power_table[power]); + + if (rate <= RATE_11M) + ret &= vnt_rf_write_embedded(priv, 0x0001b400); + else + ret &= vnt_rf_write_embedded(priv, 0x0005a400); + break; + case RF_AL2230S: + if (power >= AL2230_PWR_IDX_LEN) + return false; + + ret &= vnt_rf_write_embedded(priv, al2230_power_table[power]); + + if (rate <= RATE_11M) { + ret &= vnt_rf_write_embedded(priv, 0x040c1400); + ret &= vnt_rf_write_embedded(priv, 0x00299b00); + } else { + ret &= vnt_rf_write_embedded(priv, 0x0005a400); + ret &= vnt_rf_write_embedded(priv, 0x00099b00); + } + break; + + case RF_AIROHA7230: + if (rate <= RATE_11M) + ret &= vnt_rf_write_embedded(priv, 0x111bb900); + else + ret &= vnt_rf_write_embedded(priv, 0x221bb900); + + if (power >= AL7230_PWR_IDX_LEN) + return false; + + /* + * 0x080F1B00 for 3 wire control TxGain(D10) + * and 0x31 as TX Gain value + */ + power_setting = 0x080c0b00 | (power << 12); + + ret &= vnt_rf_write_embedded(priv, power_setting); + + break; + + case RF_VT3226: + if (power >= VT3226_PWR_IDX_LEN) + return false; + power_setting = ((0x3f - power) << 20) | (0x17 << 8); + + ret &= vnt_rf_write_embedded(priv, power_setting); + + break; + case RF_VT3226D0: + if (power >= VT3226_PWR_IDX_LEN) + return false; + + if (rate <= RATE_11M) { + u16 hw_value = priv->hw->conf.chandef.chan->hw_value; + + power_setting = ((0x3f - power) << 20) | (0xe07 << 8); + + ret &= vnt_rf_write_embedded(priv, power_setting); + ret &= vnt_rf_write_embedded(priv, 0x03c6a200); + + dev_dbg(&priv->usb->dev, + "%s 11b channel [%d]\n", __func__, hw_value); + + hw_value--; + + if (hw_value < ARRAY_SIZE(vt3226d0_lo_current_table)) + ret &= vnt_rf_write_embedded(priv, + vt3226d0_lo_current_table[hw_value]); + + ret &= vnt_rf_write_embedded(priv, 0x015C0800); + } else { + dev_dbg(&priv->usb->dev, + "@@@@ vnt_rf_set_txpower> 11G mode\n"); + + power_setting = ((0x3f - power) << 20) | (0x7 << 8); + + ret &= vnt_rf_write_embedded(priv, power_setting); + ret &= vnt_rf_write_embedded(priv, 0x00C6A200); + ret &= vnt_rf_write_embedded(priv, 0x016BC600); + ret &= vnt_rf_write_embedded(priv, 0x00900800); + } + break; + + case RF_VT3342A0: + if (power >= VT3342_PWR_IDX_LEN) + return false; + + power_setting = ((0x3f - power) << 20) | (0x27 << 8); + + ret &= vnt_rf_write_embedded(priv, power_setting); + + break; + default: + break; + } + return ret; +} + +/* Convert rssi to dbm */ +void vnt_rf_rssi_to_dbm(struct vnt_private *priv, u8 rssi, long *dbm) +{ + u8 idx = (((rssi & 0xc0) >> 6) & 0x03); + long b = (rssi & 0x3f); + long a = 0; + u8 airoharf[4] = {0, 18, 0, 40}; + + switch (priv->rf_type) { + case RF_AL2230: + case RF_AL2230S: + case RF_AIROHA7230: + case RF_VT3226: + case RF_VT3226D0: + case RF_VT3342A0: + a = airoharf[idx]; + break; + default: + break; + } + + *dbm = -1 * (a + b * 2); +} + +void vnt_rf_table_download(struct vnt_private *priv) +{ + u16 length1 = 0, length2 = 0, length3 = 0; + u8 *addr1 = NULL, *addr2 = NULL, *addr3 = NULL; + u16 length, value; + u8 array[256]; + + switch (priv->rf_type) { + case RF_AL2230: + case RF_AL2230S: + length1 = CB_AL2230_INIT_SEQ * 3; + length2 = CB_MAX_CHANNEL_24G * 3; + length3 = CB_MAX_CHANNEL_24G * 3; + addr1 = &al2230_init_table[0][0]; + addr2 = &al2230_channel_table0[0][0]; + addr3 = &al2230_channel_table1[0][0]; + break; + case RF_AIROHA7230: + length1 = CB_AL7230_INIT_SEQ * 3; + length2 = CB_MAX_CHANNEL * 3; + length3 = CB_MAX_CHANNEL * 3; + addr1 = &al7230_init_table[0][0]; + addr2 = &al7230_channel_table0[0][0]; + addr3 = &al7230_channel_table1[0][0]; + break; + case RF_VT3226: + length1 = CB_VT3226_INIT_SEQ * 3; + length2 = CB_MAX_CHANNEL_24G * 3; + length3 = CB_MAX_CHANNEL_24G * 3; + addr1 = &vt3226_init_table[0][0]; + addr2 = &vt3226_channel_table0[0][0]; + addr3 = &vt3226_channel_table1[0][0]; + break; + case RF_VT3226D0: + length1 = CB_VT3226_INIT_SEQ * 3; + length2 = CB_MAX_CHANNEL_24G * 3; + length3 = CB_MAX_CHANNEL_24G * 3; + addr1 = &vt3226d0_init_table[0][0]; + addr2 = &vt3226_channel_table0[0][0]; + addr3 = &vt3226_channel_table1[0][0]; + break; + case RF_VT3342A0: + length1 = CB_VT3342_INIT_SEQ * 3; + length2 = CB_MAX_CHANNEL * 3; + length3 = CB_MAX_CHANNEL * 3; + addr1 = &vt3342a0_init_table[0][0]; + addr2 = &vt3342_channel_table0[0][0]; + addr3 = &vt3342_channel_table1[0][0]; + break; + } + + /* Init Table */ + memcpy(array, addr1, length1); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0, + MESSAGE_REQUEST_RF_INIT, length1, array); + + /* Channel Table 0 */ + value = 0; + while (length2 > 0) { + if (length2 >= 64) + length = 64; + else + length = length2; + + memcpy(array, addr2, length); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, + value, MESSAGE_REQUEST_RF_CH0, length, array); + + length2 -= length; + value += length; + addr2 += length; + } + + /* Channel table 1 */ + value = 0; + while (length3 > 0) { + if (length3 >= 64) + length = 64; + else + length = length3; + + memcpy(array, addr3, length); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, + value, MESSAGE_REQUEST_RF_CH1, length, array); + + length3 -= length; + value += length; + addr3 += length; + } + + if (priv->rf_type == RF_AIROHA7230) { + length1 = CB_AL7230_INIT_SEQ * 3; + length2 = CB_MAX_CHANNEL * 3; + addr1 = &(al7230_init_table_amode[0][0]); + addr2 = &(al7230_channel_table2[0][0]); + + memcpy(array, addr1, length1); + + /* Init Table 2 */ + vnt_control_out(priv, MESSAGE_TYPE_WRITE, + 0, MESSAGE_REQUEST_RF_INIT2, length1, array); + + /* Channel Table 0 */ + value = 0; + while (length2 > 0) { + if (length2 >= 64) + length = 64; + else + length = length2; + + memcpy(array, addr2, length); + + vnt_control_out(priv, MESSAGE_TYPE_WRITE, + value, MESSAGE_REQUEST_RF_CH2, length, array); + + length2 -= length; + value += length; + addr2 += length; + } + } +} diff --git a/kernel/drivers/staging/vt6656/rf.h b/kernel/drivers/staging/vt6656/rf.h new file mode 100644 index 000000000..3acdc65b1 --- /dev/null +++ b/kernel/drivers/staging/vt6656/rf.h @@ -0,0 +1,63 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: rf.h + * + * Purpose: + * + * Author: Jerry Chen + * + * Date: Feb. 19, 2004 + * + */ + +#ifndef __RF_H__ +#define __RF_H__ + +#include "device.h" + +/* Baseband RF pair definition in eeprom (Bits 6..0) */ +#define RF_RFMD2959 0x01 +#define RF_MAXIMAG 0x02 +#define RF_AL2230 0x03 +#define RF_GCT5103 0x04 +#define RF_UW2451 0x05 +#define RF_MAXIMG 0x06 +#define RF_MAXIM2829 0x07 +#define RF_UW2452 0x08 +#define RF_VT3226 0x09 +#define RF_AIROHA7230 0x0a +#define RF_UW2453 0x0b +#define RF_VT3226D0 0x0c /* RobertYu:20051114 */ +#define RF_VT3342A0 0x0d /* RobertYu:20060609 */ +#define RF_AL2230S 0x0e + +#define RF_EMU 0x80 +#define RF_MASK 0x7F + +#define VNT_RF_MAX_POWER 0x3f +#define VNT_RF_REG_LEN 0x17 /* 24 bit length */ + +int vnt_rf_write_embedded(struct vnt_private *, u32); +int vnt_rf_setpower(struct vnt_private *, u32, u32); +int vnt_rf_set_txpower(struct vnt_private *, u8, u32); +void vnt_rf_rssi_to_dbm(struct vnt_private *, u8, long *); +void vnt_rf_table_download(struct vnt_private *); + +#endif /* __RF_H__ */ diff --git a/kernel/drivers/staging/vt6656/rxtx.c b/kernel/drivers/staging/vt6656/rxtx.c new file mode 100644 index 000000000..5c589962a --- /dev/null +++ b/kernel/drivers/staging/vt6656/rxtx.c @@ -0,0 +1,1112 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: rxtx.c + * + * Purpose: handle WMAC/802.3/802.11 rx & tx functions + * + * Author: Lyndon Chen + * + * Date: May 20, 2003 + * + * Functions: + * vnt_generate_tx_parameter - Generate tx dma required parameter. + * vnt_get_duration_le - get tx data required duration + * vnt_get_rtscts_duration_le- get rtx/cts required duration + * vnt_get_rtscts_rsvtime_le- get rts/cts reserved time + * vnt_get_rsvtime- get frame reserved time + * vnt_fill_cts_head- fulfill CTS ctl header + * + * Revision History: + * + */ + +#include <linux/etherdevice.h> +#include "device.h" +#include "rxtx.h" +#include "card.h" +#include "mac.h" +#include "rf.h" +#include "usbpipe.h" + +static const u16 vnt_time_stampoff[2][MAX_RATE] = { + {384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23},/* Long Preamble */ + {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23},/* Short Preamble */ +}; + +static const u16 vnt_fb_opt0[2][5] = { + {RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, /* fallback_rate0 */ + {RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, /* fallback_rate1 */ +}; + +static const u16 vnt_fb_opt1[2][5] = { + {RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, /* fallback_rate0 */ + {RATE_6M, RATE_6M, RATE_12M, RATE_12M, RATE_18M}, /* fallback_rate1 */ +}; + +#define RTSDUR_BB 0 +#define RTSDUR_BA 1 +#define RTSDUR_AA 2 +#define CTSDUR_BA 3 +#define RTSDUR_BA_F0 4 +#define RTSDUR_AA_F0 5 +#define RTSDUR_BA_F1 6 +#define RTSDUR_AA_F1 7 +#define CTSDUR_BA_F0 8 +#define CTSDUR_BA_F1 9 +#define DATADUR_B 10 +#define DATADUR_A 11 +#define DATADUR_A_F0 12 +#define DATADUR_A_F1 13 + +static struct vnt_usb_send_context + *vnt_get_free_context(struct vnt_private *priv) +{ + struct vnt_usb_send_context *context = NULL; + int ii; + + dev_dbg(&priv->usb->dev, "%s\n", __func__); + + for (ii = 0; ii < priv->num_tx_context; ii++) { + if (!priv->tx_context[ii]) + return NULL; + + context = priv->tx_context[ii]; + if (context->in_use == false) { + context->in_use = true; + memset(context->data, 0, + MAX_TOTAL_SIZE_WITH_ALL_HEADERS); + + context->hdr = NULL; + + return context; + } + } + + if (ii == priv->num_tx_context) + dev_dbg(&priv->usb->dev, "%s No Free Tx Context\n", __func__); + + return NULL; +} + +static __le16 vnt_time_stamp_off(struct vnt_private *priv, u16 rate) +{ + return cpu_to_le16(vnt_time_stampoff[priv->preamble_type % 2] + [rate % MAX_RATE]); +} + +static u32 vnt_get_rsvtime(struct vnt_private *priv, u8 pkt_type, + u32 frame_length, u16 rate, int need_ack) +{ + u32 data_time, ack_time; + + data_time = vnt_get_frame_time(priv->preamble_type, pkt_type, + frame_length, rate); + + if (pkt_type == PK_TYPE_11B) + ack_time = vnt_get_frame_time(priv->preamble_type, pkt_type, + 14, (u16)priv->top_cck_basic_rate); + else + ack_time = vnt_get_frame_time(priv->preamble_type, pkt_type, + 14, (u16)priv->top_ofdm_basic_rate); + + if (need_ack) + return data_time + priv->sifs + ack_time; + + return data_time; +} + +static __le16 vnt_rxtx_rsvtime_le16(struct vnt_private *priv, u8 pkt_type, + u32 frame_length, u16 rate, int need_ack) +{ + return cpu_to_le16((u16)vnt_get_rsvtime(priv, pkt_type, + frame_length, rate, need_ack)); +} + +static __le16 vnt_get_rtscts_rsvtime_le(struct vnt_private *priv, + u8 rsv_type, u8 pkt_type, u32 frame_length, u16 current_rate) +{ + u32 rrv_time, rts_time, cts_time, ack_time, data_time; + + rrv_time = rts_time = cts_time = ack_time = data_time = 0; + + data_time = vnt_get_frame_time(priv->preamble_type, pkt_type, + frame_length, current_rate); + + if (rsv_type == 0) { + rts_time = vnt_get_frame_time(priv->preamble_type, + pkt_type, 20, priv->top_cck_basic_rate); + cts_time = ack_time = vnt_get_frame_time(priv->preamble_type, + pkt_type, 14, priv->top_cck_basic_rate); + } else if (rsv_type == 1) { + rts_time = vnt_get_frame_time(priv->preamble_type, + pkt_type, 20, priv->top_cck_basic_rate); + cts_time = vnt_get_frame_time(priv->preamble_type, pkt_type, + 14, priv->top_cck_basic_rate); + ack_time = vnt_get_frame_time(priv->preamble_type, pkt_type, + 14, priv->top_ofdm_basic_rate); + } else if (rsv_type == 2) { + rts_time = vnt_get_frame_time(priv->preamble_type, pkt_type, + 20, priv->top_ofdm_basic_rate); + cts_time = ack_time = vnt_get_frame_time(priv->preamble_type, + pkt_type, 14, priv->top_ofdm_basic_rate); + } else if (rsv_type == 3) { + cts_time = vnt_get_frame_time(priv->preamble_type, pkt_type, + 14, priv->top_cck_basic_rate); + ack_time = vnt_get_frame_time(priv->preamble_type, pkt_type, + 14, priv->top_ofdm_basic_rate); + + rrv_time = cts_time + ack_time + data_time + 2 * priv->sifs; + + return cpu_to_le16((u16)rrv_time); + } + + rrv_time = rts_time + cts_time + ack_time + data_time + 3 * priv->sifs; + + return cpu_to_le16((u16)rrv_time); +} + +static __le16 vnt_get_duration_le(struct vnt_private *priv, + u8 pkt_type, int need_ack) +{ + u32 ack_time = 0; + + if (need_ack) { + if (pkt_type == PK_TYPE_11B) + ack_time = vnt_get_frame_time(priv->preamble_type, + pkt_type, 14, priv->top_cck_basic_rate); + else + ack_time = vnt_get_frame_time(priv->preamble_type, + pkt_type, 14, priv->top_ofdm_basic_rate); + + return cpu_to_le16((u16)(priv->sifs + ack_time)); + } + + return 0; +} + +static __le16 vnt_get_rtscts_duration_le(struct vnt_usb_send_context *context, + u8 dur_type, u8 pkt_type, u16 rate) +{ + struct vnt_private *priv = context->priv; + u32 cts_time = 0, dur_time = 0; + u32 frame_length = context->frame_len; + u8 need_ack = context->need_ack; + + switch (dur_type) { + case RTSDUR_BB: + case RTSDUR_BA: + case RTSDUR_BA_F0: + case RTSDUR_BA_F1: + cts_time = vnt_get_frame_time(priv->preamble_type, + pkt_type, 14, priv->top_cck_basic_rate); + dur_time = cts_time + 2 * priv->sifs + + vnt_get_rsvtime(priv, pkt_type, + frame_length, rate, need_ack); + break; + + case RTSDUR_AA: + case RTSDUR_AA_F0: + case RTSDUR_AA_F1: + cts_time = vnt_get_frame_time(priv->preamble_type, + pkt_type, 14, priv->top_ofdm_basic_rate); + dur_time = cts_time + 2 * priv->sifs + + vnt_get_rsvtime(priv, pkt_type, + frame_length, rate, need_ack); + break; + + case CTSDUR_BA: + case CTSDUR_BA_F0: + case CTSDUR_BA_F1: + dur_time = priv->sifs + vnt_get_rsvtime(priv, + pkt_type, frame_length, rate, need_ack); + break; + + default: + break; + } + + return cpu_to_le16((u16)dur_time); +} + +static u16 vnt_mac_hdr_pos(struct vnt_usb_send_context *tx_context, + struct ieee80211_hdr *hdr) +{ + u8 *head = tx_context->data + offsetof(struct vnt_tx_buffer, fifo_head); + u8 *hdr_pos = (u8 *)hdr; + + tx_context->hdr = hdr; + if (!tx_context->hdr) + return 0; + + return (u16)(hdr_pos - head); +} + +static u16 vnt_rxtx_datahead_g(struct vnt_usb_send_context *tx_context, + struct vnt_tx_datahead_g *buf) +{ + + struct vnt_private *priv = tx_context->priv; + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *)tx_context->skb->data; + u32 frame_len = tx_context->frame_len; + u16 rate = tx_context->tx_rate; + u8 need_ack = tx_context->need_ack; + + /* Get SignalField,ServiceField,Length */ + vnt_get_phy_field(priv, frame_len, rate, tx_context->pkt_type, &buf->a); + vnt_get_phy_field(priv, frame_len, priv->top_cck_basic_rate, + PK_TYPE_11B, &buf->b); + + /* Get Duration and TimeStamp */ + if (ieee80211_is_pspoll(hdr->frame_control)) { + __le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15)); + + buf->duration_a = dur; + buf->duration_b = dur; + } else { + buf->duration_a = vnt_get_duration_le(priv, + tx_context->pkt_type, need_ack); + buf->duration_b = vnt_get_duration_le(priv, + PK_TYPE_11B, need_ack); + } + + buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate); + buf->time_stamp_off_b = vnt_time_stamp_off(priv, + priv->top_cck_basic_rate); + + tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr); + + return le16_to_cpu(buf->duration_a); +} + +static u16 vnt_rxtx_datahead_g_fb(struct vnt_usb_send_context *tx_context, + struct vnt_tx_datahead_g_fb *buf) +{ + struct vnt_private *priv = tx_context->priv; + u32 frame_len = tx_context->frame_len; + u16 rate = tx_context->tx_rate; + u8 need_ack = tx_context->need_ack; + + /* Get SignalField,ServiceField,Length */ + vnt_get_phy_field(priv, frame_len, rate, tx_context->pkt_type, &buf->a); + + vnt_get_phy_field(priv, frame_len, priv->top_cck_basic_rate, + PK_TYPE_11B, &buf->b); + + /* Get Duration and TimeStamp */ + buf->duration_a = vnt_get_duration_le(priv, tx_context->pkt_type, + need_ack); + buf->duration_b = vnt_get_duration_le(priv, PK_TYPE_11B, need_ack); + + buf->duration_a_f0 = vnt_get_duration_le(priv, tx_context->pkt_type, + need_ack); + buf->duration_a_f1 = vnt_get_duration_le(priv, tx_context->pkt_type, + need_ack); + + buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate); + buf->time_stamp_off_b = vnt_time_stamp_off(priv, + priv->top_cck_basic_rate); + + tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr); + + return le16_to_cpu(buf->duration_a); +} + +static u16 vnt_rxtx_datahead_a_fb(struct vnt_usb_send_context *tx_context, + struct vnt_tx_datahead_a_fb *buf) +{ + struct vnt_private *priv = tx_context->priv; + u16 rate = tx_context->tx_rate; + u8 pkt_type = tx_context->pkt_type; + u8 need_ack = tx_context->need_ack; + u32 frame_len = tx_context->frame_len; + + /* Get SignalField,ServiceField,Length */ + vnt_get_phy_field(priv, frame_len, rate, pkt_type, &buf->a); + /* Get Duration and TimeStampOff */ + buf->duration = vnt_get_duration_le(priv, pkt_type, need_ack); + + buf->duration_f0 = vnt_get_duration_le(priv, pkt_type, need_ack); + buf->duration_f1 = vnt_get_duration_le(priv, pkt_type, need_ack); + + buf->time_stamp_off = vnt_time_stamp_off(priv, rate); + + tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr); + + return le16_to_cpu(buf->duration); +} + +static u16 vnt_rxtx_datahead_ab(struct vnt_usb_send_context *tx_context, + struct vnt_tx_datahead_ab *buf) +{ + struct vnt_private *priv = tx_context->priv; + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *)tx_context->skb->data; + u32 frame_len = tx_context->frame_len; + u16 rate = tx_context->tx_rate; + u8 need_ack = tx_context->need_ack; + + /* Get SignalField,ServiceField,Length */ + vnt_get_phy_field(priv, frame_len, rate, + tx_context->pkt_type, &buf->ab); + + /* Get Duration and TimeStampOff */ + if (ieee80211_is_pspoll(hdr->frame_control)) { + __le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15)); + + buf->duration = dur; + } else { + buf->duration = vnt_get_duration_le(priv, tx_context->pkt_type, + need_ack); + } + + buf->time_stamp_off = vnt_time_stamp_off(priv, rate); + + tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr); + + return le16_to_cpu(buf->duration); +} + +static int vnt_fill_ieee80211_rts(struct vnt_usb_send_context *tx_context, + struct ieee80211_rts *rts, __le16 duration) +{ + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *)tx_context->skb->data; + + rts->duration = duration; + rts->frame_control = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); + + ether_addr_copy(rts->ra, hdr->addr1); + ether_addr_copy(rts->ta, hdr->addr2); + + return 0; +} + +static u16 vnt_rxtx_rts_g_head(struct vnt_usb_send_context *tx_context, + struct vnt_rts_g *buf) +{ + struct vnt_private *priv = tx_context->priv; + u16 rts_frame_len = 20; + u16 current_rate = tx_context->tx_rate; + + vnt_get_phy_field(priv, rts_frame_len, priv->top_cck_basic_rate, + PK_TYPE_11B, &buf->b); + vnt_get_phy_field(priv, rts_frame_len, priv->top_ofdm_basic_rate, + tx_context->pkt_type, &buf->a); + + buf->duration_bb = vnt_get_rtscts_duration_le(tx_context, RTSDUR_BB, + PK_TYPE_11B, + priv->top_cck_basic_rate); + buf->duration_aa = vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA, + tx_context->pkt_type, + current_rate); + buf->duration_ba = vnt_get_rtscts_duration_le(tx_context, RTSDUR_BA, + tx_context->pkt_type, + current_rate); + + vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration_aa); + + return vnt_rxtx_datahead_g(tx_context, &buf->data_head); +} + +static u16 vnt_rxtx_rts_g_fb_head(struct vnt_usb_send_context *tx_context, + struct vnt_rts_g_fb *buf) +{ + struct vnt_private *priv = tx_context->priv; + u16 current_rate = tx_context->tx_rate; + u16 rts_frame_len = 20; + + vnt_get_phy_field(priv, rts_frame_len, priv->top_cck_basic_rate, + PK_TYPE_11B, &buf->b); + vnt_get_phy_field(priv, rts_frame_len, priv->top_ofdm_basic_rate, + tx_context->pkt_type, &buf->a); + + buf->duration_bb = vnt_get_rtscts_duration_le(tx_context, RTSDUR_BB, + PK_TYPE_11B, + priv->top_cck_basic_rate); + buf->duration_aa = vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA, + tx_context->pkt_type, + current_rate); + buf->duration_ba = vnt_get_rtscts_duration_le(tx_context, RTSDUR_BA, + tx_context->pkt_type, + current_rate); + + buf->rts_duration_ba_f0 = + vnt_get_rtscts_duration_le(tx_context, RTSDUR_BA_F0, + tx_context->pkt_type, + priv->tx_rate_fb0); + buf->rts_duration_aa_f0 = + vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA_F0, + tx_context->pkt_type, + priv->tx_rate_fb0); + buf->rts_duration_ba_f1 = + vnt_get_rtscts_duration_le(tx_context, RTSDUR_BA_F1, + tx_context->pkt_type, + priv->tx_rate_fb1); + buf->rts_duration_aa_f1 = + vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA_F1, + tx_context->pkt_type, + priv->tx_rate_fb1); + + vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration_aa); + + return vnt_rxtx_datahead_g_fb(tx_context, &buf->data_head); +} + +static u16 vnt_rxtx_rts_ab_head(struct vnt_usb_send_context *tx_context, + struct vnt_rts_ab *buf) +{ + struct vnt_private *priv = tx_context->priv; + u16 current_rate = tx_context->tx_rate; + u16 rts_frame_len = 20; + + vnt_get_phy_field(priv, rts_frame_len, priv->top_ofdm_basic_rate, + tx_context->pkt_type, &buf->ab); + + buf->duration = vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA, + tx_context->pkt_type, + current_rate); + + vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration); + + return vnt_rxtx_datahead_ab(tx_context, &buf->data_head); +} + +static u16 vnt_rxtx_rts_a_fb_head(struct vnt_usb_send_context *tx_context, + struct vnt_rts_a_fb *buf) +{ + struct vnt_private *priv = tx_context->priv; + u16 current_rate = tx_context->tx_rate; + u16 rts_frame_len = 20; + + vnt_get_phy_field(priv, rts_frame_len, + priv->top_ofdm_basic_rate, tx_context->pkt_type, &buf->a); + + buf->duration = vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA, + tx_context->pkt_type, + current_rate); + + buf->rts_duration_f0 = + vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA_F0, + tx_context->pkt_type, + priv->tx_rate_fb0); + + buf->rts_duration_f1 = + vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA_F1, + tx_context->pkt_type, + priv->tx_rate_fb1); + + vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration); + + return vnt_rxtx_datahead_a_fb(tx_context, &buf->data_head); +} + +static u16 vnt_fill_cts_fb_head(struct vnt_usb_send_context *tx_context, + union vnt_tx_data_head *head) +{ + struct vnt_private *priv = tx_context->priv; + struct vnt_cts_fb *buf = &head->cts_g_fb; + u32 cts_frame_len = 14; + u16 current_rate = tx_context->tx_rate; + + /* Get SignalField,ServiceField,Length */ + vnt_get_phy_field(priv, cts_frame_len, priv->top_cck_basic_rate, + PK_TYPE_11B, &buf->b); + + buf->duration_ba = + vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA, + tx_context->pkt_type, + current_rate); + /* Get CTSDuration_ba_f0 */ + buf->cts_duration_ba_f0 = + vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F0, + tx_context->pkt_type, + priv->tx_rate_fb0); + /* Get CTSDuration_ba_f1 */ + buf->cts_duration_ba_f1 = + vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F1, + tx_context->pkt_type, + priv->tx_rate_fb1); + /* Get CTS Frame body */ + buf->data.duration = buf->duration_ba; + buf->data.frame_control = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); + + ether_addr_copy(buf->data.ra, priv->current_net_addr); + + return vnt_rxtx_datahead_g_fb(tx_context, &buf->data_head); +} + +static u16 vnt_fill_cts_head(struct vnt_usb_send_context *tx_context, + union vnt_tx_data_head *head) +{ + struct vnt_private *priv = tx_context->priv; + struct vnt_cts *buf = &head->cts_g; + u32 cts_frame_len = 14; + u16 current_rate = tx_context->tx_rate; + + /* Get SignalField,ServiceField,Length */ + vnt_get_phy_field(priv, cts_frame_len, priv->top_cck_basic_rate, + PK_TYPE_11B, &buf->b); + /* Get CTSDuration_ba */ + buf->duration_ba = + vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA, + tx_context->pkt_type, + current_rate); + /*Get CTS Frame body*/ + buf->data.duration = buf->duration_ba; + buf->data.frame_control = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); + + ether_addr_copy(buf->data.ra, priv->current_net_addr); + + return vnt_rxtx_datahead_g(tx_context, &buf->data_head); +} + +static u16 vnt_rxtx_rts(struct vnt_usb_send_context *tx_context, + union vnt_tx_head *tx_head, bool need_mic) +{ + struct vnt_private *priv = tx_context->priv; + struct vnt_rrv_time_rts *buf = &tx_head->tx_rts.rts; + union vnt_tx_data_head *head = &tx_head->tx_rts.tx.head; + u32 frame_len = tx_context->frame_len; + u16 current_rate = tx_context->tx_rate; + u8 need_ack = tx_context->need_ack; + + buf->rts_rrv_time_aa = vnt_get_rtscts_rsvtime_le(priv, 2, + tx_context->pkt_type, frame_len, current_rate); + buf->rts_rrv_time_ba = vnt_get_rtscts_rsvtime_le(priv, 1, + tx_context->pkt_type, frame_len, current_rate); + buf->rts_rrv_time_bb = vnt_get_rtscts_rsvtime_le(priv, 0, + tx_context->pkt_type, frame_len, current_rate); + + buf->rrv_time_a = vnt_rxtx_rsvtime_le16(priv, tx_context->pkt_type, + frame_len, current_rate, + need_ack); + buf->rrv_time_b = vnt_rxtx_rsvtime_le16(priv, PK_TYPE_11B, frame_len, + priv->top_cck_basic_rate, need_ack); + + if (need_mic) + head = &tx_head->tx_rts.tx.mic.head; + + if (tx_context->fb_option) + return vnt_rxtx_rts_g_fb_head(tx_context, &head->rts_g_fb); + + return vnt_rxtx_rts_g_head(tx_context, &head->rts_g); +} + +static u16 vnt_rxtx_cts(struct vnt_usb_send_context *tx_context, + union vnt_tx_head *tx_head, bool need_mic) +{ + struct vnt_private *priv = tx_context->priv; + struct vnt_rrv_time_cts *buf = &tx_head->tx_cts.cts; + union vnt_tx_data_head *head = &tx_head->tx_cts.tx.head; + u32 frame_len = tx_context->frame_len; + u16 current_rate = tx_context->tx_rate; + u8 need_ack = tx_context->need_ack; + + buf->rrv_time_a = vnt_rxtx_rsvtime_le16(priv, tx_context->pkt_type, + frame_len, current_rate, need_ack); + buf->rrv_time_b = vnt_rxtx_rsvtime_le16(priv, PK_TYPE_11B, + frame_len, priv->top_cck_basic_rate, need_ack); + + buf->cts_rrv_time_ba = vnt_get_rtscts_rsvtime_le(priv, 3, + tx_context->pkt_type, frame_len, current_rate); + + if (need_mic) + head = &tx_head->tx_cts.tx.mic.head; + + /* Fill CTS */ + if (tx_context->fb_option) + return vnt_fill_cts_fb_head(tx_context, head); + + return vnt_fill_cts_head(tx_context, head); +} + +static u16 vnt_rxtx_ab(struct vnt_usb_send_context *tx_context, + union vnt_tx_head *tx_head, bool need_rts, bool need_mic) +{ + struct vnt_private *priv = tx_context->priv; + struct vnt_rrv_time_ab *buf = &tx_head->tx_ab.ab; + union vnt_tx_data_head *head = &tx_head->tx_ab.tx.head; + u32 frame_len = tx_context->frame_len; + u16 current_rate = tx_context->tx_rate; + u8 need_ack = tx_context->need_ack; + + buf->rrv_time = vnt_rxtx_rsvtime_le16(priv, tx_context->pkt_type, + frame_len, current_rate, need_ack); + + if (need_mic) + head = &tx_head->tx_ab.tx.mic.head; + + if (need_rts) { + if (tx_context->pkt_type == PK_TYPE_11B) + buf->rts_rrv_time = vnt_get_rtscts_rsvtime_le(priv, 0, + tx_context->pkt_type, frame_len, current_rate); + else /* PK_TYPE_11A */ + buf->rts_rrv_time = vnt_get_rtscts_rsvtime_le(priv, 2, + tx_context->pkt_type, frame_len, current_rate); + + if (tx_context->fb_option && + tx_context->pkt_type == PK_TYPE_11A) + return vnt_rxtx_rts_a_fb_head(tx_context, + &head->rts_a_fb); + + return vnt_rxtx_rts_ab_head(tx_context, &head->rts_ab); + } + + if (tx_context->pkt_type == PK_TYPE_11A) + return vnt_rxtx_datahead_a_fb(tx_context, + &head->data_head_a_fb); + + return vnt_rxtx_datahead_ab(tx_context, &head->data_head_ab); +} + +static u16 vnt_generate_tx_parameter(struct vnt_usb_send_context *tx_context, + struct vnt_tx_buffer *tx_buffer, + struct vnt_mic_hdr **mic_hdr, u32 need_mic, + bool need_rts) +{ + + if (tx_context->pkt_type == PK_TYPE_11GB || + tx_context->pkt_type == PK_TYPE_11GA) { + if (need_rts) { + if (need_mic) + *mic_hdr = &tx_buffer-> + tx_head.tx_rts.tx.mic.hdr; + + return vnt_rxtx_rts(tx_context, &tx_buffer->tx_head, + need_mic); + } + + if (need_mic) + *mic_hdr = &tx_buffer->tx_head.tx_cts.tx.mic.hdr; + + return vnt_rxtx_cts(tx_context, &tx_buffer->tx_head, need_mic); + } + + if (need_mic) + *mic_hdr = &tx_buffer->tx_head.tx_ab.tx.mic.hdr; + + return vnt_rxtx_ab(tx_context, &tx_buffer->tx_head, need_rts, need_mic); +} + +static void vnt_fill_txkey(struct vnt_usb_send_context *tx_context, + u8 *key_buffer, struct ieee80211_key_conf *tx_key, struct sk_buff *skb, + u16 payload_len, struct vnt_mic_hdr *mic_hdr) +{ + struct ieee80211_hdr *hdr = tx_context->hdr; + struct ieee80211_key_seq seq; + u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb)); + + /* strip header and icv len from payload */ + payload_len -= ieee80211_get_hdrlen_from_skb(skb); + payload_len -= tx_key->icv_len; + + switch (tx_key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + memcpy(key_buffer, iv, 3); + memcpy(key_buffer + 3, tx_key->key, tx_key->keylen); + + if (tx_key->keylen == WLAN_KEY_LEN_WEP40) { + memcpy(key_buffer + 8, iv, 3); + memcpy(key_buffer + 11, + tx_key->key, WLAN_KEY_LEN_WEP40); + } + + break; + case WLAN_CIPHER_SUITE_TKIP: + ieee80211_get_tkip_p2k(tx_key, skb, key_buffer); + + break; + case WLAN_CIPHER_SUITE_CCMP: + + if (!mic_hdr) + return; + + mic_hdr->id = 0x59; + mic_hdr->payload_len = cpu_to_be16(payload_len); + ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2); + + ieee80211_get_key_tx_seq(tx_key, &seq); + + memcpy(mic_hdr->ccmp_pn, seq.ccmp.pn, IEEE80211_CCMP_PN_LEN); + + if (ieee80211_has_a4(hdr->frame_control)) + mic_hdr->hlen = cpu_to_be16(28); + else + mic_hdr->hlen = cpu_to_be16(22); + + ether_addr_copy(mic_hdr->addr1, hdr->addr1); + ether_addr_copy(mic_hdr->addr2, hdr->addr2); + ether_addr_copy(mic_hdr->addr3, hdr->addr3); + + mic_hdr->frame_control = cpu_to_le16( + le16_to_cpu(hdr->frame_control) & 0xc78f); + mic_hdr->seq_ctrl = cpu_to_le16( + le16_to_cpu(hdr->seq_ctrl) & 0xf); + + if (ieee80211_has_a4(hdr->frame_control)) + ether_addr_copy(mic_hdr->addr4, hdr->addr4); + + + memcpy(key_buffer, tx_key->key, WLAN_KEY_LEN_CCMP); + + break; + default: + break; + } + +} + +int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *tx_rate = &info->control.rates[0]; + struct ieee80211_rate *rate; + struct ieee80211_key_conf *tx_key; + struct ieee80211_hdr *hdr; + struct vnt_mic_hdr *mic_hdr = NULL; + struct vnt_tx_buffer *tx_buffer; + struct vnt_tx_fifo_head *tx_buffer_head; + struct vnt_usb_send_context *tx_context; + unsigned long flags; + u16 tx_bytes, tx_header_size, tx_body_size, current_rate, duration_id; + u8 pkt_type, fb_option = AUTO_FB_NONE; + bool need_rts = false, is_pspoll = false; + bool need_mic = false; + + hdr = (struct ieee80211_hdr *)(skb->data); + + rate = ieee80211_get_tx_rate(priv->hw, info); + + current_rate = rate->hw_value; + if (priv->current_rate != current_rate && + !(priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { + priv->current_rate = current_rate; + vnt_schedule_command(priv, WLAN_CMD_SETPOWER); + } + + if (current_rate > RATE_11M) { + if (info->band == IEEE80211_BAND_5GHZ) { + pkt_type = PK_TYPE_11A; + } else { + if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + pkt_type = PK_TYPE_11GB; + else + pkt_type = PK_TYPE_11GA; + } + } else { + pkt_type = PK_TYPE_11B; + } + + spin_lock_irqsave(&priv->lock, flags); + + tx_context = vnt_get_free_context(priv); + if (!tx_context) { + dev_dbg(&priv->usb->dev, "%s No free context\n", __func__); + spin_unlock_irqrestore(&priv->lock, flags); + return -ENOMEM; + } + + tx_context->skb = skb; + tx_context->pkt_type = pkt_type; + tx_context->need_ack = false; + tx_context->frame_len = skb->len + 4; + tx_context->tx_rate = current_rate; + + spin_unlock_irqrestore(&priv->lock, flags); + + tx_buffer = (struct vnt_tx_buffer *)tx_context->data; + tx_buffer_head = &tx_buffer->fifo_head; + tx_body_size = skb->len; + + /*Set fifo controls */ + if (pkt_type == PK_TYPE_11A) + tx_buffer_head->fifo_ctl = 0; + else if (pkt_type == PK_TYPE_11B) + tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11B); + else if (pkt_type == PK_TYPE_11GB) + tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11GB); + else if (pkt_type == PK_TYPE_11GA) + tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11GA); + + if (!ieee80211_is_data(hdr->frame_control)) { + tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_GENINT | + FIFOCTL_ISDMA0); + tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_TMOEN); + + tx_buffer_head->time_stamp = + cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); + } else { + tx_buffer_head->time_stamp = + cpu_to_le16(DEFAULT_MSDU_LIFETIME_RES_64us); + } + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { + tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_NEEDACK); + tx_context->need_ack = true; + } + + if (ieee80211_has_retry(hdr->frame_control)) + tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_LRETRY); + + if (tx_rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + priv->preamble_type = PREAMBLE_SHORT; + else + priv->preamble_type = PREAMBLE_LONG; + + if (tx_rate->flags & IEEE80211_TX_RC_USE_RTS_CTS) { + need_rts = true; + tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_RTS); + } + + if (ieee80211_has_a4(hdr->frame_control)) + tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_LHEAD); + + if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) + is_pspoll = true; + + tx_buffer_head->frag_ctl = + cpu_to_le16(ieee80211_get_hdrlen_from_skb(skb) << 10); + + if (info->control.hw_key) { + tx_key = info->control.hw_key; + switch (info->control.hw_key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_LEGACY); + break; + case WLAN_CIPHER_SUITE_TKIP: + tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_TKIP); + break; + case WLAN_CIPHER_SUITE_CCMP: + tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_AES); + need_mic = true; + default: + break; + } + tx_context->frame_len += tx_key->icv_len; + } + + tx_buffer_head->current_rate = cpu_to_le16(current_rate); + + /* legacy rates TODO use ieee80211_tx_rate */ + if (current_rate >= RATE_18M && ieee80211_is_data(hdr->frame_control)) { + if (priv->auto_fb_ctrl == AUTO_FB_0) { + tx_buffer_head->fifo_ctl |= + cpu_to_le16(FIFOCTL_AUTO_FB_0); + + priv->tx_rate_fb0 = + vnt_fb_opt0[FB_RATE0][current_rate - RATE_18M]; + priv->tx_rate_fb1 = + vnt_fb_opt0[FB_RATE1][current_rate - RATE_18M]; + + fb_option = AUTO_FB_0; + } else if (priv->auto_fb_ctrl == AUTO_FB_1) { + tx_buffer_head->fifo_ctl |= + cpu_to_le16(FIFOCTL_AUTO_FB_1); + + priv->tx_rate_fb0 = + vnt_fb_opt1[FB_RATE0][current_rate - RATE_18M]; + priv->tx_rate_fb1 = + vnt_fb_opt1[FB_RATE1][current_rate - RATE_18M]; + + fb_option = AUTO_FB_1; + } + } + + tx_context->fb_option = fb_option; + + duration_id = vnt_generate_tx_parameter(tx_context, tx_buffer, &mic_hdr, + need_mic, need_rts); + + tx_header_size = tx_context->tx_hdr_size; + if (!tx_header_size) { + tx_context->in_use = false; + return -ENOMEM; + } + + tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_NONFRAG); + + tx_bytes = tx_header_size + tx_body_size; + + memcpy(tx_context->hdr, skb->data, tx_body_size); + + hdr->duration_id = cpu_to_le16(duration_id); + + if (info->control.hw_key) { + tx_key = info->control.hw_key; + if (tx_key->keylen > 0) + vnt_fill_txkey(tx_context, tx_buffer_head->tx_key, + tx_key, skb, tx_body_size, mic_hdr); + } + + priv->seq_counter = (le16_to_cpu(hdr->seq_ctrl) & + IEEE80211_SCTL_SEQ) >> 4; + + tx_buffer->tx_byte_count = cpu_to_le16(tx_bytes); + tx_buffer->pkt_no = tx_context->pkt_no; + tx_buffer->type = 0x00; + + tx_bytes += 4; + + tx_context->type = CONTEXT_DATA_PACKET; + tx_context->buf_len = tx_bytes; + + spin_lock_irqsave(&priv->lock, flags); + + if (vnt_tx_context(priv, tx_context) != STATUS_PENDING) { + spin_unlock_irqrestore(&priv->lock, flags); + return -EIO; + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int vnt_beacon_xmit(struct vnt_private *priv, + struct sk_buff *skb) +{ + struct vnt_beacon_buffer *beacon_buffer; + struct vnt_tx_short_buf_head *short_head; + struct ieee80211_tx_info *info; + struct vnt_usb_send_context *context; + struct ieee80211_mgmt *mgmt_hdr; + unsigned long flags; + u32 frame_size = skb->len + 4; + u16 current_rate, count; + + spin_lock_irqsave(&priv->lock, flags); + + context = vnt_get_free_context(priv); + if (!context) { + dev_dbg(&priv->usb->dev, "%s No free context!\n", __func__); + spin_unlock_irqrestore(&priv->lock, flags); + return -ENOMEM; + } + + context->skb = skb; + + spin_unlock_irqrestore(&priv->lock, flags); + + beacon_buffer = (struct vnt_beacon_buffer *)&context->data[0]; + short_head = &beacon_buffer->short_head; + + if (priv->bb_type == BB_TYPE_11A) { + current_rate = RATE_6M; + + /* Get SignalField,ServiceField,Length */ + vnt_get_phy_field(priv, frame_size, current_rate, + PK_TYPE_11A, &short_head->ab); + + /* Get Duration and TimeStampOff */ + short_head->duration = vnt_get_duration_le(priv, + PK_TYPE_11A, false); + short_head->time_stamp_off = + vnt_time_stamp_off(priv, current_rate); + } else { + current_rate = RATE_1M; + short_head->fifo_ctl |= cpu_to_le16(FIFOCTL_11B); + + /* Get SignalField,ServiceField,Length */ + vnt_get_phy_field(priv, frame_size, current_rate, + PK_TYPE_11B, &short_head->ab); + + /* Get Duration and TimeStampOff */ + short_head->duration = vnt_get_duration_le(priv, + PK_TYPE_11B, false); + short_head->time_stamp_off = + vnt_time_stamp_off(priv, current_rate); + } + + /* Generate Beacon Header */ + mgmt_hdr = &beacon_buffer->mgmt_hdr; + memcpy(mgmt_hdr, skb->data, skb->len); + + /* time stamp always 0 */ + mgmt_hdr->u.beacon.timestamp = 0; + + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)mgmt_hdr; + + hdr->duration_id = 0; + hdr->seq_ctrl = cpu_to_le16(priv->seq_counter << 4); + } + + priv->seq_counter++; + if (priv->seq_counter > 0x0fff) + priv->seq_counter = 0; + + count = sizeof(struct vnt_tx_short_buf_head) + skb->len; + + beacon_buffer->tx_byte_count = cpu_to_le16(count); + beacon_buffer->pkt_no = context->pkt_no; + beacon_buffer->type = 0x01; + + context->type = CONTEXT_BEACON_PACKET; + context->buf_len = count + 4; /* USB header */ + + spin_lock_irqsave(&priv->lock, flags); + + if (vnt_tx_context(priv, context) != STATUS_PENDING) + ieee80211_free_txskb(priv->hw, context->skb); + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif) +{ + struct sk_buff *beacon; + + beacon = ieee80211_beacon_get(priv->hw, vif); + if (!beacon) + return -ENOMEM; + + if (vnt_beacon_xmit(priv, beacon)) { + ieee80211_free_txskb(priv->hw, beacon); + return -ENODEV; + } + + return 0; +} + +int vnt_beacon_enable(struct vnt_private *priv, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf) +{ + vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX); + + vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + + vnt_mac_set_beacon_interval(priv, conf->beacon_int); + + vnt_clear_current_tsf(priv); + + vnt_mac_reg_bits_on(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + + vnt_reset_next_tbtt(priv, conf->beacon_int); + + return vnt_beacon_make(priv, vif); +} diff --git a/kernel/drivers/staging/vt6656/rxtx.h b/kernel/drivers/staging/vt6656/rxtx.h new file mode 100644 index 000000000..90b34ab2f --- /dev/null +++ b/kernel/drivers/staging/vt6656/rxtx.h @@ -0,0 +1,260 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: rxtx.h + * + * Purpose: + * + * Author: Jerry Chen + * + * Date: Jun. 27, 2002 + * + */ + +#ifndef __RXTX_H__ +#define __RXTX_H__ + +#include "device.h" +#include "wcmd.h" +#include "baseband.h" + +#define DEFAULT_MGN_LIFETIME_RES_64us 125 /* 64us */ +#define DEFAULT_MSDU_LIFETIME_RES_64us 8000 + +/* MIC HDR data header */ +struct vnt_mic_hdr { + u8 id; + u8 tx_priority; + u8 mic_addr2[6]; + u8 ccmp_pn[IEEE80211_CCMP_PN_LEN]; + __be16 payload_len; + __be16 hlen; + __le16 frame_control; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + __le16 seq_ctrl; + u8 addr4[6]; + u16 packing; /* packing to 48 bytes */ +} __packed; + +/* RsvTime buffer header */ +struct vnt_rrv_time_rts { + __le16 rts_rrv_time_ba; + __le16 rts_rrv_time_aa; + __le16 rts_rrv_time_bb; + u16 wReserved; + __le16 rrv_time_b; + __le16 rrv_time_a; +} __packed; + +struct vnt_rrv_time_cts { + __le16 cts_rrv_time_ba; + u16 wReserved; + __le16 rrv_time_b; + __le16 rrv_time_a; +} __packed; + +struct vnt_rrv_time_ab { + __le16 rts_rrv_time; + __le16 rrv_time; +} __packed; + +/* TX data header */ +struct vnt_tx_datahead_g { + struct vnt_phy_field b; + struct vnt_phy_field a; + __le16 duration_b; + __le16 duration_a; + __le16 time_stamp_off_b; + __le16 time_stamp_off_a; + struct ieee80211_hdr hdr; +} __packed; + +struct vnt_tx_datahead_g_fb { + struct vnt_phy_field b; + struct vnt_phy_field a; + __le16 duration_b; + __le16 duration_a; + __le16 duration_a_f0; + __le16 duration_a_f1; + __le16 time_stamp_off_b; + __le16 time_stamp_off_a; + struct ieee80211_hdr hdr; +} __packed; + +struct vnt_tx_datahead_ab { + struct vnt_phy_field ab; + __le16 duration; + __le16 time_stamp_off; + struct ieee80211_hdr hdr; +} __packed; + +struct vnt_tx_datahead_a_fb { + struct vnt_phy_field a; + __le16 duration; + __le16 time_stamp_off; + __le16 duration_f0; + __le16 duration_f1; + struct ieee80211_hdr hdr; +} __packed; + +/* RTS buffer header */ +struct vnt_rts_g { + struct vnt_phy_field b; + struct vnt_phy_field a; + __le16 duration_ba; + __le16 duration_aa; + __le16 duration_bb; + u16 wReserved; + struct ieee80211_rts data; + struct vnt_tx_datahead_g data_head; +} __packed; + +struct vnt_rts_g_fb { + struct vnt_phy_field b; + struct vnt_phy_field a; + __le16 duration_ba; + __le16 duration_aa; + __le16 duration_bb; + u16 wReserved; + __le16 rts_duration_ba_f0; + __le16 rts_duration_aa_f0; + __le16 rts_duration_ba_f1; + __le16 rts_duration_aa_f1; + struct ieee80211_rts data; + struct vnt_tx_datahead_g_fb data_head; +} __packed; + +struct vnt_rts_ab { + struct vnt_phy_field ab; + __le16 duration; + u16 wReserved; + struct ieee80211_rts data; + struct vnt_tx_datahead_ab data_head; +} __packed; + +struct vnt_rts_a_fb { + struct vnt_phy_field a; + __le16 duration; + u16 wReserved; + __le16 rts_duration_f0; + __le16 rts_duration_f1; + struct ieee80211_rts data; + struct vnt_tx_datahead_a_fb data_head; +} __packed; + +/* CTS buffer header */ +struct vnt_cts { + struct vnt_phy_field b; + __le16 duration_ba; + u16 wReserved; + struct ieee80211_cts data; + u16 reserved2; + struct vnt_tx_datahead_g data_head; +} __packed; + +struct vnt_cts_fb { + struct vnt_phy_field b; + __le16 duration_ba; + u16 wReserved; + __le16 cts_duration_ba_f0; + __le16 cts_duration_ba_f1; + struct ieee80211_cts data; + u16 reserved2; + struct vnt_tx_datahead_g_fb data_head; +} __packed; + +union vnt_tx_data_head { + /* rts g */ + struct vnt_rts_g rts_g; + struct vnt_rts_g_fb rts_g_fb; + /* rts a/b */ + struct vnt_rts_ab rts_ab; + struct vnt_rts_a_fb rts_a_fb; + /* cts g */ + struct vnt_cts cts_g; + struct vnt_cts_fb cts_g_fb; + /* no rts/cts */ + struct vnt_tx_datahead_a_fb data_head_a_fb; + struct vnt_tx_datahead_ab data_head_ab; +}; + +struct vnt_tx_mic_hdr { + struct vnt_mic_hdr hdr; + union vnt_tx_data_head head; +} __packed; + +union vnt_tx { + struct vnt_tx_mic_hdr mic; + union vnt_tx_data_head head; +}; + +union vnt_tx_head { + struct { + struct vnt_rrv_time_rts rts; + union vnt_tx tx; + } __packed tx_rts; + struct { + struct vnt_rrv_time_cts cts; + union vnt_tx tx; + } __packed tx_cts; + struct { + struct vnt_rrv_time_ab ab; + union vnt_tx tx; + } __packed tx_ab; +}; + +struct vnt_tx_fifo_head { + u8 tx_key[WLAN_KEY_LEN_CCMP]; + __le16 fifo_ctl; + __le16 time_stamp; + __le16 frag_ctl; + __le16 current_rate; +} __packed; + +struct vnt_tx_buffer { + u8 type; + u8 pkt_no; + __le16 tx_byte_count; + struct vnt_tx_fifo_head fifo_head; + union vnt_tx_head tx_head; +} __packed; + +struct vnt_tx_short_buf_head { + __le16 fifo_ctl; + u16 time_stamp; + struct vnt_phy_field ab; + __le16 duration; + __le16 time_stamp_off; +} __packed; + +struct vnt_beacon_buffer { + u8 type; + u8 pkt_no; + __le16 tx_byte_count; + struct vnt_tx_short_buf_head short_head; + struct ieee80211_mgmt mgmt_hdr; +} __packed; + +int vnt_tx_packet(struct vnt_private *, struct sk_buff *); +int vnt_beacon_make(struct vnt_private *, struct ieee80211_vif *); +int vnt_beacon_enable(struct vnt_private *, struct ieee80211_vif *, + struct ieee80211_bss_conf *); + +#endif /* __RXTX_H__ */ diff --git a/kernel/drivers/staging/vt6656/usbpipe.c b/kernel/drivers/staging/vt6656/usbpipe.c new file mode 100644 index 000000000..88bf518f2 --- /dev/null +++ b/kernel/drivers/staging/vt6656/usbpipe.c @@ -0,0 +1,308 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: usbpipe.c + * + * Purpose: Handle USB control endpoint + * + * Author: Warren Hsu + * + * Date: Mar. 29, 2005 + * + * Functions: + * vnt_control_out - Write variable length bytes to MEM/BB/MAC/EEPROM + * vnt_control_in - Read variable length bytes from MEM/BB/MAC/EEPROM + * vnt_control_out_u8 - Write one byte to MEM/BB/MAC/EEPROM + * vnt_control_in_u8 - Read one byte from MEM/BB/MAC/EEPROM + * + * Revision History: + * 04-05-2004 Jerry Chen: Initial release + * 11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte,ControlvMaskByte + * + */ + +#include "int.h" +#include "rxtx.h" +#include "dpc.h" +#include "desc.h" +#include "device.h" +#include "usbpipe.h" + +#define USB_CTL_WAIT 500 /* ms */ + +int vnt_control_out(struct vnt_private *priv, u8 request, u16 value, + u16 index, u16 length, u8 *buffer) +{ + int status = 0; + + if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) + return STATUS_FAILURE; + + mutex_lock(&priv->usb_lock); + + status = usb_control_msg(priv->usb, + usb_sndctrlpipe(priv->usb, 0), request, 0x40, value, + index, buffer, length, USB_CTL_WAIT); + + mutex_unlock(&priv->usb_lock); + + if (status < (int)length) + return STATUS_FAILURE; + + return STATUS_SUCCESS; +} + +void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data) +{ + vnt_control_out(priv, MESSAGE_TYPE_WRITE, + reg_off, reg, sizeof(u8), &data); +} + +int vnt_control_in(struct vnt_private *priv, u8 request, u16 value, + u16 index, u16 length, u8 *buffer) +{ + int status; + + if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) + return STATUS_FAILURE; + + mutex_lock(&priv->usb_lock); + + status = usb_control_msg(priv->usb, + usb_rcvctrlpipe(priv->usb, 0), request, 0xc0, value, + index, buffer, length, USB_CTL_WAIT); + + mutex_unlock(&priv->usb_lock); + + if (status < (int)length) + return STATUS_FAILURE; + + return STATUS_SUCCESS; +} + +void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data) +{ + vnt_control_in(priv, MESSAGE_TYPE_READ, + reg_off, reg, sizeof(u8), data); +} + +static void vnt_start_interrupt_urb_complete(struct urb *urb) +{ + struct vnt_private *priv = urb->context; + int status; + + switch (urb->status) { + case 0: + case -ETIMEDOUT: + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + priv->int_buf.in_use = false; + return; + default: + break; + } + + status = urb->status; + + if (status != STATUS_SUCCESS) { + priv->int_buf.in_use = false; + + dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status); + } else { + vnt_int_process_data(priv); + } + + status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC); + if (status) + dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); + else + priv->int_buf.in_use = true; +} + +int vnt_start_interrupt_urb(struct vnt_private *priv) +{ + int status = STATUS_FAILURE; + + if (priv->int_buf.in_use == true) + return STATUS_FAILURE; + + priv->int_buf.in_use = true; + + usb_fill_int_urb(priv->interrupt_urb, + priv->usb, + usb_rcvintpipe(priv->usb, 1), + priv->int_buf.data_buf, + MAX_INTERRUPT_SIZE, + vnt_start_interrupt_urb_complete, + priv, + priv->int_interval); + + status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC); + if (status) { + dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); + priv->int_buf.in_use = false; + } + + return status; +} + +static void vnt_submit_rx_urb_complete(struct urb *urb) +{ + struct vnt_rcb *rcb = urb->context; + struct vnt_private *priv = rcb->priv; + unsigned long flags; + + switch (urb->status) { + case 0: + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + case -ETIMEDOUT: + default: + dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status); + break; + } + + if (urb->actual_length) { + spin_lock_irqsave(&priv->lock, flags); + + if (vnt_rx_data(priv, rcb, urb->actual_length)) { + rcb->skb = dev_alloc_skb(priv->rx_buf_sz); + if (!rcb->skb) { + dev_dbg(&priv->usb->dev, + "Failed to re-alloc rx skb\n"); + + rcb->in_use = false; + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + } else { + skb_push(rcb->skb, skb_headroom(rcb->skb)); + skb_trim(rcb->skb, 0); + } + + urb->transfer_buffer = skb_put(rcb->skb, + skb_tailroom(rcb->skb)); + + spin_unlock_irqrestore(&priv->lock, flags); + } + + if (usb_submit_urb(urb, GFP_ATOMIC)) { + dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n"); + + rcb->in_use = false; + } +} + +int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb) +{ + int status = 0; + struct urb *urb; + + urb = rcb->urb; + if (rcb->skb == NULL) { + dev_dbg(&priv->usb->dev, "rcb->skb is null\n"); + return status; + } + + usb_fill_bulk_urb(urb, + priv->usb, + usb_rcvbulkpipe(priv->usb, 2), + skb_put(rcb->skb, skb_tailroom(rcb->skb)), + MAX_TOTAL_SIZE_WITH_ALL_HEADERS, + vnt_submit_rx_urb_complete, + rcb); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status != 0) { + dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status); + return STATUS_FAILURE; + } + + rcb->in_use = true; + + return status; +} + +static void vnt_tx_context_complete(struct urb *urb) +{ + struct vnt_usb_send_context *context = urb->context; + struct vnt_private *priv = context->priv; + + switch (urb->status) { + case 0: + dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len); + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + context->in_use = false; + return; + case -ETIMEDOUT: + default: + dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status); + break; + } + + if (context->type == CONTEXT_DATA_PACKET) + ieee80211_wake_queues(priv->hw); + + if (urb->status || context->type == CONTEXT_BEACON_PACKET) { + if (context->skb) + ieee80211_free_txskb(priv->hw, context->skb); + + context->in_use = false; + } +} + +int vnt_tx_context(struct vnt_private *priv, + struct vnt_usb_send_context *context) +{ + int status; + struct urb *urb; + + if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) { + context->in_use = false; + return STATUS_RESOURCES; + } + + urb = context->urb; + + usb_fill_bulk_urb(urb, + priv->usb, + usb_sndbulkpipe(priv->usb, 3), + context->data, + context->buf_len, + vnt_tx_context_complete, + context); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status != 0) { + dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status); + + context->in_use = false; + return STATUS_FAILURE; + } + + return STATUS_PENDING; +} diff --git a/kernel/drivers/staging/vt6656/usbpipe.h b/kernel/drivers/staging/vt6656/usbpipe.h new file mode 100644 index 000000000..e74aa0809 --- /dev/null +++ b/kernel/drivers/staging/vt6656/usbpipe.h @@ -0,0 +1,45 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: usbpipe.h + * + * Purpose: + * + * Author: Warren Hsu + * + * Date: Mar. 30, 2005 + * + */ + +#ifndef __USBPIPE_H__ +#define __USBPIPE_H__ + +#include "device.h" + +int vnt_control_out(struct vnt_private *, u8, u16, u16, u16, u8 *); +int vnt_control_in(struct vnt_private *, u8, u16, u16, u16, u8 *); + +void vnt_control_out_u8(struct vnt_private *, u8, u8, u8); +void vnt_control_in_u8(struct vnt_private *, u8, u8, u8 *); + +int vnt_start_interrupt_urb(struct vnt_private *); +int vnt_submit_rx_urb(struct vnt_private *, struct vnt_rcb *); +int vnt_tx_context(struct vnt_private *, struct vnt_usb_send_context *); + +#endif /* __USBPIPE_H__ */ diff --git a/kernel/drivers/staging/vt6656/wcmd.c b/kernel/drivers/staging/vt6656/wcmd.c new file mode 100644 index 000000000..3cbf4791b --- /dev/null +++ b/kernel/drivers/staging/vt6656/wcmd.c @@ -0,0 +1,194 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wcmd.c + * + * Purpose: Handles the management command interface functions + * + * Author: Lyndon Chen + * + * Date: May 8, 2003 + * + * Functions: + * vnt_cmd_complete - Command Complete function + * vnt_schedule_command - Push Command and wait Command Scheduler to do + * vnt_cmd_timer_wait- Call back timer + * + * Revision History: + * + */ + +#include "device.h" +#include "mac.h" +#include "wcmd.h" +#include "power.h" +#include "usbpipe.h" +#include "rxtx.h" +#include "rf.h" + +static void vnt_cmd_timer_wait(struct vnt_private *priv, unsigned long msecs) +{ + schedule_delayed_work(&priv->run_command_work, msecs_to_jiffies(msecs)); +} + +static int vnt_cmd_complete(struct vnt_private *priv) +{ + + priv->command_state = WLAN_CMD_IDLE; + if (priv->free_cmd_queue == CMD_Q_SIZE) { + /* Command Queue Empty */ + priv->cmd_running = false; + return true; + } + + priv->command = priv->cmd_queue[priv->cmd_dequeue_idx]; + + ADD_ONE_WITH_WRAP_AROUND(priv->cmd_dequeue_idx, CMD_Q_SIZE); + priv->free_cmd_queue++; + priv->cmd_running = true; + + switch (priv->command) { + case WLAN_CMD_INIT_MAC80211: + priv->command_state = WLAN_CMD_INIT_MAC80211_START; + break; + + case WLAN_CMD_TBTT_WAKEUP: + priv->command_state = WLAN_CMD_TBTT_WAKEUP_START; + break; + + case WLAN_CMD_BECON_SEND: + priv->command_state = WLAN_CMD_BECON_SEND_START; + break; + + case WLAN_CMD_SETPOWER: + priv->command_state = WLAN_CMD_SETPOWER_START; + break; + + case WLAN_CMD_CHANGE_ANTENNA: + priv->command_state = WLAN_CMD_CHANGE_ANTENNA_START; + break; + + default: + break; + } + + vnt_cmd_timer_wait(priv, 0); + + return true; +} + +void vnt_run_command(struct work_struct *work) +{ + struct vnt_private *priv = + container_of(work, struct vnt_private, run_command_work.work); + + if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) + return; + + if (priv->cmd_running != true) + return; + + switch (priv->command_state) { + case WLAN_CMD_INIT_MAC80211_START: + if (priv->mac_hw) + break; + + dev_info(&priv->usb->dev, "Starting mac80211\n"); + + if (vnt_init(priv)) { + /* If fail all ends TODO retry */ + dev_err(&priv->usb->dev, "failed to start\n"); + ieee80211_free_hw(priv->hw); + return; + } + + break; + + case WLAN_CMD_TBTT_WAKEUP_START: + vnt_next_tbtt_wakeup(priv); + break; + + case WLAN_CMD_BECON_SEND_START: + if (!priv->vif) + break; + + vnt_beacon_make(priv, priv->vif); + + vnt_mac_reg_bits_on(priv, MAC_REG_TCR, TCR_AUTOBCNTX); + + break; + + case WLAN_CMD_SETPOWER_START: + + vnt_rf_setpower(priv, priv->current_rate, + priv->hw->conf.chandef.chan->hw_value); + + break; + + case WLAN_CMD_CHANGE_ANTENNA_START: + dev_dbg(&priv->usb->dev, "Change from Antenna%d to", + priv->rx_antenna_sel); + + if (priv->rx_antenna_sel == 0) { + priv->rx_antenna_sel = 1; + if (priv->tx_rx_ant_inv == true) + vnt_set_antenna_mode(priv, ANT_RXA); + else + vnt_set_antenna_mode(priv, ANT_RXB); + } else { + priv->rx_antenna_sel = 0; + if (priv->tx_rx_ant_inv == true) + vnt_set_antenna_mode(priv, ANT_RXB); + else + vnt_set_antenna_mode(priv, ANT_RXA); + } + break; + + default: + break; + } + + vnt_cmd_complete(priv); +} + +int vnt_schedule_command(struct vnt_private *priv, enum vnt_cmd command) +{ + + if (priv->free_cmd_queue == 0) + return false; + + priv->cmd_queue[priv->cmd_enqueue_idx] = command; + + ADD_ONE_WITH_WRAP_AROUND(priv->cmd_enqueue_idx, CMD_Q_SIZE); + priv->free_cmd_queue--; + + if (priv->cmd_running == false) + vnt_cmd_complete(priv); + + return true; + +} + +void vnt_reset_command_timer(struct vnt_private *priv) +{ + priv->free_cmd_queue = CMD_Q_SIZE; + priv->cmd_dequeue_idx = 0; + priv->cmd_enqueue_idx = 0; + priv->command_state = WLAN_CMD_IDLE; + priv->cmd_running = false; +} diff --git a/kernel/drivers/staging/vt6656/wcmd.h b/kernel/drivers/staging/vt6656/wcmd.h new file mode 100644 index 000000000..2b0ee285e --- /dev/null +++ b/kernel/drivers/staging/vt6656/wcmd.h @@ -0,0 +1,63 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wcmd.h + * + * Purpose: Handles the management command interface functions + * + * Author: Lyndon Chen + * + * Date: May 8, 2002 + * + */ + +#ifndef __WCMD_H__ +#define __WCMD_H__ + +#include "device.h" + +/* Command code */ +enum vnt_cmd { + WLAN_CMD_INIT_MAC80211, + WLAN_CMD_SETPOWER, + WLAN_CMD_TBTT_WAKEUP, + WLAN_CMD_BECON_SEND, + WLAN_CMD_CHANGE_ANTENNA +}; + +#define CMD_Q_SIZE 32 + +/* Command state */ +enum vnt_cmd_state { + WLAN_CMD_INIT_MAC80211_START, + WLAN_CMD_SETPOWER_START, + WLAN_CMD_TBTT_WAKEUP_START, + WLAN_CMD_BECON_SEND_START, + WLAN_CMD_CHANGE_ANTENNA_START, + WLAN_CMD_IDLE +}; + +struct vnt_private; + +void vnt_reset_command_timer(struct vnt_private *); + +int vnt_schedule_command(struct vnt_private *, enum vnt_cmd); + +void vnt_run_command(struct work_struct *work); + +#endif /* __WCMD_H__ */ |