blob: 3fc6862541cc39961623e2547ffcfd2a4169a01c [file] [log] [blame]
Forest Bond92b96792009-06-13 07:38:31 -04001/*
2 * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
3 * All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * File: main_usb.c
20 *
21 * Purpose: driver entry for initial, open, close, tx and rx.
22 *
23 * Author: Lyndon Chen
24 *
25 * Date: Dec 8, 2005
26 *
27 * Functions:
28 *
Andres More26e5b652010-04-13 19:43:07 -030029 * vt6656_probe - module initial (insmod) driver entry
Malcolm Priestleyafc7ef62014-07-25 20:51:47 +010030 * vnt_free_tx_bufs - free tx buffer function
Malcolm Priestley500e1fb2014-07-25 20:51:46 +010031 * vnt_init_registers- initial MAC & BBP & RF internal registers.
Forest Bond92b96792009-06-13 07:38:31 -040032 *
33 * Revision History:
34 */
35#undef __NO_VERSION__
36
Krzysztof Adamskie2382232014-12-09 12:01:38 +010037#include <linux/etherdevice.h>
Al Viro7c51d172013-04-06 18:00:07 -040038#include <linux/file.h>
Forest Bond92b96792009-06-13 07:38:31 -040039#include "device.h"
Forest Bond92b96792009-06-13 07:38:31 -040040#include "card.h"
Forest Bond92b96792009-06-13 07:38:31 -040041#include "baseband.h"
Forest Bond92b96792009-06-13 07:38:31 -040042#include "mac.h"
Forest Bond92b96792009-06-13 07:38:31 -040043#include "power.h"
Forest Bond92b96792009-06-13 07:38:31 -040044#include "wcmd.h"
Forest Bond92b96792009-06-13 07:38:31 -040045#include "rxtx.h"
Forest Bond92b96792009-06-13 07:38:31 -040046#include "dpc.h"
Forest Bond92b96792009-06-13 07:38:31 -040047#include "rf.h"
Forest Bond92b96792009-06-13 07:38:31 -040048#include "firmware.h"
Malcolm Priestley62c85262014-05-26 13:59:07 +010049#include "usbpipe.h"
Forest Bond92b96792009-06-13 07:38:31 -040050#include "channel.h"
Forest Bond92b96792009-06-13 07:38:31 -040051#include "int.h"
Forest Bond92b96792009-06-13 07:38:31 -040052
Andres Moreec6e0f62013-01-31 18:23:07 -050053/*
54 * define module options
55 */
Forest Bond92b96792009-06-13 07:38:31 -040056
Andres Moreec6e0f62013-01-31 18:23:07 -050057/* version information */
58#define DRIVER_AUTHOR \
59 "VIA Networking Technologies, Inc., <lyndonchen@vntek.com.tw>"
Forest Bond92b96792009-06-13 07:38:31 -040060MODULE_AUTHOR(DRIVER_AUTHOR);
61MODULE_LICENSE("GPL");
62MODULE_DESCRIPTION(DEVICE_FULL_DRV_NAM);
63
Peter Senna Tschudindbf0a032014-07-15 23:23:24 +020064#define RX_DESC_DEF0 64
Malcolm Priestley2f020eb2014-07-16 22:22:06 +010065static int vnt_rx_buffers = RX_DESC_DEF0;
66module_param_named(rx_buffers, vnt_rx_buffers, int, 0644);
67MODULE_PARM_DESC(rx_buffers, "Number of receive usb rx buffers");
Forest Bond92b96792009-06-13 07:38:31 -040068
Peter Senna Tschudindbf0a032014-07-15 23:23:24 +020069#define TX_DESC_DEF0 64
Malcolm Priestley3220e3a2014-07-16 22:22:07 +010070static int vnt_tx_buffers = TX_DESC_DEF0;
Malcolm Priestley1b6953d2014-07-18 06:36:09 +010071module_param_named(tx_buffers, vnt_tx_buffers, int, 0644);
Malcolm Priestley3220e3a2014-07-16 22:22:07 +010072MODULE_PARM_DESC(tx_buffers, "Number of receive usb tx buffers");
73
Forest Bond92b96792009-06-13 07:38:31 -040074#define RTS_THRESH_DEF 2347
Forest Bond92b96792009-06-13 07:38:31 -040075#define FRAG_THRESH_DEF 2346
Forest Bond92b96792009-06-13 07:38:31 -040076#define SHORT_RETRY_DEF 8
Forest Bond92b96792009-06-13 07:38:31 -040077#define LONG_RETRY_DEF 4
Forest Bond92b96792009-06-13 07:38:31 -040078
Forest Bond92b96792009-06-13 07:38:31 -040079/* BasebandType[] baseband type selected
80 0: indicate 802.11a type
81 1: indicate 802.11b type
82 2: indicate 802.11g type
83*/
Forest Bond92b96792009-06-13 07:38:31 -040084
Marcos Paulo de Souza24b46f92012-07-02 23:59:30 -030085#define BBP_TYPE_DEF 2
Forest Bond92b96792009-06-13 07:38:31 -040086
Andres Moreec6e0f62013-01-31 18:23:07 -050087/*
88 * Static vars definitions
89 */
Forest Bond92b96792009-06-13 07:38:31 -040090
Greg Kroah-Hartman4d088872012-08-17 17:48:33 -070091static struct usb_device_id vt6656_table[] = {
Forest Bond92b96792009-06-13 07:38:31 -040092 {USB_DEVICE(VNT_USB_VENDOR_ID, VNT_USB_PRODUCT_ID)},
93 {}
94};
95
Malcolm Priestley7665cf22014-07-25 20:51:45 +010096static void vnt_set_options(struct vnt_private *priv)
Malcolm Priestley28e067f2014-07-16 22:21:59 +010097{
Malcolm Priestley3220e3a2014-07-16 22:22:07 +010098 /* Set number of TX buffers */
99 if (vnt_tx_buffers < CB_MIN_TX_DESC || vnt_tx_buffers > CB_MAX_TX_DESC)
Malcolm Priestley03b7e352014-07-19 12:30:04 +0100100 priv->num_tx_context = TX_DESC_DEF0;
Malcolm Priestley3220e3a2014-07-16 22:22:07 +0100101 else
Malcolm Priestley03b7e352014-07-19 12:30:04 +0100102 priv->num_tx_context = vnt_tx_buffers;
Malcolm Priestley2f020eb2014-07-16 22:22:06 +0100103
104 /* Set number of RX buffers */
105 if (vnt_rx_buffers < CB_MIN_RX_DESC || vnt_rx_buffers > CB_MAX_RX_DESC)
Malcolm Priestley6da47382014-07-19 12:30:03 +0100106 priv->num_rcb = RX_DESC_DEF0;
Malcolm Priestley2f020eb2014-07-16 22:22:06 +0100107 else
Malcolm Priestley6da47382014-07-19 12:30:03 +0100108 priv->num_rcb = vnt_rx_buffers;
Malcolm Priestley2f020eb2014-07-16 22:22:06 +0100109
Malcolm Priestley388e5cb2014-07-20 15:33:20 +0100110 priv->short_retry_limit = SHORT_RETRY_DEF;
111 priv->long_retry_limit = LONG_RETRY_DEF;
Malcolm Priestleyda3b67b2014-07-16 22:22:00 +0100112 priv->op_mode = NL80211_IFTYPE_UNSPECIFIED;
Malcolm Priestley65df77e2014-07-20 15:33:11 +0100113 priv->bb_type = BBP_TYPE_DEF;
Malcolm Priestleye12471d2014-07-20 15:33:12 +0100114 priv->packet_type = priv->bb_type;
Malcolm Priestleya6177ae2014-07-20 15:33:24 +0100115 priv->auto_fb_ctrl = AUTO_FB_0;
Malcolm Priestley98e93fe2014-07-20 15:33:17 +0100116 priv->preamble_type = 0;
Malcolm Priestley35cc8f92014-07-19 12:30:12 +0100117 priv->exist_sw_net_addr = false;
Forest Bond92b96792009-06-13 07:38:31 -0400118}
119
Andres Moreec6e0f62013-01-31 18:23:07 -0500120/*
121 * initialization of MAC & BBP registers
122 */
Malcolm Priestley500e1fb2014-07-25 20:51:46 +0100123static int vnt_init_registers(struct vnt_private *priv)
Forest Bond92b96792009-06-13 07:38:31 -0400124{
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100125 struct vnt_cmd_card_init *init_cmd = &priv->init_command;
126 struct vnt_rsp_card_init *init_rsp = &priv->init_response;
127 u8 antenna;
Malcolm Priestleydd0a7742012-12-10 21:59:10 +0000128 int ii;
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100129 int status = STATUS_SUCCESS;
130 u8 tmp;
131 u8 calib_tx_iq = 0, calib_tx_dc = 0, calib_rx_iq = 0;
Forest Bond92b96792009-06-13 07:38:31 -0400132
Malcolm Priestley4e62dcc92014-07-16 22:22:02 +0100133 dev_dbg(&priv->usb->dev, "---->INIbInitAdapter. [%d][%d]\n",
Malcolm Priestleye12471d2014-07-20 15:33:12 +0100134 DEVICE_INIT_COLD, priv->packet_type);
Malcolm Priestley302433d2013-11-03 17:40:51 +0000135
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100136 if (!vnt_check_firmware_version(priv)) {
137 if (vnt_download_firmware(priv) == true) {
138 if (vnt_firmware_branch_to_sram(priv) == false) {
Malcolm Priestley4e62dcc92014-07-16 22:22:02 +0100139 dev_dbg(&priv->usb->dev,
Malcolm Priestley14321462014-06-04 18:25:32 +0100140 " vnt_firmware_branch_to_sram fail\n");
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000141 return false;
142 }
143 } else {
Malcolm Priestley4e62dcc92014-07-16 22:22:02 +0100144 dev_dbg(&priv->usb->dev, "FIRMWAREbDownload fail\n");
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000145 return false;
146 }
147 }
Forest Bond92b96792009-06-13 07:38:31 -0400148
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100149 if (!vnt_vt3184_init(priv)) {
Malcolm Priestley4e62dcc92014-07-16 22:22:02 +0100150 dev_dbg(&priv->usb->dev, "vnt_vt3184_init fail\n");
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000151 return false;
152 }
Forest Bond92b96792009-06-13 07:38:31 -0400153
Malcolm Priestley748bf692013-11-03 17:49:32 +0000154 init_cmd->init_class = DEVICE_INIT_COLD;
Malcolm Priestley35cc8f92014-07-19 12:30:12 +0100155 init_cmd->exist_sw_net_addr = priv->exist_sw_net_addr;
Malcolm Priestley3d47a6f2013-11-03 17:43:23 +0000156 for (ii = 0; ii < 6; ii++)
Malcolm Priestleyebf9b312014-07-19 12:30:10 +0100157 init_cmd->sw_net_addr[ii] = priv->current_net_addr[ii];
Malcolm Priestley388e5cb2014-07-20 15:33:20 +0100158 init_cmd->short_retry_limit = priv->short_retry_limit;
159 init_cmd->long_retry_limit = priv->long_retry_limit;
Forest Bond92b96792009-06-13 07:38:31 -0400160
Malcolm Priestley3d47a6f2013-11-03 17:43:23 +0000161 /* issue card_init command to device */
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100162 status = vnt_control_out(priv,
Malcolm Priestley3d47a6f2013-11-03 17:43:23 +0000163 MESSAGE_TYPE_CARDINIT, 0, 0,
Malcolm Priestley748bf692013-11-03 17:49:32 +0000164 sizeof(struct vnt_cmd_card_init), (u8 *)init_cmd);
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100165 if (status != STATUS_SUCCESS) {
Malcolm Priestley4e62dcc92014-07-16 22:22:02 +0100166 dev_dbg(&priv->usb->dev, "Issue Card init fail\n");
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000167 return false;
168 }
Forest Bond92b96792009-06-13 07:38:31 -0400169
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100170 status = vnt_control_in(priv, MESSAGE_TYPE_INIT_RSP, 0, 0,
Malcolm Priestley748bf692013-11-03 17:49:32 +0000171 sizeof(struct vnt_rsp_card_init), (u8 *)init_rsp);
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100172 if (status != STATUS_SUCCESS) {
Malcolm Priestley4e62dcc92014-07-16 22:22:02 +0100173 dev_dbg(&priv->usb->dev,
Malcolm Priestley302433d2013-11-03 17:40:51 +0000174 "Cardinit request in status fail!\n");
Malcolm Priestley302433d2013-11-03 17:40:51 +0000175 return false;
176 }
Forest Bond92b96792009-06-13 07:38:31 -0400177
Andres Moreec6e0f62013-01-31 18:23:07 -0500178 /* local ID for AES functions */
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100179 status = vnt_control_in(priv, MESSAGE_TYPE_READ,
Malcolm Priestley302433d2013-11-03 17:40:51 +0000180 MAC_REG_LOCALID, MESSAGE_REQUEST_MACREG, 1,
Malcolm Priestleyf1945a12014-07-19 12:30:06 +0100181 &priv->local_id);
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100182 if (status != STATUS_SUCCESS)
Malcolm Priestley302433d2013-11-03 17:40:51 +0000183 return false;
Forest Bond92b96792009-06-13 07:38:31 -0400184
Andres Moreec6e0f62013-01-31 18:23:07 -0500185 /* do MACbSoftwareReset in MACvInitialize */
186
Malcolm Priestley3c8a5b22014-07-20 15:33:14 +0100187 priv->top_ofdm_basic_rate = RATE_24M;
Malcolm Priestleyd80bf432014-07-20 15:33:15 +0100188 priv->top_cck_basic_rate = RATE_1M;
Malcolm Priestley24868902014-05-17 09:50:31 +0100189
Andres Moreec6e0f62013-01-31 18:23:07 -0500190 /* target to IF pin while programming to RF chip */
Malcolm Priestley5a974912014-07-20 15:33:18 +0100191 priv->power = 0xFF;
Forest Bond92b96792009-06-13 07:38:31 -0400192
Malcolm Priestley5a974912014-07-20 15:33:18 +0100193 priv->cck_pwr = priv->eeprom[EEP_OFS_PWR_CCK];
194 priv->ofdm_pwr_g = priv->eeprom[EEP_OFS_PWR_OFDMG];
Andres Moreec6e0f62013-01-31 18:23:07 -0500195 /* load power table */
196 for (ii = 0; ii < 14; ii++) {
Malcolm Priestley5a974912014-07-20 15:33:18 +0100197 priv->cck_pwr_tbl[ii] =
Malcolm Priestleybbb11262014-07-20 15:33:16 +0100198 priv->eeprom[ii + EEP_OFS_CCK_PWR_TBL];
Malcolm Priestley5a974912014-07-20 15:33:18 +0100199 if (priv->cck_pwr_tbl[ii] == 0)
200 priv->cck_pwr_tbl[ii] = priv->cck_pwr;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000201
Malcolm Priestley5a974912014-07-20 15:33:18 +0100202 priv->ofdm_pwr_tbl[ii] =
Malcolm Priestleybbb11262014-07-20 15:33:16 +0100203 priv->eeprom[ii + EEP_OFS_OFDM_PWR_TBL];
Malcolm Priestley5a974912014-07-20 15:33:18 +0100204 if (priv->ofdm_pwr_tbl[ii] == 0)
205 priv->ofdm_pwr_tbl[ii] = priv->ofdm_pwr_g;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000206 }
Forest Bond92b96792009-06-13 07:38:31 -0400207
Andres Moreec6e0f62013-01-31 18:23:07 -0500208 /*
209 * original zonetype is USA, but custom zonetype is Europe,
210 * then need to recover 12, 13, 14 channels with 11 channel
211 */
Malcolm Priestley9ef21842014-06-25 21:19:38 +0100212 for (ii = 11; ii < 14; ii++) {
Malcolm Priestley5a974912014-07-20 15:33:18 +0100213 priv->cck_pwr_tbl[ii] = priv->cck_pwr_tbl[10];
214 priv->ofdm_pwr_tbl[ii] = priv->ofdm_pwr_tbl[10];
Malcolm Priestley302433d2013-11-03 17:40:51 +0000215 }
Forest Bond92b96792009-06-13 07:38:31 -0400216
Malcolm Priestley5a974912014-07-20 15:33:18 +0100217 priv->ofdm_pwr_a = 0x34; /* same as RFbMA2829SelectChannel */
Andres Moreec6e0f62013-01-31 18:23:07 -0500218
Malcolm Priestley302433d2013-11-03 17:40:51 +0000219 /* load OFDM A power table */
220 for (ii = 0; ii < CB_MAX_CHANNEL_5G; ii++) {
Malcolm Priestley5a974912014-07-20 15:33:18 +0100221 priv->ofdm_a_pwr_tbl[ii] =
Malcolm Priestleybbb11262014-07-20 15:33:16 +0100222 priv->eeprom[ii + EEP_OFS_OFDMA_PWR_TBL];
Forest Bond92b96792009-06-13 07:38:31 -0400223
Malcolm Priestley5a974912014-07-20 15:33:18 +0100224 if (priv->ofdm_a_pwr_tbl[ii] == 0)
225 priv->ofdm_a_pwr_tbl[ii] = priv->ofdm_pwr_a;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000226 }
Forest Bond92b96792009-06-13 07:38:31 -0400227
Malcolm Priestleybbb11262014-07-20 15:33:16 +0100228 antenna = priv->eeprom[EEP_OFS_ANTENNA];
Malcolm Priestley302433d2013-11-03 17:40:51 +0000229
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100230 if (antenna & EEP_ANTINV)
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100231 priv->tx_rx_ant_inv = true;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000232 else
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100233 priv->tx_rx_ant_inv = false;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000234
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100235 antenna &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);
Forest Bond92b96792009-06-13 07:38:31 -0400236
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100237 if (antenna == 0) /* if not set default is both */
238 antenna = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);
Forest Bond92b96792009-06-13 07:38:31 -0400239
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100240 if (antenna == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) {
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100241 priv->tx_antenna_mode = ANT_B;
242 priv->rx_antenna_sel = 1;
Forest Bond92b96792009-06-13 07:38:31 -0400243
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100244 if (priv->tx_rx_ant_inv == true)
245 priv->rx_antenna_mode = ANT_A;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000246 else
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100247 priv->rx_antenna_mode = ANT_B;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000248 } else {
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100249 priv->rx_antenna_sel = 0;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000250
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100251 if (antenna & EEP_ANTENNA_AUX) {
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100252 priv->tx_antenna_mode = ANT_A;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000253
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100254 if (priv->tx_rx_ant_inv == true)
255 priv->rx_antenna_mode = ANT_B;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000256 else
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100257 priv->rx_antenna_mode = ANT_A;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000258 } else {
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100259 priv->tx_antenna_mode = ANT_B;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000260
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100261 if (priv->tx_rx_ant_inv == true)
262 priv->rx_antenna_mode = ANT_A;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000263 else
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100264 priv->rx_antenna_mode = ANT_B;
Malcolm Priestley302433d2013-11-03 17:40:51 +0000265 }
266 }
267
Malcolm Priestleyed0db512014-07-14 19:43:06 +0100268 /* Set initial antenna mode */
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100269 vnt_set_antenna_mode(priv, priv->rx_antenna_mode);
Malcolm Priestleyed0db512014-07-14 19:43:06 +0100270
Andres Moreec6e0f62013-01-31 18:23:07 -0500271 /* get Auto Fall Back type */
Malcolm Priestleya6177ae2014-07-20 15:33:24 +0100272 priv->auto_fb_ctrl = AUTO_FB_0;
Forest Bond92b96792009-06-13 07:38:31 -0400273
Andres Moreec6e0f62013-01-31 18:23:07 -0500274 /* default Auto Mode */
Malcolm Priestley65df77e2014-07-20 15:33:11 +0100275 priv->bb_type = BB_TYPE_11G;
Forest Bond92b96792009-06-13 07:38:31 -0400276
Andres Moreec6e0f62013-01-31 18:23:07 -0500277 /* get RFType */
Malcolm Priestley6242eca2014-07-19 12:30:07 +0100278 priv->rf_type = init_rsp->rf_type;
Forest Bond92b96792009-06-13 07:38:31 -0400279
Andres Moreec6e0f62013-01-31 18:23:07 -0500280 /* load vt3266 calibration parameters in EEPROM */
Malcolm Priestley6242eca2014-07-19 12:30:07 +0100281 if (priv->rf_type == RF_VT3226D0) {
Malcolm Priestleybbb11262014-07-20 15:33:16 +0100282 if ((priv->eeprom[EEP_OFS_MAJOR_VER] == 0x1) &&
283 (priv->eeprom[EEP_OFS_MINOR_VER] >= 0x4)) {
Malcolm Priestley302433d2013-11-03 17:40:51 +0000284
Malcolm Priestleybbb11262014-07-20 15:33:16 +0100285 calib_tx_iq = priv->eeprom[EEP_OFS_CALIB_TX_IQ];
286 calib_tx_dc = priv->eeprom[EEP_OFS_CALIB_TX_DC];
287 calib_rx_iq = priv->eeprom[EEP_OFS_CALIB_RX_IQ];
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100288 if (calib_tx_iq || calib_tx_dc || calib_rx_iq) {
Peter Senna Tschudin33e9ab32014-07-15 22:46:48 +0200289 /* CR255, enable TX/RX IQ and
290 DC compensation mode */
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100291 vnt_control_out_u8(priv,
Peter Senna Tschudin33e9ab32014-07-15 22:46:48 +0200292 MESSAGE_REQUEST_BBREG,
293 0xff,
294 0x03);
295 /* CR251, TX I/Q Imbalance Calibration */
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100296 vnt_control_out_u8(priv,
Peter Senna Tschudin33e9ab32014-07-15 22:46:48 +0200297 MESSAGE_REQUEST_BBREG,
298 0xfb,
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100299 calib_tx_iq);
Peter Senna Tschudin33e9ab32014-07-15 22:46:48 +0200300 /* CR252, TX DC-Offset Calibration */
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100301 vnt_control_out_u8(priv,
Peter Senna Tschudin33e9ab32014-07-15 22:46:48 +0200302 MESSAGE_REQUEST_BBREG,
303 0xfC,
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100304 calib_tx_dc);
Peter Senna Tschudin33e9ab32014-07-15 22:46:48 +0200305 /* CR253, RX I/Q Imbalance Calibration */
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100306 vnt_control_out_u8(priv,
Peter Senna Tschudin33e9ab32014-07-15 22:46:48 +0200307 MESSAGE_REQUEST_BBREG,
308 0xfd,
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100309 calib_rx_iq);
Malcolm Priestley302433d2013-11-03 17:40:51 +0000310 } else {
Peter Senna Tschudin33e9ab32014-07-15 22:46:48 +0200311 /* CR255, turn off
312 BB Calibration compensation */
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100313 vnt_control_out_u8(priv,
Peter Senna Tschudin33e9ab32014-07-15 22:46:48 +0200314 MESSAGE_REQUEST_BBREG,
315 0xff,
316 0x0);
Malcolm Priestley302433d2013-11-03 17:40:51 +0000317 }
318 }
319 }
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000320
Andres Moreec6e0f62013-01-31 18:23:07 -0500321 /* get permanent network address */
Malcolm Priestley41e83212014-07-19 12:30:11 +0100322 memcpy(priv->permanent_net_addr, init_rsp->net_addr, 6);
Krzysztof Adamskie2382232014-12-09 12:01:38 +0100323 ether_addr_copy(priv->current_net_addr, priv->permanent_net_addr);
Forest Bond92b96792009-06-13 07:38:31 -0400324
Andres Moreec6e0f62013-01-31 18:23:07 -0500325 /* if exist SW network address, use it */
Malcolm Priestley4e62dcc92014-07-16 22:22:02 +0100326 dev_dbg(&priv->usb->dev, "Network address = %pM\n",
Malcolm Priestleyebf9b312014-07-19 12:30:10 +0100327 priv->current_net_addr);
Forest Bond92b96792009-06-13 07:38:31 -0400328
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000329 /*
330 * set BB and packet type at the same time
331 * set Short Slot Time, xIFS, and RSPINF
332 */
Malcolm Priestley65df77e2014-07-20 15:33:11 +0100333 if (priv->bb_type == BB_TYPE_11A)
Malcolm Priestleya641c9e2014-07-20 15:33:21 +0100334 priv->short_slot_time = true;
Malcolm Priestleyd35d5fb2014-06-28 23:55:44 +0100335 else
Malcolm Priestleya641c9e2014-07-20 15:33:21 +0100336 priv->short_slot_time = false;
Forest Bond92b96792009-06-13 07:38:31 -0400337
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100338 vnt_set_short_slot_time(priv);
Forest Bond92b96792009-06-13 07:38:31 -0400339
Malcolm Priestleybbb11262014-07-20 15:33:16 +0100340 priv->radio_ctl = priv->eeprom[EEP_OFS_RADIOCTL];
Forest Bond92b96792009-06-13 07:38:31 -0400341
Malcolm Priestley2044dbd2014-07-19 12:30:16 +0100342 if ((priv->radio_ctl & EEP_RADIOCTL_ENABLE) != 0) {
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100343 status = vnt_control_in(priv, MESSAGE_TYPE_READ,
344 MAC_REG_GPIOCTL1, MESSAGE_REQUEST_MACREG, 1, &tmp);
Forest Bond92b96792009-06-13 07:38:31 -0400345
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100346 if (status != STATUS_SUCCESS)
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000347 return false;
Forest Bond92b96792009-06-13 07:38:31 -0400348
Malcolm Priestleyd7f2d8f2014-07-18 23:00:54 +0100349 if ((tmp & GPIO3_DATA) == 0)
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100350 vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1,
Malcolm Priestley36957532014-05-31 11:50:42 +0100351 GPIO3_INTMD);
Malcolm Priestleyd7f2d8f2014-07-18 23:00:54 +0100352 else
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100353 vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1,
Malcolm Priestleya9bed1d2014-05-31 11:50:41 +0100354 GPIO3_INTMD);
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000355 }
356
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100357 vnt_mac_set_led(priv, LEDSTS_TMLEN, 0x38);
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000358
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100359 vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW);
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000360
Malcolm Priestley3ce54932014-07-16 22:22:01 +0100361 vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL0, 0x01);
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000362
Malcolm Priestleyd7f2d8f2014-07-18 23:00:54 +0100363 vnt_radio_power_on(priv);
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000364
Malcolm Priestley4e62dcc92014-07-16 22:22:02 +0100365 dev_dbg(&priv->usb->dev, "<----INIbInitAdapter Exit\n");
Malcolm Priestleycbc06fb2013-11-03 17:52:15 +0000366
367 return true;
Forest Bond92b96792009-06-13 07:38:31 -0400368}
369
Malcolm Priestleyafc7ef62014-07-25 20:51:47 +0100370static void vnt_free_tx_bufs(struct vnt_private *priv)
Andres More8611a292010-05-01 14:25:00 -0300371{
Malcolm Priestleyf2625c22014-02-28 23:58:36 +0000372 struct vnt_usb_send_context *tx_context;
373 int ii;
Forest Bond92b96792009-06-13 07:38:31 -0400374
Malcolm Priestley03b7e352014-07-19 12:30:04 +0100375 for (ii = 0; ii < priv->num_tx_context; ii++) {
Malcolm Priestleyf7e4a8f2014-07-18 06:36:16 +0100376 tx_context = priv->tx_context[ii];
Malcolm Priestleyf2625c22014-02-28 23:58:36 +0000377 /* deallocate URBs */
Malcolm Priestley30a05b32014-05-15 22:49:11 +0100378 if (tx_context->urb) {
379 usb_kill_urb(tx_context->urb);
380 usb_free_urb(tx_context->urb);
Malcolm Priestleyf2625c22014-02-28 23:58:36 +0000381 }
Forest Bond92b96792009-06-13 07:38:31 -0400382
Malcolm Priestleyf2625c22014-02-28 23:58:36 +0000383 kfree(tx_context);
384 }
Forest Bond92b96792009-06-13 07:38:31 -0400385}
386
Malcolm Priestley0dd6e682014-07-25 20:51:48 +0100387static void vnt_free_rx_bufs(struct vnt_private *priv)
Andres More8611a292010-05-01 14:25:00 -0300388{
Malcolm Priestleyafc5eeb2014-02-28 23:58:35 +0000389 struct vnt_rcb *rcb;
Malcolm Priestley115cac22013-08-28 21:12:35 +0100390 int ii;
Forest Bond92b96792009-06-13 07:38:31 -0400391
Malcolm Priestley6da47382014-07-19 12:30:03 +0100392 for (ii = 0; ii < priv->num_rcb; ii++) {
Malcolm Priestley85770112014-07-18 06:36:15 +0100393 rcb = priv->rcb[ii];
Malcolm Priestley8cffb3c2014-06-28 23:55:42 +0100394 if (!rcb)
395 continue;
Forest Bond92b96792009-06-13 07:38:31 -0400396
Malcolm Priestleyafc5eeb2014-02-28 23:58:35 +0000397 /* deallocate URBs */
Malcolm Priestley325de982014-07-18 06:36:11 +0100398 if (rcb->urb) {
399 usb_kill_urb(rcb->urb);
400 usb_free_urb(rcb->urb);
Malcolm Priestleyafc5eeb2014-02-28 23:58:35 +0000401 }
Forest Bond92b96792009-06-13 07:38:31 -0400402
Malcolm Priestleyafc5eeb2014-02-28 23:58:35 +0000403 /* deallocate skb */
404 if (rcb->skb)
405 dev_kfree_skb(rcb->skb);
Malcolm Priestleyafc5eeb2014-02-28 23:58:35 +0000406
Malcolm Priestley8cffb3c2014-06-28 23:55:42 +0100407 kfree(rcb);
408 }
Forest Bond92b96792009-06-13 07:38:31 -0400409}
410
Malcolm Priestley76d382f2014-07-18 06:36:08 +0100411static void usb_device_reset(struct vnt_private *priv)
Forest Bond92b96792009-06-13 07:38:31 -0400412{
Peter Senna Tschudin42b138d2014-07-15 23:23:26 +0200413 int status;
414
Malcolm Priestley76d382f2014-07-18 06:36:08 +0100415 status = usb_reset_device(priv->usb);
Forest Bond92b96792009-06-13 07:38:31 -0400416 if (status)
Malcolm Priestley76d382f2014-07-18 06:36:08 +0100417 dev_warn(&priv->usb->dev,
Peter Senna Tschudind9cf2f92014-07-16 18:08:02 +0200418 "usb_device_reset fail status=%d\n", status);
Forest Bond92b96792009-06-13 07:38:31 -0400419}
Forest Bond92b96792009-06-13 07:38:31 -0400420
Malcolm Priestley1c2fd562014-07-25 20:51:49 +0100421static void vnt_free_int_bufs(struct vnt_private *priv)
Andres More8611a292010-05-01 14:25:00 -0300422{
Malcolm Priestley1506bf32014-02-28 23:58:37 +0000423 kfree(priv->int_buf.data_buf);
Forest Bond92b96792009-06-13 07:38:31 -0400424}
425
Malcolm Priestleyef484422014-07-25 20:51:50 +0100426static bool vnt_alloc_bufs(struct vnt_private *priv)
Malcolm Priestleydd0a7742012-12-10 21:59:10 +0000427{
Malcolm Priestley35491de2014-02-28 23:58:34 +0000428 struct vnt_usb_send_context *tx_context;
429 struct vnt_rcb *rcb;
Malcolm Priestley115cac22013-08-28 21:12:35 +0100430 int ii;
Forest Bond92b96792009-06-13 07:38:31 -0400431
Malcolm Priestley03b7e352014-07-19 12:30:04 +0100432 for (ii = 0; ii < priv->num_tx_context; ii++) {
Malcolm Priestley35491de2014-02-28 23:58:34 +0000433 tx_context = kmalloc(sizeof(struct vnt_usb_send_context),
Malcolm Priestley115cac22013-08-28 21:12:35 +0100434 GFP_KERNEL);
Melike Yurtoglu2ff61792014-10-05 01:05:57 +0300435 if (tx_context == NULL)
Malcolm Priestley35491de2014-02-28 23:58:34 +0000436 goto free_tx;
Forest Bond92b96792009-06-13 07:38:31 -0400437
Malcolm Priestleyf7e4a8f2014-07-18 06:36:16 +0100438 priv->tx_context[ii] = tx_context;
Malcolm Priestley30a05b32014-05-15 22:49:11 +0100439 tx_context->priv = priv;
Malcolm Priestley71d764a2014-07-05 19:24:27 +0100440 tx_context->pkt_no = ii;
Malcolm Priestley115cac22013-08-28 21:12:35 +0100441
Malcolm Priestley35491de2014-02-28 23:58:34 +0000442 /* allocate URBs */
Malcolm Priestley30a05b32014-05-15 22:49:11 +0100443 tx_context->urb = usb_alloc_urb(0, GFP_ATOMIC);
444 if (!tx_context->urb) {
Malcolm Priestleyb4ae1352014-07-16 22:22:03 +0100445 dev_err(&priv->usb->dev, "alloc tx urb failed\n");
Malcolm Priestley35491de2014-02-28 23:58:34 +0000446 goto free_tx;
447 }
Forest Bond92b96792009-06-13 07:38:31 -0400448
Malcolm Priestley30a05b32014-05-15 22:49:11 +0100449 tx_context->in_use = false;
Forest Bond92b96792009-06-13 07:38:31 -0400450 }
451
Malcolm Priestley6da47382014-07-19 12:30:03 +0100452 for (ii = 0; ii < priv->num_rcb; ii++) {
Malcolm Priestley85770112014-07-18 06:36:15 +0100453 priv->rcb[ii] = kzalloc(sizeof(struct vnt_rcb), GFP_KERNEL);
454 if (!priv->rcb[ii]) {
Malcolm Priestley8cffb3c2014-06-28 23:55:42 +0100455 dev_err(&priv->usb->dev,
456 "failed to allocate rcb no %d\n", ii);
457 goto free_rx_tx;
458 }
459
Malcolm Priestley85770112014-07-18 06:36:15 +0100460 rcb = priv->rcb[ii];
Malcolm Priestley8cffb3c2014-06-28 23:55:42 +0100461
Malcolm Priestley325de982014-07-18 06:36:11 +0100462 rcb->priv = priv;
Malcolm Priestley35491de2014-02-28 23:58:34 +0000463
464 /* allocate URBs */
Malcolm Priestley325de982014-07-18 06:36:11 +0100465 rcb->urb = usb_alloc_urb(0, GFP_ATOMIC);
466 if (rcb->urb == NULL) {
Malcolm Priestleyb4ae1352014-07-16 22:22:03 +0100467 dev_err(&priv->usb->dev, "Failed to alloc rx urb\n");
Malcolm Priestley35491de2014-02-28 23:58:34 +0000468 goto free_rx_tx;
469 }
470
Malcolm Priestley63b99072014-06-25 21:14:22 +0100471 rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
Melike Yurtoglu2ff61792014-10-05 01:05:57 +0300472 if (rcb->skb == NULL)
Malcolm Priestley35491de2014-02-28 23:58:34 +0000473 goto free_rx_tx;
Malcolm Priestley35491de2014-02-28 23:58:34 +0000474
Malcolm Priestley325de982014-07-18 06:36:11 +0100475 rcb->in_use = false;
Malcolm Priestley35491de2014-02-28 23:58:34 +0000476
Malcolm Priestley8cffb3c2014-06-28 23:55:42 +0100477 /* submit rx urb */
Malcolm Priestley2dc37af2014-07-15 19:54:41 +0100478 if (vnt_submit_rx_urb(priv, rcb))
Malcolm Priestley8cffb3c2014-06-28 23:55:42 +0100479 goto free_rx_tx;
Malcolm Priestley35491de2014-02-28 23:58:34 +0000480 }
481
Malcolm Priestley3d582482014-07-18 06:36:14 +0100482 priv->interrupt_urb = usb_alloc_urb(0, GFP_ATOMIC);
483 if (priv->interrupt_urb == NULL) {
Malcolm Priestleyb4ae1352014-07-16 22:22:03 +0100484 dev_err(&priv->usb->dev, "Failed to alloc int urb\n");
Malcolm Priestley35491de2014-02-28 23:58:34 +0000485 goto free_rx_tx;
486 }
487
488 priv->int_buf.data_buf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL);
489 if (priv->int_buf.data_buf == NULL) {
Malcolm Priestley3d582482014-07-18 06:36:14 +0100490 usb_free_urb(priv->interrupt_urb);
Malcolm Priestley35491de2014-02-28 23:58:34 +0000491 goto free_rx_tx;
492 }
493
494 return true;
Forest Bond92b96792009-06-13 07:38:31 -0400495
496free_rx_tx:
Malcolm Priestley0dd6e682014-07-25 20:51:48 +0100497 vnt_free_rx_bufs(priv);
Forest Bond92b96792009-06-13 07:38:31 -0400498
499free_tx:
Malcolm Priestleyafc7ef62014-07-25 20:51:47 +0100500 vnt_free_tx_bufs(priv);
Forest Bond92b96792009-06-13 07:38:31 -0400501
Andres Moree269fc22013-02-12 20:36:29 -0500502 return false;
Forest Bond92b96792009-06-13 07:38:31 -0400503}
504
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100505static void vnt_tx_80211(struct ieee80211_hw *hw,
506 struct ieee80211_tx_control *control, struct sk_buff *skb)
507{
508 struct vnt_private *priv = hw->priv;
509
510 ieee80211_stop_queues(hw);
511
512 if (vnt_tx_packet(priv, skb)) {
513 ieee80211_free_txskb(hw, skb);
514
515 ieee80211_wake_queues(hw);
516 }
517}
518
519static int vnt_start(struct ieee80211_hw *hw)
520{
521 struct vnt_private *priv = hw->priv;
522
523 priv->rx_buf_sz = MAX_TOTAL_SIZE_WITH_ALL_HEADERS;
524
Abdul Hussain5699c0f2015-06-16 05:43:16 +0000525 if (!vnt_alloc_bufs(priv)) {
Malcolm Priestleyef484422014-07-25 20:51:50 +0100526 dev_dbg(&priv->usb->dev, "vnt_alloc_bufs fail...\n");
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100527 return -ENOMEM;
528 }
529
Malcolm Priestley2ab3d462014-07-24 21:13:18 +0100530 clear_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100531
Malcolm Priestley500e1fb2014-07-25 20:51:46 +0100532 if (vnt_init_registers(priv) == false) {
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100533 dev_dbg(&priv->usb->dev, " init register fail\n");
534 goto free_all;
535 }
536
537 priv->int_interval = 1; /* bInterval is set to 1 */
538
Malcolm Priestley62001932014-07-15 19:54:35 +0100539 vnt_int_start_interrupt(priv);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100540
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100541 ieee80211_wake_queues(hw);
542
543 return 0;
544
545free_all:
Malcolm Priestley0dd6e682014-07-25 20:51:48 +0100546 vnt_free_rx_bufs(priv);
Malcolm Priestleyafc7ef62014-07-25 20:51:47 +0100547 vnt_free_tx_bufs(priv);
Malcolm Priestley1c2fd562014-07-25 20:51:49 +0100548 vnt_free_int_bufs(priv);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100549
Malcolm Priestley3d582482014-07-18 06:36:14 +0100550 usb_kill_urb(priv->interrupt_urb);
551 usb_free_urb(priv->interrupt_urb);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100552
553 return -ENOMEM;
554}
555
556static void vnt_stop(struct ieee80211_hw *hw)
557{
558 struct vnt_private *priv = hw->priv;
559 int i;
560
561 if (!priv)
562 return;
563
564 for (i = 0; i < MAX_KEY_TABLE; i++)
565 vnt_mac_disable_keyentry(priv, i);
566
567 /* clear all keys */
568 priv->key_entry_inuse = 0;
569
Malcolm Priestleycbcc9a32014-07-24 21:13:20 +0100570 if (!test_bit(DEVICE_FLAGS_UNPLUG, &priv->flags))
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100571 vnt_mac_shutdown(priv);
572
573 ieee80211_stop_queues(hw);
574
Malcolm Priestley4c3b0d42014-07-24 21:13:17 +0100575 set_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100576
577 cancel_delayed_work_sync(&priv->run_command_work);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100578
Malcolm Priestley33a60b82014-07-13 10:42:45 +0100579 priv->cmd_running = false;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100580
Malcolm Priestleyafc7ef62014-07-25 20:51:47 +0100581 vnt_free_tx_bufs(priv);
Malcolm Priestley0dd6e682014-07-25 20:51:48 +0100582 vnt_free_rx_bufs(priv);
Malcolm Priestley1c2fd562014-07-25 20:51:49 +0100583 vnt_free_int_bufs(priv);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100584
Malcolm Priestley3d582482014-07-18 06:36:14 +0100585 usb_kill_urb(priv->interrupt_urb);
586 usb_free_urb(priv->interrupt_urb);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100587}
588
589static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
590{
591 struct vnt_private *priv = hw->priv;
592
593 priv->vif = vif;
594
595 switch (vif->type) {
596 case NL80211_IFTYPE_STATION:
597 break;
598 case NL80211_IFTYPE_ADHOC:
599 vnt_mac_reg_bits_off(priv, MAC_REG_RCR, RCR_UNICAST);
600
601 vnt_mac_reg_bits_on(priv, MAC_REG_HOSTCR, HOSTCR_ADHOC);
602
603 break;
604 case NL80211_IFTYPE_AP:
605 vnt_mac_reg_bits_off(priv, MAC_REG_RCR, RCR_UNICAST);
606
607 vnt_mac_reg_bits_on(priv, MAC_REG_HOSTCR, HOSTCR_AP);
608
609 break;
610 default:
611 return -EOPNOTSUPP;
612 }
613
614 priv->op_mode = vif->type;
615
Malcolm Priestley1ecd0832014-06-28 23:55:46 +0100616 vnt_set_bss_mode(priv);
617
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100618 /* LED blink on TX */
619 vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_INTER);
620
621 return 0;
622}
623
624static void vnt_remove_interface(struct ieee80211_hw *hw,
625 struct ieee80211_vif *vif)
626{
627 struct vnt_private *priv = hw->priv;
628
629 switch (vif->type) {
630 case NL80211_IFTYPE_STATION:
631 break;
632 case NL80211_IFTYPE_ADHOC:
633 vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX);
634 vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
635 vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_ADHOC);
636 break;
637 case NL80211_IFTYPE_AP:
638 vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX);
639 vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
640 vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_AP);
641 break;
642 default:
643 break;
644 }
645
646 vnt_radio_power_off(priv);
647
648 priv->op_mode = NL80211_IFTYPE_UNSPECIFIED;
649
650 /* LED slow blink */
651 vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100652}
653
654static int vnt_config(struct ieee80211_hw *hw, u32 changed)
655{
656 struct vnt_private *priv = hw->priv;
657 struct ieee80211_conf *conf = &hw->conf;
658 u8 bb_type;
659
660 if (changed & IEEE80211_CONF_CHANGE_PS) {
661 if (conf->flags & IEEE80211_CONF_PS)
662 vnt_enable_power_saving(priv, conf->listen_interval);
663 else
664 vnt_disable_power_saving(priv);
665 }
666
667 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
668 (conf->flags & IEEE80211_CONF_OFFCHANNEL)) {
669 vnt_set_channel(priv, conf->chandef.chan->hw_value);
670
671 if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ)
672 bb_type = BB_TYPE_11A;
673 else
674 bb_type = BB_TYPE_11G;
675
Malcolm Priestley65df77e2014-07-20 15:33:11 +0100676 if (priv->bb_type != bb_type) {
677 priv->bb_type = bb_type;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100678
679 vnt_set_bss_mode(priv);
680 }
681 }
682
683 if (changed & IEEE80211_CONF_CHANGE_POWER) {
Malcolm Priestley65df77e2014-07-20 15:33:11 +0100684 if (priv->bb_type == BB_TYPE_11B)
Malcolm Priestley8b84c1d2014-07-20 15:33:19 +0100685 priv->current_rate = RATE_1M;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100686 else
Malcolm Priestley8b84c1d2014-07-20 15:33:19 +0100687 priv->current_rate = RATE_54M;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100688
Malcolm Priestley8b84c1d2014-07-20 15:33:19 +0100689 vnt_rf_setpower(priv, priv->current_rate,
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100690 conf->chandef.chan->hw_value);
691 }
692
693 return 0;
694}
695
696static void vnt_bss_info_changed(struct ieee80211_hw *hw,
697 struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf,
698 u32 changed)
699{
700 struct vnt_private *priv = hw->priv;
Peter Senna Tschudin14c5e412014-07-15 23:23:27 +0200701
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100702 priv->current_aid = conf->aid;
703
Malcolm Priestleyd3095092015-07-09 17:03:57 +0100704 if (changed & BSS_CHANGED_BSSID && conf->bssid)
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100705 vnt_mac_set_bssid_addr(priv, (u8 *)conf->bssid);
706
707
708 if (changed & BSS_CHANGED_BASIC_RATES) {
Malcolm Priestley93a73552014-07-20 15:33:13 +0100709 priv->basic_rates = conf->basic_rates;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100710
711 vnt_update_top_rates(priv);
712
713 dev_dbg(&priv->usb->dev, "basic rates %x\n", conf->basic_rates);
714 }
715
716 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
717 if (conf->use_short_preamble) {
718 vnt_mac_enable_barker_preamble_mode(priv);
Malcolm Priestley98e93fe2014-07-20 15:33:17 +0100719 priv->preamble_type = true;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100720 } else {
721 vnt_mac_disable_barker_preamble_mode(priv);
Malcolm Priestley98e93fe2014-07-20 15:33:17 +0100722 priv->preamble_type = false;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100723 }
724 }
725
726 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
727 if (conf->use_cts_prot)
728 vnt_mac_enable_protect_mode(priv);
729 else
730 vnt_mac_disable_protect_mode(priv);
731 }
732
733 if (changed & BSS_CHANGED_ERP_SLOT) {
734 if (conf->use_short_slot)
Malcolm Priestleya641c9e2014-07-20 15:33:21 +0100735 priv->short_slot_time = true;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100736 else
Malcolm Priestleya641c9e2014-07-20 15:33:21 +0100737 priv->short_slot_time = false;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100738
Malcolm Priestley3c956cc2014-07-16 22:21:54 +0100739 vnt_set_short_slot_time(priv);
Malcolm Priestleyc37cbd32014-07-20 15:33:25 +0100740 vnt_set_vga_gain_offset(priv, priv->bb_vga[0]);
Malcolm Priestley80dcc0a2014-07-16 22:21:58 +0100741 vnt_update_pre_ed_threshold(priv, false);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100742 }
743
744 if (changed & BSS_CHANGED_TXPOWER)
Malcolm Priestley8b84c1d2014-07-20 15:33:19 +0100745 vnt_rf_setpower(priv, priv->current_rate,
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100746 conf->chandef.chan->hw_value);
747
748 if (changed & BSS_CHANGED_BEACON_ENABLED) {
749 dev_dbg(&priv->usb->dev,
750 "Beacon enable %d\n", conf->enable_beacon);
751
752 if (conf->enable_beacon) {
753 vnt_beacon_enable(priv, vif, conf);
754
755 vnt_mac_reg_bits_on(priv, MAC_REG_TCR, TCR_AUTOBCNTX);
756 } else {
757 vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX);
758 }
759 }
Malcolm Priestleyc1515872015-09-27 09:17:40 +0100760
761 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) &&
762 priv->op_mode != NL80211_IFTYPE_AP) {
763 if (conf->assoc && conf->beacon_rate) {
764 vnt_mac_reg_bits_on(priv, MAC_REG_TFTCTL,
765 TFTCTL_TSFCNTREN);
766
767 vnt_adjust_tsf(priv, conf->beacon_rate->hw_value,
768 conf->sync_tsf, priv->current_tsf);
769
770 vnt_mac_set_beacon_interval(priv, conf->beacon_int);
771
772 vnt_reset_next_tbtt(priv, conf->beacon_int);
773 } else {
774 vnt_clear_current_tsf(priv);
775
776 vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL,
777 TFTCTL_TSFCNTREN);
778 }
779 }
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100780}
781
782static u64 vnt_prepare_multicast(struct ieee80211_hw *hw,
783 struct netdev_hw_addr_list *mc_list)
784{
785 struct vnt_private *priv = hw->priv;
786 struct netdev_hw_addr *ha;
787 u64 mc_filter = 0;
788 u32 bit_nr = 0;
789
790 netdev_hw_addr_list_for_each(ha, mc_list) {
791 bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
792
793 mc_filter |= 1ULL << (bit_nr & 0x3f);
794 }
795
796 priv->mc_list_count = mc_list->count;
797
798 return mc_filter;
799}
800
801static void vnt_configure(struct ieee80211_hw *hw,
802 unsigned int changed_flags, unsigned int *total_flags, u64 multicast)
803{
804 struct vnt_private *priv = hw->priv;
805 u8 rx_mode = 0;
806 int rc;
807
Johannes Bergdf140462015-04-22 14:40:58 +0200808 *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100809
810 rc = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_RCR,
811 MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode);
812
813 if (!rc)
814 rx_mode = RCR_MULTICAST | RCR_BROADCAST;
815
816 dev_dbg(&priv->usb->dev, "rx mode in = %x\n", rx_mode);
817
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100818 if (changed_flags & FIF_ALLMULTI) {
819 if (*total_flags & FIF_ALLMULTI) {
820 if (priv->mc_list_count > 2)
821 vnt_mac_set_filter(priv, ~0);
822 else
823 vnt_mac_set_filter(priv, multicast);
824
825 rx_mode |= RCR_MULTICAST | RCR_BROADCAST;
826 } else {
827 rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST);
828 }
829
830 }
831
832 if (changed_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) {
833 if (*total_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC))
834 rx_mode &= ~RCR_BSSID;
835 else
836 rx_mode |= RCR_BSSID;
837 }
838
839 vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, MAC_REG_RCR, rx_mode);
840
841 dev_dbg(&priv->usb->dev, "rx mode out= %x\n", rx_mode);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100842}
843
844static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
845 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
846 struct ieee80211_key_conf *key)
847{
848 struct vnt_private *priv = hw->priv;
849
850 switch (cmd) {
851 case SET_KEY:
852 if (vnt_set_keys(hw, sta, vif, key))
853 return -EOPNOTSUPP;
854 break;
855 case DISABLE_KEY:
856 if (test_bit(key->hw_key_idx, &priv->key_entry_inuse))
857 clear_bit(key->hw_key_idx, &priv->key_entry_inuse);
858 default:
859 break;
860 }
861
862 return 0;
863}
864
Johannes Berga344d672014-06-12 22:24:31 +0200865static void vnt_sw_scan_start(struct ieee80211_hw *hw,
866 struct ieee80211_vif *vif,
867 const u8 *addr)
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100868{
869 struct vnt_private *priv = hw->priv;
870
Malcolm Priestley1ecd0832014-06-28 23:55:46 +0100871 vnt_set_bss_mode(priv);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100872 /* Set max sensitivity*/
Malcolm Priestley80dcc0a2014-07-16 22:21:58 +0100873 vnt_update_pre_ed_threshold(priv, true);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100874}
875
Johannes Berga344d672014-06-12 22:24:31 +0200876static void vnt_sw_scan_complete(struct ieee80211_hw *hw,
877 struct ieee80211_vif *vif)
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100878{
879 struct vnt_private *priv = hw->priv;
880
881 /* Return sensitivity to channel level*/
Malcolm Priestley80dcc0a2014-07-16 22:21:58 +0100882 vnt_update_pre_ed_threshold(priv, false);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100883}
884
Malcolm Priestley17863842014-06-29 20:39:54 +0100885static int vnt_get_stats(struct ieee80211_hw *hw,
886 struct ieee80211_low_level_stats *stats)
887{
888 struct vnt_private *priv = hw->priv;
889
890 memcpy(stats, &priv->low_stats, sizeof(*stats));
891
892 return 0;
893}
894
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100895static u64 vnt_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
896{
897 struct vnt_private *priv = hw->priv;
898
Malcolm Priestley113f0b92014-07-19 12:30:13 +0100899 return priv->current_tsf;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100900}
901
902static void vnt_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
903 u64 tsf)
904{
905 struct vnt_private *priv = hw->priv;
906
907 vnt_update_next_tbtt(priv, tsf, vif->bss_conf.beacon_int);
908}
909
910static void vnt_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
911{
912 struct vnt_private *priv = hw->priv;
913
914 vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
915
916 vnt_clear_current_tsf(priv);
917}
918
919static const struct ieee80211_ops vnt_mac_ops = {
920 .tx = vnt_tx_80211,
921 .start = vnt_start,
922 .stop = vnt_stop,
923 .add_interface = vnt_add_interface,
924 .remove_interface = vnt_remove_interface,
925 .config = vnt_config,
926 .bss_info_changed = vnt_bss_info_changed,
927 .prepare_multicast = vnt_prepare_multicast,
928 .configure_filter = vnt_configure,
929 .set_key = vnt_set_key,
930 .sw_scan_start = vnt_sw_scan_start,
931 .sw_scan_complete = vnt_sw_scan_complete,
Malcolm Priestley17863842014-06-29 20:39:54 +0100932 .get_stats = vnt_get_stats,
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100933 .get_tsf = vnt_get_tsf,
934 .set_tsf = vnt_set_tsf,
935 .reset_tsf = vnt_reset_tsf,
936};
937
938int vnt_init(struct vnt_private *priv)
939{
940
Malcolm Priestley500e1fb2014-07-25 20:51:46 +0100941 if (!(vnt_init_registers(priv)))
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100942 return -EAGAIN;
943
Malcolm Priestley41e83212014-07-19 12:30:11 +0100944 SET_IEEE80211_PERM_ADDR(priv->hw, priv->permanent_net_addr);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100945
Malcolm Priestley110f97e2014-06-25 21:14:26 +0100946 vnt_init_bands(priv);
947
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100948 if (ieee80211_register_hw(priv->hw))
949 return -ENODEV;
950
Malcolm Priestley30816f82014-06-25 21:14:27 +0100951 priv->mac_hw = true;
952
Malcolm Priestleyba911c92014-07-05 19:24:20 +0100953 vnt_radio_power_off(priv);
954
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100955 return 0;
956}
957
958static int
959vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id)
960{
961 struct usb_device *udev;
962 struct vnt_private *priv;
963 struct ieee80211_hw *hw;
964 struct wiphy *wiphy;
965 int rc = 0;
966
967 udev = usb_get_dev(interface_to_usbdev(intf));
968
969 dev_notice(&udev->dev, "%s Ver. %s\n",
970 DEVICE_FULL_DRV_NAM, DEVICE_VERSION);
971 dev_notice(&udev->dev,
972 "Copyright (c) 2004 VIA Networking Technologies, Inc.\n");
973
974 hw = ieee80211_alloc_hw(sizeof(struct vnt_private), &vnt_mac_ops);
975 if (!hw) {
976 dev_err(&udev->dev, "could not register ieee80211_hw\n");
Alexey Khoroshilov20ff1412015-03-14 01:34:41 +0300977 rc = -ENOMEM;
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100978 goto err_nomem;
979 }
980
981 priv = hw->priv;
982 priv->hw = hw;
983 priv->usb = udev;
984
Malcolm Priestley7665cf22014-07-25 20:51:45 +0100985 vnt_set_options(priv);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100986
987 spin_lock_init(&priv->lock);
988 mutex_init(&priv->usb_lock);
989
Malcolm Priestley592365ae4a2014-07-13 10:42:49 +0100990 INIT_DELAYED_WORK(&priv->run_command_work, vnt_run_command);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100991
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +0100992 usb_set_intfdata(intf, priv);
993
994 wiphy = priv->hw->wiphy;
995
996 wiphy->frag_threshold = FRAG_THRESH_DEF;
997 wiphy->rts_threshold = RTS_THRESH_DEF;
998 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
999 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
1000
Johannes Berg30686bf2015-06-02 21:39:54 +02001001 ieee80211_hw_set(priv->hw, TIMING_BEACON_ONLY);
1002 ieee80211_hw_set(priv->hw, SIGNAL_DBM);
1003 ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
1004 ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS);
Malcolm Priestley49a315b2015-09-27 09:17:42 +01001005 ieee80211_hw_set(priv->hw, SUPPORTS_PS);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +01001006
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +01001007 priv->hw->max_signal = 100;
1008
1009 SET_IEEE80211_DEV(priv->hw, &intf->dev);
1010
1011 usb_device_reset(priv);
1012
Malcolm Priestley2ab3d462014-07-24 21:13:18 +01001013 clear_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags);
Malcolm Priestley68cc1612014-07-13 10:42:51 +01001014 vnt_reset_command_timer(priv);
Malcolm Priestley30816f82014-06-25 21:14:27 +01001015
Malcolm Priestley57981a62014-07-13 10:42:50 +01001016 vnt_schedule_command(priv, WLAN_CMD_INIT_MAC80211);
Malcolm Priestley30816f82014-06-25 21:14:27 +01001017
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +01001018 return 0;
1019
1020err_nomem:
1021 usb_put_dev(udev);
1022
1023 return rc;
1024}
1025
Bill Pemberton0d7fe142012-11-19 13:26:58 -05001026static void vt6656_disconnect(struct usb_interface *intf)
Forest Bond92b96792009-06-13 07:38:31 -04001027{
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +01001028 struct vnt_private *priv = usb_get_intfdata(intf);
Forest Bond92b96792009-06-13 07:38:31 -04001029
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +01001030 if (!priv)
Andres More6cda24f2010-06-22 20:43:39 -03001031 return;
Forest Bond92b96792009-06-13 07:38:31 -04001032
Malcolm Priestley30816f82014-06-25 21:14:27 +01001033 if (priv->mac_hw)
1034 ieee80211_unregister_hw(priv->hw);
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +01001035
Forest Bond92b96792009-06-13 07:38:31 -04001036 usb_set_intfdata(intf, NULL);
Andres More6cda24f2010-06-22 20:43:39 -03001037 usb_put_dev(interface_to_usbdev(intf));
Forest Bond92b96792009-06-13 07:38:31 -04001038
Malcolm Priestley4c3b0d42014-07-24 21:13:17 +01001039 set_bit(DEVICE_FLAGS_UNPLUG, &priv->flags);
Forest Bond92b96792009-06-13 07:38:31 -04001040
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +01001041 ieee80211_free_hw(priv->hw);
Forest Bond92b96792009-06-13 07:38:31 -04001042}
1043
Malcolm Priestleydb8f37f2014-06-25 21:14:25 +01001044#ifdef CONFIG_PM
1045
1046static int vt6656_suspend(struct usb_interface *intf, pm_message_t message)
1047{
1048 return 0;
1049}
1050
1051static int vt6656_resume(struct usb_interface *intf)
1052{
1053 return 0;
1054}
1055
1056#endif /* CONFIG_PM */
1057
Andres More26e5b652010-04-13 19:43:07 -03001058MODULE_DEVICE_TABLE(usb, vt6656_table);
Forest Bond92b96792009-06-13 07:38:31 -04001059
Andres More26e5b652010-04-13 19:43:07 -03001060static struct usb_driver vt6656_driver = {
1061 .name = DEVICE_NAME,
1062 .probe = vt6656_probe,
1063 .disconnect = vt6656_disconnect,
1064 .id_table = vt6656_table,
Forest Bond92b96792009-06-13 07:38:31 -04001065#ifdef CONFIG_PM
Andres More26e5b652010-04-13 19:43:07 -03001066 .suspend = vt6656_suspend,
1067 .resume = vt6656_resume,
1068#endif /* CONFIG_PM */
Forest Bond92b96792009-06-13 07:38:31 -04001069};
1070
Greg Kroah-Hartmanbac2c122011-11-18 09:42:11 -08001071module_usb_driver(vt6656_driver);