blob: 0d29624416c335887a08da772f9ce2c8b63c85bd [file] [log] [blame]
Pavel Machek66101de2008-10-01 14:36:56 +02001/*
Pavel Macheka2531292010-07-18 14:27:13 +02002 * Copyright 2008 Pavel Machek <pavel@ucw.cz>
Pavel Machek66101de2008-10-01 14:36:56 +02003 *
4 * Distribute under GPLv2.
Pekka Enberg7c49a0a2009-04-08 11:14:05 +03005 *
6 * The original driver was written by:
7 * Jeff Lee <YY_Lee@issc.com.tw>
8 *
9 * and was adapted to the 2.6 kernel by:
10 * Costantino Leandro (Rxart Desktop) <le_costantino@pixartargentina.com.ar>
Pavel Machek66101de2008-10-01 14:36:56 +020011 */
Pavel Machek66101de2008-10-01 14:36:56 +020012#include <net/mac80211.h>
Pekka Enberg80aba532008-10-30 13:04:29 +020013#include <linux/usb.h>
Paul Gortmaker45296232011-08-30 17:50:46 -040014#include <linux/module.h>
Pekka Enberg80aba532008-10-30 13:04:29 +020015
Pekka Enbergcc180712008-10-30 16:14:35 +020016#include "core.h"
Pekka Enberg912b2092008-10-30 18:12:02 +020017#include "mds_f.h"
Pekka Enberg64328c82009-01-07 17:33:45 +020018#include "mto.h"
Pekka Enbergb5ef0762010-11-01 21:50:06 +020019#include "wbhal.h"
Pekka Enberg72ca8812010-11-01 21:50:05 +020020#include "wb35reg_f.h"
21#include "wb35tx_f.h"
22#include "wb35rx_f.h"
Pavel Machek66101de2008-10-01 14:36:56 +020023
Pekka Enberg7b9a79b2008-10-30 18:12:01 +020024MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver");
Pavel Machek66101de2008-10-01 14:36:56 +020025MODULE_LICENSE("GPL");
26MODULE_VERSION("0.1");
27
Greg Kroah-Hartman43a34692012-08-17 17:48:37 -070028static const struct usb_device_id wb35_table[] = {
Pekka Enberga32b9812009-04-08 11:14:04 +030029 { USB_DEVICE(0x0416, 0x0035) },
30 { USB_DEVICE(0x18E8, 0x6201) },
31 { USB_DEVICE(0x18E8, 0x6206) },
32 { USB_DEVICE(0x18E8, 0x6217) },
33 { USB_DEVICE(0x18E8, 0x6230) },
34 { USB_DEVICE(0x18E8, 0x6233) },
35 { USB_DEVICE(0x1131, 0x2035) },
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070036 { 0, }
Pavel Machek66101de2008-10-01 14:36:56 +020037};
38
Pekka Enbergdd38da42008-10-21 13:01:42 +030039MODULE_DEVICE_TABLE(usb, wb35_table);
Pavel Machek66101de2008-10-01 14:36:56 +020040
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070041static struct ieee80211_rate wbsoft_rates[] = {
Pavel Machek66101de2008-10-01 14:36:56 +020042 { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
43};
44
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070045static struct ieee80211_channel wbsoft_channels[] = {
Pekka Enberga32b9812009-04-08 11:14:04 +030046 { .center_freq = 2412 },
Pavel Machek66101de2008-10-01 14:36:56 +020047};
48
Pekka Enberga36e0892008-10-28 00:20:03 +020049static struct ieee80211_supported_band wbsoft_band_2GHz = {
50 .channels = wbsoft_channels,
51 .n_channels = ARRAY_SIZE(wbsoft_channels),
52 .bitrates = wbsoft_rates,
53 .n_bitrates = ARRAY_SIZE(wbsoft_rates),
54};
55
Pekka Enberg4074e772009-09-21 12:52:15 +030056static void hal_set_beacon_period(struct hw_data *pHwData, u16 beacon_period)
57{
58 u32 tmp;
59
60 if (pHwData->SurpriseRemove)
61 return;
62
63 pHwData->BeaconPeriod = beacon_period;
64 tmp = pHwData->BeaconPeriod << 16;
65 tmp |= pHwData->ProbeDelay;
66 Wb35Reg_Write(pHwData, 0x0848, tmp);
67}
68
Pavel Machek66101de2008-10-01 14:36:56 +020069static int wbsoft_add_interface(struct ieee80211_hw *dev,
Greg Kroah-Hartmana71b6762010-03-04 08:44:13 -080070 struct ieee80211_vif *vif)
Pavel Machek66101de2008-10-01 14:36:56 +020071{
Pekka Enberg4074e772009-09-21 12:52:15 +030072 struct wbsoft_priv *priv = dev->priv;
73
Greg Kroah-Hartmana71b6762010-03-04 08:44:13 -080074 hal_set_beacon_period(&priv->sHwData, vif->bss_conf.beacon_int);
Pekka Enberg4074e772009-09-21 12:52:15 +030075
Pavel Machek66101de2008-10-01 14:36:56 +020076 return 0;
77}
78
79static void wbsoft_remove_interface(struct ieee80211_hw *dev,
Greg Kroah-Hartmana71b6762010-03-04 08:44:13 -080080 struct ieee80211_vif *vif)
Pavel Machek66101de2008-10-01 14:36:56 +020081{
Pavel Machek66101de2008-10-01 14:36:56 +020082}
83
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070084static void wbsoft_stop(struct ieee80211_hw *hw)
Pavel Machek66101de2008-10-01 14:36:56 +020085{
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070086}
87
88static int wbsoft_get_stats(struct ieee80211_hw *hw,
89 struct ieee80211_low_level_stats *stats)
90{
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070091 return 0;
92}
93
Jiri Pirko22bedad32010-04-01 21:22:57 +000094static u64 wbsoft_prepare_multicast(struct ieee80211_hw *hw,
95 struct netdev_hw_addr_list *mc_list)
Jeff Mahoney6d7fd642009-10-08 17:27:51 -040096{
Jiri Pirko22bedad32010-04-01 21:22:57 +000097 return netdev_hw_addr_list_count(mc_list);
Jeff Mahoney6d7fd642009-10-08 17:27:51 -040098}
99
Pavel Machek66101de2008-10-01 14:36:56 +0200100static void wbsoft_configure_filter(struct ieee80211_hw *dev,
Pekka Enberga32b9812009-04-08 11:14:04 +0300101 unsigned int changed_flags,
102 unsigned int *total_flags,
Jeff Mahoney6d7fd642009-10-08 17:27:51 -0400103 u64 multicast)
Pavel Machek66101de2008-10-01 14:36:56 +0200104{
Pekka Enberg6ab32122009-03-27 19:46:45 +0200105 unsigned int new_flags;
Pavel Machek66101de2008-10-01 14:36:56 +0200106
107 new_flags = 0;
108
Pekka Enberg6ab32122009-03-27 19:46:45 +0200109 if (*total_flags & FIF_PROMISC_IN_BSS)
Pavel Machek66101de2008-10-01 14:36:56 +0200110 new_flags |= FIF_PROMISC_IN_BSS;
Jeff Mahoney6d7fd642009-10-08 17:27:51 -0400111 else if ((*total_flags & FIF_ALLMULTI) || (multicast > 32))
Pavel Machek66101de2008-10-01 14:36:56 +0200112 new_flags |= FIF_ALLMULTI;
Pavel Machek66101de2008-10-01 14:36:56 +0200113
114 dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
115
116 *total_flags = new_flags;
117}
118
Thomas Huehn36323f82012-07-23 21:33:42 +0200119static void wbsoft_tx(struct ieee80211_hw *dev,
120 struct ieee80211_tx_control *control,
121 struct sk_buff *skb)
Pavel Machek66101de2008-10-01 14:36:56 +0200122{
Pekka Enbergcc180712008-10-30 16:14:35 +0200123 struct wbsoft_priv *priv = dev->priv;
124
Ashvini Varatharajf68cae42013-10-21 19:27:30 +0530125 if (priv->sMlmeFrame.is_in_used != PACKET_FREE_TO_USE) {
Pekka Enberg11c9a552010-09-19 13:01:03 +0300126 priv->sMlmeFrame.wNumTxMMPDUDiscarded++;
Johannes Berg7bb45682011-02-24 14:42:06 +0100127 kfree_skb(skb);
128 return;
Pekka Enberg11c9a552010-09-19 13:01:03 +0300129 }
130
Ashvini Varatharajf68cae42013-10-21 19:27:30 +0530131 priv->sMlmeFrame.is_in_used = PACKET_COME_FROM_MLME;
Pekka Enberg11c9a552010-09-19 13:01:03 +0300132
133 priv->sMlmeFrame.pMMPDU = skb->data;
Ashvini Varatharajf68cae42013-10-21 19:27:30 +0530134 priv->sMlmeFrame.data_type = FRAME_TYPE_802_11_MANAGEMENT;
Pekka Enberg11c9a552010-09-19 13:01:03 +0300135 priv->sMlmeFrame.len = skb->len;
136 priv->sMlmeFrame.wNumTxMMPDU++;
137
138 /*
139 * H/W will enter power save by set the register. S/W don't send null
140 * frame with PWRMgt bit enbled to enter power save now.
141 */
142
143 Mds_Tx(priv);
Pavel Machek66101de2008-10-01 14:36:56 +0200144}
145
Pavel Machek66101de2008-10-01 14:36:56 +0200146static int wbsoft_start(struct ieee80211_hw *dev)
147{
Pekka Enbergc930e0c02008-10-30 18:12:04 +0200148 struct wbsoft_priv *priv = dev->priv;
149
150 priv->enabled = true;
151
Pavel Machek66101de2008-10-01 14:36:56 +0200152 return 0;
153}
154
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300155static void hal_set_radio_mode(struct hw_data *pHwData, unsigned char radio_off)
156{
157 struct wb35_reg *reg = &pHwData->reg;
158
159 if (pHwData->SurpriseRemove)
160 return;
161
Lars Lindleye5851c22010-04-02 10:57:35 +0200162 if (radio_off) { /* disable Baseband receive off */
163 pHwData->CurrentRadioSw = 1; /* off */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300164 reg->M24_MacControl &= 0xffffffbf;
165 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200166 pHwData->CurrentRadioSw = 0; /* on */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300167 reg->M24_MacControl |= 0x00000040;
168 }
169 Wb35Reg_Write(pHwData, 0x0824, reg->M24_MacControl);
170}
171
Lars Lindleye5851c22010-04-02 10:57:35 +0200172static void hal_set_current_channel_ex(struct hw_data *pHwData, struct chan_info channel)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300173{
174 struct wb35_reg *reg = &pHwData->reg;
175
176 if (pHwData->SurpriseRemove)
177 return;
178
Lars Lindleye5851c22010-04-02 10:57:35 +0200179 RFSynthesizer_SwitchingChannel(pHwData, channel); /* Switch channel */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300180 pHwData->Channel = channel.ChanNo;
181 pHwData->band = channel.band;
Lars Lindleye5851c22010-04-02 10:57:35 +0200182 reg->M28_MacControl &= ~0xff; /* Clean channel information field */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300183 reg->M28_MacControl |= channel.ChanNo;
184 Wb35Reg_WriteWithCallbackValue(pHwData, 0x0828, reg->M28_MacControl,
Lars Lindleye5851c22010-04-02 10:57:35 +0200185 (s8 *) &channel,
186 sizeof(struct chan_info));
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300187}
188
Pekka Enberg440a2332009-12-18 23:08:18 +0200189static void hal_set_current_channel(struct hw_data *pHwData, struct chan_info channel)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300190{
191 hal_set_current_channel_ex(pHwData, channel);
192}
193
194static void hal_set_accept_broadcast(struct hw_data *pHwData, u8 enable)
195{
196 struct wb35_reg *reg = &pHwData->reg;
197
198 if (pHwData->SurpriseRemove)
199 return;
200
Lars Lindleye5851c22010-04-02 10:57:35 +0200201 reg->M00_MacControl &= ~0x02000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300202
203 if (enable)
Lars Lindleye5851c22010-04-02 10:57:35 +0200204 reg->M00_MacControl |= 0x02000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300205
206 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
207}
208
Lars Lindleye5851c22010-04-02 10:57:35 +0200209/* For wep key error detection, we need to accept broadcast packets to be received temporary. */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300210static void hal_set_accept_promiscuous(struct hw_data *pHwData, u8 enable)
211{
212 struct wb35_reg *reg = &pHwData->reg;
213
214 if (pHwData->SurpriseRemove)
215 return;
Lars Lindleye5851c22010-04-02 10:57:35 +0200216
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300217 if (enable) {
218 reg->M00_MacControl |= 0x00400000;
219 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
220 } else {
221 reg->M00_MacControl &= ~0x00400000;
222 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
223 }
224}
225
226static void hal_set_accept_multicast(struct hw_data *pHwData, u8 enable)
227{
228 struct wb35_reg *reg = &pHwData->reg;
229
230 if (pHwData->SurpriseRemove)
231 return;
232
Lars Lindleye5851c22010-04-02 10:57:35 +0200233 reg->M00_MacControl &= ~0x01000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300234 if (enable)
Lars Lindleye5851c22010-04-02 10:57:35 +0200235 reg->M00_MacControl |= 0x01000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300236 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
237}
238
239static void hal_set_accept_beacon(struct hw_data *pHwData, u8 enable)
240{
241 struct wb35_reg *reg = &pHwData->reg;
242
243 if (pHwData->SurpriseRemove)
244 return;
245
Lars Lindleye5851c22010-04-02 10:57:35 +0200246 if (!enable) /* Due to SME and MLME are not suitable for 35 */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300247 return;
248
Lars Lindleye5851c22010-04-02 10:57:35 +0200249 reg->M00_MacControl &= ~0x04000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300250 if (enable)
Lars Lindleye5851c22010-04-02 10:57:35 +0200251 reg->M00_MacControl |= 0x04000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300252
253 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
254}
255
Greg Kroah-Hartmanf02466f2009-01-05 10:46:00 -0800256static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
Pavel Machek66101de2008-10-01 14:36:56 +0200257{
Pekka Enbergcc180712008-10-30 16:14:35 +0200258 struct wbsoft_priv *priv = dev->priv;
Pekka Enberg440a2332009-12-18 23:08:18 +0200259 struct chan_info ch;
Greg Kroah-Hartmanf02466f2009-01-05 10:46:00 -0800260
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300261 /* Should use channel_num, or something, as that is already pre-translated */
Pavel Machek66101de2008-10-01 14:36:56 +0200262 ch.band = 1;
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300263 ch.ChanNo = 1;
Pavel Machek66101de2008-10-01 14:36:56 +0200264
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200265 hal_set_current_channel(&priv->sHwData, ch);
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200266 hal_set_accept_broadcast(&priv->sHwData, 1);
Pekka Enberga32b9812009-04-08 11:14:04 +0300267 hal_set_accept_promiscuous(&priv->sHwData, 1);
268 hal_set_accept_multicast(&priv->sHwData, 1);
269 hal_set_accept_beacon(&priv->sHwData, 1);
270 hal_set_radio_mode(&priv->sHwData, 0);
Pavel Machek66101de2008-10-01 14:36:56 +0200271
272 return 0;
273}
274
Eliad Peller37a41b42011-09-21 14:06:11 +0300275static u64 wbsoft_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
Pavel Machek66101de2008-10-01 14:36:56 +0200276{
Pavel Machek66101de2008-10-01 14:36:56 +0200277 return 0;
278}
279
280static const struct ieee80211_ops wbsoft_ops = {
281 .tx = wbsoft_tx,
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300282 .start = wbsoft_start,
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -0700283 .stop = wbsoft_stop,
Pavel Machek66101de2008-10-01 14:36:56 +0200284 .add_interface = wbsoft_add_interface,
285 .remove_interface = wbsoft_remove_interface,
286 .config = wbsoft_config,
Jeff Mahoney6d7fd642009-10-08 17:27:51 -0400287 .prepare_multicast = wbsoft_prepare_multicast,
Pavel Machek66101de2008-10-01 14:36:56 +0200288 .configure_filter = wbsoft_configure_filter,
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -0700289 .get_stats = wbsoft_get_stats,
Pavel Machek66101de2008-10-01 14:36:56 +0200290 .get_tsf = wbsoft_get_tsf,
Pavel Machek66101de2008-10-01 14:36:56 +0200291};
292
Lars Lindleye5851c22010-04-02 10:57:35 +0200293static void hal_set_ethernet_address(struct hw_data *pHwData, u8 *current_address)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300294{
295 u32 ltmp[2];
296
297 if (pHwData->SurpriseRemove)
298 return;
299
300 memcpy(pHwData->CurrentMacAddress, current_address, ETH_ALEN);
301
302 ltmp[0] = cpu_to_le32(*(u32 *) pHwData->CurrentMacAddress);
Lars Lindleye5851c22010-04-02 10:57:35 +0200303 ltmp[1] = cpu_to_le32(*(u32 *) (pHwData->CurrentMacAddress + 4)) & 0xffff;
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300304
305 Wb35Reg_BurstWrite(pHwData, 0x03e8, ltmp, 2, AUTO_INCREMENT);
306}
307
Lars Lindleye5851c22010-04-02 10:57:35 +0200308static void hal_get_permanent_address(struct hw_data *pHwData, u8 *pethernet_address)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300309{
310 if (pHwData->SurpriseRemove)
311 return;
312
313 memcpy(pethernet_address, pHwData->PermanentMacAddress, 6);
314}
315
316static void hal_stop(struct hw_data *pHwData)
317{
318 struct wb35_reg *reg = &pHwData->reg;
319
320 pHwData->Wb35Rx.rx_halt = 1;
321 Wb35Rx_stop(pHwData);
322
323 pHwData->Wb35Tx.tx_halt = 1;
324 Wb35Tx_stop(pHwData);
325
Lars Lindleye5851c22010-04-02 10:57:35 +0200326 reg->D00_DmaControl &= ~0xc0000000; /* Tx Off, Rx Off */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300327 Wb35Reg_Write(pHwData, 0x0400, reg->D00_DmaControl);
328}
329
330static unsigned char hal_idle(struct hw_data *pHwData)
331{
332 struct wb35_reg *reg = &pHwData->reg;
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300333
Pekka Enberg9be98812010-11-28 23:00:07 +0200334 if (!pHwData->SurpriseRemove && reg->EP0vm_state != VM_STOP)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300335 return false;
336
337 return true;
338}
339
340u8 hal_get_antenna_number(struct hw_data *pHwData)
341{
342 struct wb35_reg *reg = &pHwData->reg;
343
344 if ((reg->BB2C & BIT(11)) == 0)
345 return 0;
346 else
347 return 1;
348}
349
350/* 0 : radio on; 1: radio off */
Lars Lindleye5851c22010-04-02 10:57:35 +0200351static u8 hal_get_hw_radio_off(struct hw_data *pHwData)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300352{
353 struct wb35_reg *reg = &pHwData->reg;
354
355 if (pHwData->SurpriseRemove)
356 return 1;
357
Lars Lindleye5851c22010-04-02 10:57:35 +0200358 /* read the bit16 of register U1B0 */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300359 Wb35Reg_Read(pHwData, 0x3b0, &reg->U1B0);
360 if ((reg->U1B0 & 0x00010000)) {
361 pHwData->CurrentRadioHw = 1;
362 return 1;
363 } else {
364 pHwData->CurrentRadioHw = 0;
365 return 0;
366 }
367}
368
Pekka Enberg833d0cd2009-04-08 11:14:06 +0300369static u8 LED_GRAY[20] = {
370 0, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 14, 13, 12, 11, 10, 8, 6, 4, 2
371};
372
373static u8 LED_GRAY2[30] = {
374 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
375 0, 15, 14, 13, 12, 11, 10, 9, 8
376};
377
Pekka Enberg80767e62009-04-08 11:13:57 +0300378static void hal_led_control(unsigned long data)
379{
Pekka Enberga32b9812009-04-08 11:14:04 +0300380 struct wbsoft_priv *adapter = (struct wbsoft_priv *)data;
381 struct hw_data *pHwData = &adapter->sHwData;
Pekka Enberg80767e62009-04-08 11:13:57 +0300382 struct wb35_reg *reg = &pHwData->reg;
Pekka Enberga32b9812009-04-08 11:14:04 +0300383 u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT;
Pekka Enberga32b9812009-04-08 11:14:04 +0300384 u32 TimeInterval = 500, ltmp, ltmp2;
385 ltmp = 0;
Pekka Enberg80767e62009-04-08 11:13:57 +0300386
Pekka Enberga32b9812009-04-08 11:14:04 +0300387 if (pHwData->SurpriseRemove)
388 return;
Pekka Enberg80767e62009-04-08 11:13:57 +0300389
Pekka Enberga32b9812009-04-08 11:14:04 +0300390 if (pHwData->LED_control) {
Pekka Enberg80767e62009-04-08 11:13:57 +0300391 ltmp2 = pHwData->LED_control & 0xff;
Lars Lindleye5851c22010-04-02 10:57:35 +0200392 if (ltmp2 == 5) { /* 5 is WPS mode */
Pekka Enberg80767e62009-04-08 11:13:57 +0300393 TimeInterval = 100;
Pekka Enberga32b9812009-04-08 11:14:04 +0300394 ltmp2 = (pHwData->LED_control >> 8) & 0xff;
395 switch (ltmp2) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200396 case 1: /* [0.2 On][0.1 Off]... */
Pekka Enberga32b9812009-04-08 11:14:04 +0300397 pHwData->LED_Blinking %= 3;
Lars Lindleye5851c22010-04-02 10:57:35 +0200398 ltmp = 0x1010; /* Led 1 & 0 Green and Red */
399 if (pHwData->LED_Blinking == 2) /* Turn off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300400 ltmp = 0;
401 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200402 case 2: /* [0.1 On][0.1 Off]... */
Pekka Enberga32b9812009-04-08 11:14:04 +0300403 pHwData->LED_Blinking %= 2;
Lars Lindleye5851c22010-04-02 10:57:35 +0200404 ltmp = 0x0010; /* Led 0 red color */
405 if (pHwData->LED_Blinking) /* Turn off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300406 ltmp = 0;
407 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200408 case 3: /* [0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.5 Off]... */
Pekka Enberga32b9812009-04-08 11:14:04 +0300409 pHwData->LED_Blinking %= 15;
Lars Lindleye5851c22010-04-02 10:57:35 +0200410 ltmp = 0x0010; /* Led 0 red color */
411 if ((pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking % 2)) /* Turn off 0.6 sec */
Pekka Enberga32b9812009-04-08 11:14:04 +0300412 ltmp = 0;
413 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200414 case 4: /* [300 On][ off ] */
415 ltmp = 0x1000; /* Led 1 Green color */
Pekka Enberga32b9812009-04-08 11:14:04 +0300416 if (pHwData->LED_Blinking >= 3000)
Lars Lindleye5851c22010-04-02 10:57:35 +0200417 ltmp = 0; /* led maybe on after 300sec * 32bit counter overlap. */
Pekka Enberga32b9812009-04-08 11:14:04 +0300418 break;
Pekka Enberg80767e62009-04-08 11:13:57 +0300419 }
420 pHwData->LED_Blinking++;
421
422 reg->U1BC_LEDConfigure = ltmp;
Lars Lindleye5851c22010-04-02 10:57:35 +0200423 if (LEDSet != 7) { /* Only 111 mode has 2 LEDs on PCB. */
424 reg->U1BC_LEDConfigure |= (ltmp & 0xff) << 8; /* Copy LED result to each LED control register */
Pekka Enberga32b9812009-04-08 11:14:04 +0300425 reg->U1BC_LEDConfigure |= (ltmp & 0xff00) >> 8;
Pekka Enberg80767e62009-04-08 11:13:57 +0300426 }
Pekka Enberga32b9812009-04-08 11:14:04 +0300427 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
Pekka Enberg80767e62009-04-08 11:13:57 +0300428 }
Lars Lindleye5851c22010-04-02 10:57:35 +0200429 } else if (pHwData->CurrentRadioSw || pHwData->CurrentRadioHw) { /* If radio off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300430 if (reg->U1BC_LEDConfigure & 0x1010) {
Pekka Enberg80767e62009-04-08 11:13:57 +0300431 reg->U1BC_LEDConfigure &= ~0x1010;
Pekka Enberga32b9812009-04-08 11:14:04 +0300432 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
Pekka Enberg80767e62009-04-08 11:13:57 +0300433 }
Pekka Enberga32b9812009-04-08 11:14:04 +0300434 } else {
435 switch (LEDSet) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200436 case 4: /* [100] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing */
437 if (!pHwData->LED_LinkOn) { /* Blink only if not Link On */
438 /* Blinking if scanning is on progress */
Pekka Enberga32b9812009-04-08 11:14:04 +0300439 if (pHwData->LED_Scanning) {
440 if (pHwData->LED_Blinking == 0) {
Pekka Enberg80767e62009-04-08 11:13:57 +0300441 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200442 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300443 pHwData->LED_Blinking = 1;
444 TimeInterval = 300;
445 } else {
Pekka Enberg80767e62009-04-08 11:13:57 +0300446 reg->U1BC_LEDConfigure &= ~0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200447 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300448 pHwData->LED_Blinking = 0;
449 TimeInterval = 300;
450 }
451 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200452 /* Turn Off LED_0 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300453 if (reg->U1BC_LEDConfigure & 0x10) {
454 reg->U1BC_LEDConfigure &= ~0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200455 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberg80767e62009-04-08 11:13:57 +0300456 }
457 }
Pekka Enberga32b9812009-04-08 11:14:04 +0300458 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200459 /* Turn On LED_0 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300460 if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
461 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200462 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300463 }
464 }
465 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200466 case 6: /* [110] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing */
467 if (!pHwData->LED_LinkOn) { /* Blink only if not Link On */
468 /* Blinking if scanning is on progress */
Pekka Enberga32b9812009-04-08 11:14:04 +0300469 if (pHwData->LED_Scanning) {
470 if (pHwData->LED_Blinking == 0) {
471 reg->U1BC_LEDConfigure &= ~0xf;
472 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200473 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300474 pHwData->LED_Blinking = 1;
475 TimeInterval = 300;
476 } else {
477 reg->U1BC_LEDConfigure &= ~0x1f;
Lars Lindleye5851c22010-04-02 10:57:35 +0200478 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300479 pHwData->LED_Blinking = 0;
480 TimeInterval = 300;
481 }
482 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200483 /* Gray blinking if in disconnect state and not scanning */
Pekka Enberga32b9812009-04-08 11:14:04 +0300484 ltmp = reg->U1BC_LEDConfigure;
485 reg->U1BC_LEDConfigure &= ~0x1f;
Pekka Enberg833d0cd2009-04-08 11:14:06 +0300486 if (LED_GRAY2[(pHwData->LED_Blinking % 30)]) {
Pekka Enberga32b9812009-04-08 11:14:04 +0300487 reg->U1BC_LEDConfigure |= 0x10;
488 reg->U1BC_LEDConfigure |=
Pekka Enberg833d0cd2009-04-08 11:14:06 +0300489 LED_GRAY2[(pHwData->LED_Blinking % 30)];
Pekka Enberga32b9812009-04-08 11:14:04 +0300490 }
491 pHwData->LED_Blinking++;
492 if (reg->U1BC_LEDConfigure != ltmp)
Lars Lindleye5851c22010-04-02 10:57:35 +0200493 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300494 TimeInterval = 100;
495 }
496 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200497 /* Turn On LED_0 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300498 if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
499 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200500 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300501 }
502 }
503 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200504 case 5: /* [101] Only 1 Led be placed on PCB and use LED_1 for showing */
505 if (!pHwData->LED_LinkOn) { /* Blink only if not Link On */
506 /* Blinking if scanning is on progress */
Pekka Enberga32b9812009-04-08 11:14:04 +0300507 if (pHwData->LED_Scanning) {
508 if (pHwData->LED_Blinking == 0) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200509 reg->U1BC_LEDConfigure |= 0x1000;
510 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300511 pHwData->LED_Blinking = 1;
512 TimeInterval = 300;
513 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200514 reg->U1BC_LEDConfigure &= ~0x1000;
515 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300516 pHwData->LED_Blinking = 0;
517 TimeInterval = 300;
518 }
519 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200520 /* Turn Off LED_1 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300521 if (reg->U1BC_LEDConfigure & 0x1000) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200522 reg->U1BC_LEDConfigure &= ~0x1000;
523 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300524 }
525 }
526 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200527 /* Is transmitting/receiving ?? */
Pekka Enberga32b9812009-04-08 11:14:04 +0300528 if ((adapter->RxByteCount !=
529 pHwData->RxByteCountLast)
530 || (adapter->TxByteCount !=
531 pHwData->TxByteCountLast)) {
532 if ((reg->U1BC_LEDConfigure & 0x3000) !=
533 0x3000) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200534 reg->U1BC_LEDConfigure |= 0x3000;
535 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300536 }
Lars Lindleye5851c22010-04-02 10:57:35 +0200537 /* Update variable */
Pekka Enberga32b9812009-04-08 11:14:04 +0300538 pHwData->RxByteCountLast =
539 adapter->RxByteCount;
540 pHwData->TxByteCountLast =
541 adapter->TxByteCount;
542 TimeInterval = 200;
543 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200544 /* Turn On LED_1 and blinking if transmitting/receiving */
Pekka Enberga32b9812009-04-08 11:14:04 +0300545 if ((reg->U1BC_LEDConfigure & 0x3000) !=
546 0x1000) {
547 reg->U1BC_LEDConfigure &=
548 ~0x3000;
549 reg->U1BC_LEDConfigure |=
550 0x1000;
Lars Lindleye5851c22010-04-02 10:57:35 +0200551 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300552 }
553 }
554 }
555 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200556 default: /* Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active */
Pekka Enberga32b9812009-04-08 11:14:04 +0300557 if ((reg->U1BC_LEDConfigure & 0x3000) != 0x3000) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200558 reg->U1BC_LEDConfigure |= 0x3000; /* LED_1 is always on and event enable */
Pekka Enberga32b9812009-04-08 11:14:04 +0300559 Wb35Reg_Write(pHwData, 0x03bc,
560 reg->U1BC_LEDConfigure);
561 }
562
563 if (pHwData->LED_Blinking) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200564 /* Gray blinking */
Pekka Enberga32b9812009-04-08 11:14:04 +0300565 reg->U1BC_LEDConfigure &= ~0x0f;
566 reg->U1BC_LEDConfigure |= 0x10;
567 reg->U1BC_LEDConfigure |=
Pekka Enberg833d0cd2009-04-08 11:14:06 +0300568 LED_GRAY[(pHwData->LED_Blinking - 1) % 20];
Pekka Enberga32b9812009-04-08 11:14:04 +0300569 Wb35Reg_Write(pHwData, 0x03bc,
570 reg->U1BC_LEDConfigure);
571
572 pHwData->LED_Blinking += 2;
573 if (pHwData->LED_Blinking < 40)
574 TimeInterval = 100;
575 else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200576 pHwData->LED_Blinking = 0; /* Stop blinking */
Pekka Enberga32b9812009-04-08 11:14:04 +0300577 reg->U1BC_LEDConfigure &= ~0x0f;
578 Wb35Reg_Write(pHwData, 0x03bc,
579 reg->U1BC_LEDConfigure);
580 }
Pekka Enberg80767e62009-04-08 11:13:57 +0300581 break;
Pekka Enberga32b9812009-04-08 11:14:04 +0300582 }
583
584 if (pHwData->LED_LinkOn) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200585 if (!(reg->U1BC_LEDConfigure & 0x10)) { /* Check the LED_0 */
586 /* Try to turn ON LED_0 after gray blinking */
Pekka Enberga32b9812009-04-08 11:14:04 +0300587 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200588 pHwData->LED_Blinking = 1; /* Start blinking */
Pekka Enberga32b9812009-04-08 11:14:04 +0300589 TimeInterval = 50;
590 }
591 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200592 if (reg->U1BC_LEDConfigure & 0x10) { /* Check the LED_0 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300593 reg->U1BC_LEDConfigure &= ~0x10;
594 Wb35Reg_Write(pHwData, 0x03bc,
595 reg->U1BC_LEDConfigure);
596 }
597 }
598 break;
Pekka Enberg80767e62009-04-08 11:13:57 +0300599 }
Pekka Enberg80767e62009-04-08 11:13:57 +0300600 }
601
602 pHwData->time_count += TimeInterval;
Lars Lindleye5851c22010-04-02 10:57:35 +0200603 Wb35Tx_CurrentTime(adapter, pHwData->time_count);
Pekka Enberg80767e62009-04-08 11:13:57 +0300604 pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(TimeInterval);
605 add_timer(&pHwData->LEDTimer);
606}
607
Pekka Enbergcfe31f82009-04-08 11:13:58 +0300608static int hal_init_hardware(struct ieee80211_hw *hw)
Pekka Enberg80767e62009-04-08 11:13:57 +0300609{
610 struct wbsoft_priv *priv = hw->priv;
Pekka Enberga32b9812009-04-08 11:14:04 +0300611 struct hw_data *pHwData = &priv->sHwData;
Pekka Enberg80767e62009-04-08 11:13:57 +0300612 u16 SoftwareSet;
613
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300614 pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME;
615 pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
Pekka Enberg80767e62009-04-08 11:13:57 +0300616
Pekka Enberg00e2e052009-04-08 11:13:59 +0300617 if (!Wb35Reg_initial(pHwData))
Pekka Enberga39ee672009-04-08 11:14:00 +0300618 goto error_reg_destroy;
Pekka Enberg80767e62009-04-08 11:13:57 +0300619
Pekka Enberg00e2e052009-04-08 11:13:59 +0300620 if (!Wb35Tx_initial(pHwData))
Pekka Enberga39ee672009-04-08 11:14:00 +0300621 goto error_tx_destroy;
Pekka Enberg80767e62009-04-08 11:13:57 +0300622
Pekka Enberg00e2e052009-04-08 11:13:59 +0300623 if (!Wb35Rx_initial(pHwData))
Pekka Enberga39ee672009-04-08 11:14:00 +0300624 goto error_rx_destroy;
Pekka Enberg80767e62009-04-08 11:13:57 +0300625
Pekka Enberg00e2e052009-04-08 11:13:59 +0300626 init_timer(&pHwData->LEDTimer);
627 pHwData->LEDTimer.function = hal_led_control;
Pekka Enberga32b9812009-04-08 11:14:04 +0300628 pHwData->LEDTimer.data = (unsigned long)priv;
Pekka Enberg00e2e052009-04-08 11:13:59 +0300629 pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(1000);
630 add_timer(&pHwData->LEDTimer);
Pekka Enberg80767e62009-04-08 11:13:57 +0300631
Pekka Enberga32b9812009-04-08 11:14:04 +0300632 SoftwareSet = hal_software_set(pHwData);
Pekka Enberg80767e62009-04-08 11:13:57 +0300633
Pekka Enberg00e2e052009-04-08 11:13:59 +0300634 Wb35Rx_start(hw);
635 Wb35Tx_EP2VM_start(priv);
636
637 return 0;
638
Pekka Enberga39ee672009-04-08 11:14:00 +0300639error_rx_destroy:
640 Wb35Rx_destroy(pHwData);
641error_tx_destroy:
642 Wb35Tx_destroy(pHwData);
643error_reg_destroy:
644 Wb35Reg_destroy(pHwData);
645
Pekka Enberg80767e62009-04-08 11:13:57 +0300646 pHwData->SurpriseRemove = 1;
Pekka Enbergcfe31f82009-04-08 11:13:58 +0300647 return -EINVAL;
Pekka Enberg80767e62009-04-08 11:13:57 +0300648}
649
Pekka Enberg26598512009-04-08 11:13:56 +0300650static int wb35_hw_init(struct ieee80211_hw *hw)
Pekka Enberg912b2092008-10-30 18:12:02 +0200651{
652 struct wbsoft_priv *priv = hw->priv;
Pekka Enberga32b9812009-04-08 11:14:04 +0300653 struct hw_data *pHwData = &priv->sHwData;
654 u8 EEPROM_region;
655 u8 HwRadioOff;
656 u8 *pMacAddr2;
657 u8 *pMacAddr;
Pekka Enberg26598512009-04-08 11:13:56 +0300658 int err;
Pekka Enberg912b2092008-10-30 18:12:02 +0200659
Pekka Enberg9ca748c2009-04-08 11:14:03 +0300660 pHwData->phy_type = RF_DECIDE_BY_INF;
Pekka Enberg912b2092008-10-30 18:12:02 +0200661
Pekka Enberga32b9812009-04-08 11:14:04 +0300662 priv->Mds.TxRTSThreshold = DEFAULT_RTSThreshold;
663 priv->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
664
665 priv->sLocalPara.region_INF = REGION_AUTO;
666 priv->sLocalPara.TxRateMode = RATE_AUTO;
667 priv->sLocalPara.bMacOperationMode = MODE_802_11_BG;
668 priv->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE;
669 priv->sLocalPara.bPreambleMode = AUTO_MODE;
670 priv->sLocalPara.bWepKeyError = false;
671 priv->sLocalPara.bToSelfPacketReceived = false;
672 priv->sLocalPara.WepKeyDetectTimerCount = 2 * 100; /* 2 seconds */
673
674 priv->sLocalPara.RadioOffStatus.boSwRadioOff = false;
Pekka Enberg912b2092008-10-30 18:12:02 +0200675
Pekka Enbergcfe31f82009-04-08 11:13:58 +0300676 err = hal_init_hardware(hw);
677 if (err)
Pekka Enberg912b2092008-10-30 18:12:02 +0200678 goto error;
679
Pekka Enberga32b9812009-04-08 11:14:04 +0300680 EEPROM_region = hal_get_region_from_EEPROM(pHwData);
Pekka Enberg912b2092008-10-30 18:12:02 +0200681 if (EEPROM_region != REGION_AUTO)
682 priv->sLocalPara.region = EEPROM_region;
683 else {
684 if (priv->sLocalPara.region_INF != REGION_AUTO)
685 priv->sLocalPara.region = priv->sLocalPara.region_INF;
686 else
Pekka Enberga32b9812009-04-08 11:14:04 +0300687 priv->sLocalPara.region = REGION_USA; /* default setting */
Pekka Enberg912b2092008-10-30 18:12:02 +0200688 }
689
Pekka Enberg912b2092008-10-30 18:12:02 +0200690 Mds_initial(priv);
691
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300692 /*
Uwe Kleine-Königf69b0d62010-07-12 17:15:46 +0200693 * If no user-defined address in the registry, use the address
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300694 * "burned" on the NIC instead.
695 */
Pekka Enberg912b2092008-10-30 18:12:02 +0200696 pMacAddr = priv->sLocalPara.ThisMacAddress;
697 pMacAddr2 = priv->sLocalPara.PermanentAddress;
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300698
699 /* Reading ethernet address from EEPROM */
Pekka Enberga32b9812009-04-08 11:14:04 +0300700 hal_get_permanent_address(pHwData, priv->sLocalPara.PermanentAddress);
Pekka Enberg912b2092008-10-30 18:12:02 +0200701 if (memcmp(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) == 0)
702 memcpy(pMacAddr, pMacAddr2, MAC_ADDR_LENGTH);
703 else {
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300704 /* Set the user define MAC address */
Pekka Enberga32b9812009-04-08 11:14:04 +0300705 hal_set_ethernet_address(pHwData,
706 priv->sLocalPara.ThisMacAddress);
Pekka Enberg912b2092008-10-30 18:12:02 +0200707 }
708
Pekka Enberg912b2092008-10-30 18:12:02 +0200709 priv->sLocalPara.bAntennaNo = hal_get_antenna_number(pHwData);
Pekka Enberga32b9812009-04-08 11:14:04 +0300710 hal_get_hw_radio_off(pHwData);
Pekka Enberg912b2092008-10-30 18:12:02 +0200711
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300712 /* Waiting for HAL setting OK */
Pekka Enberg912b2092008-10-30 18:12:02 +0200713 while (!hal_idle(pHwData))
714 msleep(10);
715
716 MTO_Init(priv);
717
Pekka Enberga32b9812009-04-08 11:14:04 +0300718 HwRadioOff = hal_get_hw_radio_off(pHwData);
Pekka Enberg912b2092008-10-30 18:12:02 +0200719 priv->sLocalPara.RadioOffStatus.boHwRadioOff = !!HwRadioOff;
720
Pekka Enberga32b9812009-04-08 11:14:04 +0300721 hal_set_radio_mode(pHwData,
722 (unsigned char)(priv->sLocalPara.RadioOffStatus.
723 boSwRadioOff
724 || priv->sLocalPara.RadioOffStatus.
725 boHwRadioOff));
Pekka Enberg912b2092008-10-30 18:12:02 +0200726
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300727 /* Notify hal that the driver is ready now. */
728 hal_driver_init_OK(pHwData) = 1;
Pekka Enberg912b2092008-10-30 18:12:02 +0200729
730error:
Pekka Enberg26598512009-04-08 11:13:56 +0300731 return err;
Pekka Enberg912b2092008-10-30 18:12:02 +0200732}
733
Pekka Enberga32b9812009-04-08 11:14:04 +0300734static int wb35_probe(struct usb_interface *intf,
735 const struct usb_device_id *id_table)
Pavel Machek66101de2008-10-01 14:36:56 +0200736{
Pavel Machek66101de2008-10-01 14:36:56 +0200737 struct usb_device *udev = interface_to_usbdev(intf);
Pekka Enberga32b9812009-04-08 11:14:04 +0300738 struct usb_endpoint_descriptor *endpoint;
739 struct usb_host_interface *interface;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300740 struct ieee80211_hw *dev;
Pekka Enberga32b9812009-04-08 11:14:04 +0300741 struct wbsoft_priv *priv;
Devendra Naga6594ac52012-07-14 13:25:37 +0545742 int err;
Pekka Enberga32b9812009-04-08 11:14:04 +0300743 u32 ltmp;
Pavel Machek66101de2008-10-01 14:36:56 +0200744
745 usb_get_dev(udev);
746
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300747 /* Check the device if it already be opened */
Devendra Naga6594ac52012-07-14 13:25:37 +0545748 err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
Pekka Enberga32b9812009-04-08 11:14:04 +0300749 0x01,
750 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
751 0x0, 0x400, &ltmp, 4, HZ * 100);
Devendra Naga6594ac52012-07-14 13:25:37 +0545752 if (err < 0)
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300753 goto error;
754
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300755 /* Is already initialized? */
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300756 ltmp = cpu_to_le32(ltmp);
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300757 if (ltmp) {
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300758 err = -EBUSY;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300759 goto error;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300760 }
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300761
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200762 dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
Pekka Enbergacfa5112009-01-30 11:32:47 +0200763 if (!dev) {
764 err = -ENOMEM;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300765 goto error;
Pekka Enbergacfa5112009-01-30 11:32:47 +0200766 }
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300767
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200768 priv = dev->priv;
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200769
Pekka Enberg2894c6c2010-11-28 23:00:08 +0200770 priv->sHwData.udev = udev;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300771
Pekka Enberga32b9812009-04-08 11:14:04 +0300772 interface = intf->cur_altsetting;
773 endpoint = &interface->endpoint[0].desc;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300774
Pekka Enberg26598512009-04-08 11:13:56 +0300775 err = wb35_hw_init(dev);
776 if (err)
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200777 goto error_free_hw;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300778
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300779 SET_IEEE80211_DEV(dev, &udev->dev);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300780 {
Pekka Enberga32b9812009-04-08 11:14:04 +0300781 struct hw_data *pHwData = &priv->sHwData;
782 unsigned char dev_addr[MAX_ADDR_LEN];
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300783 hal_get_permanent_address(pHwData, dev_addr);
784 SET_IEEE80211_PERM_ADDR(dev, dev_addr);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300785 }
Pavel Machek66101de2008-10-01 14:36:56 +0200786
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300787 dev->extra_tx_headroom = 12; /* FIXME */
Pavel Machek05e361c2009-01-30 10:05:25 +0100788 dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
789 dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
Pavel Machek66101de2008-10-01 14:36:56 +0200790
Pavel Machek05e361c2009-01-30 10:05:25 +0100791 dev->max_signal = 100;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300792 dev->queues = 1;
793
Pekka Enberga36e0892008-10-28 00:20:03 +0200794 dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &wbsoft_band_2GHz;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300795
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300796 err = ieee80211_register_hw(dev);
797 if (err)
798 goto error_free_hw;
799
Pekka Enberg82fbb012009-04-16 14:43:14 +0300800 usb_set_intfdata(intf, dev);
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300801
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300802 return 0;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300803
804error_free_hw:
805 ieee80211_free_hw(dev);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300806error:
Pekka Enberg4af12e52008-10-27 23:29:31 +0200807 usb_put_dev(udev);
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300808 return err;
Pavel Machek66101de2008-10-01 14:36:56 +0200809}
810
Pekka Enbergf592a852009-04-08 11:14:01 +0300811static void hal_halt(struct hw_data *pHwData)
812{
813 del_timer_sync(&pHwData->LEDTimer);
814 /* XXX: Wait for Timer DPC exit. */
815 msleep(100);
816 Wb35Rx_destroy(pHwData);
817 Wb35Tx_destroy(pHwData);
818 Wb35Reg_destroy(pHwData);
819}
820
Pekka Enberg912b2092008-10-30 18:12:02 +0200821static void wb35_hw_halt(struct wbsoft_priv *adapter)
822{
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300823 /* Turn off Rx and Tx hardware ability */
Pekka Enberga32b9812009-04-08 11:14:04 +0300824 hal_stop(&adapter->sHwData);
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300825 /* Waiting Irp completed */
826 msleep(100);
Pekka Enberg912b2092008-10-30 18:12:02 +0200827
Pekka Enbergf592a852009-04-08 11:14:01 +0300828 hal_halt(&adapter->sHwData);
Pekka Enberg912b2092008-10-30 18:12:02 +0200829}
830
Pekka Enberg302bae82008-10-22 19:05:54 +0300831static void wb35_disconnect(struct usb_interface *intf)
Pavel Machek66101de2008-10-01 14:36:56 +0200832{
Pekka Enberg82fbb012009-04-16 14:43:14 +0300833 struct ieee80211_hw *hw = usb_get_intfdata(intf);
834 struct wbsoft_priv *priv = hw->priv;
Pavel Machek66101de2008-10-01 14:36:56 +0200835
Pekka Enberg912b2092008-10-30 18:12:02 +0200836 wb35_hw_halt(priv);
Pavel Machek66101de2008-10-01 14:36:56 +0200837
Pekka Enberg82fbb012009-04-16 14:43:14 +0300838 ieee80211_stop_queues(hw);
839 ieee80211_unregister_hw(hw);
840 ieee80211_free_hw(hw);
841
Pekka Enberg4af12e52008-10-27 23:29:31 +0200842 usb_set_intfdata(intf, NULL);
843 usb_put_dev(interface_to_usbdev(intf));
Pavel Machek66101de2008-10-01 14:36:56 +0200844}
845
Pekka Enbergdd38da42008-10-21 13:01:42 +0300846static struct usb_driver wb35_driver = {
847 .name = "w35und",
848 .id_table = wb35_table,
849 .probe = wb35_probe,
850 .disconnect = wb35_disconnect,
851};
Pavel Machek66101de2008-10-01 14:36:56 +0200852
Greg Kroah-Hartmanbac2c122011-11-18 09:42:11 -0800853module_usb_driver(wb35_driver);