blob: d7694e6a37a1e8a5ee308c45ea0bf9a64398eedd [file] [log] [blame]
Pavel Machek66101de2008-10-01 14:36:56 +02001/*
2 * Copyright 2008 Pavel Machek <pavel@suse.cz>
3 *
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>
14
Pekka Enbergcc180712008-10-30 16:14:35 +020015#include "core.h"
Pekka Enberg912b2092008-10-30 18:12:02 +020016#include "mds_f.h"
Pekka Enberg9ce922f2008-10-30 13:05:42 +020017#include "mlmetxrx_f.h"
Pekka Enberg64328c82009-01-07 17:33:45 +020018#include "mto.h"
Pekka Enberg9ce922f2008-10-30 13:05:42 +020019#include "wbhal_f.h"
20#include "wblinux_f.h"
Pavel Machek66101de2008-10-01 14:36:56 +020021
Pekka Enberg7b9a79b2008-10-30 18:12:01 +020022MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver");
Pavel Machek66101de2008-10-01 14:36:56 +020023MODULE_LICENSE("GPL");
24MODULE_VERSION("0.1");
25
Németh Mártona4577322010-01-10 00:18:34 +010026static const struct usb_device_id wb35_table[] __devinitconst = {
Pekka Enberga32b9812009-04-08 11:14:04 +030027 { USB_DEVICE(0x0416, 0x0035) },
28 { USB_DEVICE(0x18E8, 0x6201) },
29 { USB_DEVICE(0x18E8, 0x6206) },
30 { USB_DEVICE(0x18E8, 0x6217) },
31 { USB_DEVICE(0x18E8, 0x6230) },
32 { USB_DEVICE(0x18E8, 0x6233) },
33 { USB_DEVICE(0x1131, 0x2035) },
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070034 { 0, }
Pavel Machek66101de2008-10-01 14:36:56 +020035};
36
Pekka Enbergdd38da42008-10-21 13:01:42 +030037MODULE_DEVICE_TABLE(usb, wb35_table);
Pavel Machek66101de2008-10-01 14:36:56 +020038
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070039static struct ieee80211_rate wbsoft_rates[] = {
Pavel Machek66101de2008-10-01 14:36:56 +020040 { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
41};
42
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070043static struct ieee80211_channel wbsoft_channels[] = {
Pekka Enberga32b9812009-04-08 11:14:04 +030044 { .center_freq = 2412 },
Pavel Machek66101de2008-10-01 14:36:56 +020045};
46
Pekka Enberga36e0892008-10-28 00:20:03 +020047static struct ieee80211_supported_band wbsoft_band_2GHz = {
48 .channels = wbsoft_channels,
49 .n_channels = ARRAY_SIZE(wbsoft_channels),
50 .bitrates = wbsoft_rates,
51 .n_bitrates = ARRAY_SIZE(wbsoft_rates),
52};
53
Pekka Enberg4074e772009-09-21 12:52:15 +030054static void hal_set_beacon_period(struct hw_data *pHwData, u16 beacon_period)
55{
56 u32 tmp;
57
58 if (pHwData->SurpriseRemove)
59 return;
60
61 pHwData->BeaconPeriod = beacon_period;
62 tmp = pHwData->BeaconPeriod << 16;
63 tmp |= pHwData->ProbeDelay;
64 Wb35Reg_Write(pHwData, 0x0848, tmp);
65}
66
Pavel Machek66101de2008-10-01 14:36:56 +020067static int wbsoft_add_interface(struct ieee80211_hw *dev,
Greg Kroah-Hartmana71b6762010-03-04 08:44:13 -080068 struct ieee80211_vif *vif)
Pavel Machek66101de2008-10-01 14:36:56 +020069{
Pekka Enberg4074e772009-09-21 12:52:15 +030070 struct wbsoft_priv *priv = dev->priv;
71
Greg Kroah-Hartmana71b6762010-03-04 08:44:13 -080072 hal_set_beacon_period(&priv->sHwData, vif->bss_conf.beacon_int);
Pekka Enberg4074e772009-09-21 12:52:15 +030073
Pavel Machek66101de2008-10-01 14:36:56 +020074 return 0;
75}
76
77static void wbsoft_remove_interface(struct ieee80211_hw *dev,
Greg Kroah-Hartmana71b6762010-03-04 08:44:13 -080078 struct ieee80211_vif *vif)
Pavel Machek66101de2008-10-01 14:36:56 +020079{
80 printk("wbsoft_remove interface called\n");
81}
82
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070083static void wbsoft_stop(struct ieee80211_hw *hw)
Pavel Machek66101de2008-10-01 14:36:56 +020084{
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -070085 printk(KERN_INFO "%s called\n", __func__);
86}
87
88static int wbsoft_get_stats(struct ieee80211_hw *hw,
89 struct ieee80211_low_level_stats *stats)
90{
91 printk(KERN_INFO "%s called\n", __func__);
92 return 0;
93}
94
Jeff Mahoney6d7fd642009-10-08 17:27:51 -040095static u64 wbsoft_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
96 struct dev_addr_list *mc_list)
97{
98 return mc_count;
99}
100
Pavel Machek66101de2008-10-01 14:36:56 +0200101static void wbsoft_configure_filter(struct ieee80211_hw *dev,
Pekka Enberga32b9812009-04-08 11:14:04 +0300102 unsigned int changed_flags,
103 unsigned int *total_flags,
Jeff Mahoney6d7fd642009-10-08 17:27:51 -0400104 u64 multicast)
Pavel Machek66101de2008-10-01 14:36:56 +0200105{
Pekka Enberg6ab32122009-03-27 19:46:45 +0200106 unsigned int new_flags;
Pavel Machek66101de2008-10-01 14:36:56 +0200107
108 new_flags = 0;
109
Pekka Enberg6ab32122009-03-27 19:46:45 +0200110 if (*total_flags & FIF_PROMISC_IN_BSS)
Pavel Machek66101de2008-10-01 14:36:56 +0200111 new_flags |= FIF_PROMISC_IN_BSS;
Jeff Mahoney6d7fd642009-10-08 17:27:51 -0400112 else if ((*total_flags & FIF_ALLMULTI) || (multicast > 32))
Pavel Machek66101de2008-10-01 14:36:56 +0200113 new_flags |= FIF_ALLMULTI;
Pavel Machek66101de2008-10-01 14:36:56 +0200114
115 dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
116
117 *total_flags = new_flags;
118}
119
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -0700120static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
Pavel Machek66101de2008-10-01 14:36:56 +0200121{
Pekka Enbergcc180712008-10-30 16:14:35 +0200122 struct wbsoft_priv *priv = dev->priv;
123
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200124 MLMESendFrame(priv, skb->data, skb->len, FRAME_TYPE_802_11_MANAGEMENT);
Pekka Enberg16d36592008-10-28 00:14:38 +0200125
Pavel Machek66101de2008-10-01 14:36:56 +0200126 return NETDEV_TX_OK;
127}
128
Pavel Machek66101de2008-10-01 14:36:56 +0200129static int wbsoft_start(struct ieee80211_hw *dev)
130{
Pekka Enbergc930e0c02008-10-30 18:12:04 +0200131 struct wbsoft_priv *priv = dev->priv;
132
133 priv->enabled = true;
134
Pavel Machek66101de2008-10-01 14:36:56 +0200135 return 0;
136}
137
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300138static void hal_set_radio_mode(struct hw_data *pHwData, unsigned char radio_off)
139{
140 struct wb35_reg *reg = &pHwData->reg;
141
142 if (pHwData->SurpriseRemove)
143 return;
144
Lars Lindleye5851c22010-04-02 10:57:35 +0200145 if (radio_off) { /* disable Baseband receive off */
146 pHwData->CurrentRadioSw = 1; /* off */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300147 reg->M24_MacControl &= 0xffffffbf;
148 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200149 pHwData->CurrentRadioSw = 0; /* on */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300150 reg->M24_MacControl |= 0x00000040;
151 }
152 Wb35Reg_Write(pHwData, 0x0824, reg->M24_MacControl);
153}
154
Lars Lindleye5851c22010-04-02 10:57:35 +0200155static void hal_set_current_channel_ex(struct hw_data *pHwData, struct chan_info channel)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300156{
157 struct wb35_reg *reg = &pHwData->reg;
158
159 if (pHwData->SurpriseRemove)
160 return;
161
162 printk("Going to channel: %d/%d\n", channel.band, channel.ChanNo);
163
Lars Lindleye5851c22010-04-02 10:57:35 +0200164 RFSynthesizer_SwitchingChannel(pHwData, channel); /* Switch channel */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300165 pHwData->Channel = channel.ChanNo;
166 pHwData->band = channel.band;
167#ifdef _PE_STATE_DUMP_
168 printk("Set channel is %d, band =%d\n", pHwData->Channel,
169 pHwData->band);
170#endif
Lars Lindleye5851c22010-04-02 10:57:35 +0200171 reg->M28_MacControl &= ~0xff; /* Clean channel information field */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300172 reg->M28_MacControl |= channel.ChanNo;
173 Wb35Reg_WriteWithCallbackValue(pHwData, 0x0828, reg->M28_MacControl,
Lars Lindleye5851c22010-04-02 10:57:35 +0200174 (s8 *) &channel,
175 sizeof(struct chan_info));
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300176}
177
Pekka Enberg440a2332009-12-18 23:08:18 +0200178static void hal_set_current_channel(struct hw_data *pHwData, struct chan_info channel)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300179{
180 hal_set_current_channel_ex(pHwData, channel);
181}
182
183static void hal_set_accept_broadcast(struct hw_data *pHwData, u8 enable)
184{
185 struct wb35_reg *reg = &pHwData->reg;
186
187 if (pHwData->SurpriseRemove)
188 return;
189
Lars Lindleye5851c22010-04-02 10:57:35 +0200190 reg->M00_MacControl &= ~0x02000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300191
192 if (enable)
Lars Lindleye5851c22010-04-02 10:57:35 +0200193 reg->M00_MacControl |= 0x02000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300194
195 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
196}
197
Lars Lindleye5851c22010-04-02 10:57:35 +0200198/* For wep key error detection, we need to accept broadcast packets to be received temporary. */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300199static void hal_set_accept_promiscuous(struct hw_data *pHwData, u8 enable)
200{
201 struct wb35_reg *reg = &pHwData->reg;
202
203 if (pHwData->SurpriseRemove)
204 return;
Lars Lindleye5851c22010-04-02 10:57:35 +0200205
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300206 if (enable) {
207 reg->M00_MacControl |= 0x00400000;
208 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
209 } else {
210 reg->M00_MacControl &= ~0x00400000;
211 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
212 }
213}
214
215static void hal_set_accept_multicast(struct hw_data *pHwData, u8 enable)
216{
217 struct wb35_reg *reg = &pHwData->reg;
218
219 if (pHwData->SurpriseRemove)
220 return;
221
Lars Lindleye5851c22010-04-02 10:57:35 +0200222 reg->M00_MacControl &= ~0x01000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300223 if (enable)
Lars Lindleye5851c22010-04-02 10:57:35 +0200224 reg->M00_MacControl |= 0x01000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300225 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
226}
227
228static void hal_set_accept_beacon(struct hw_data *pHwData, u8 enable)
229{
230 struct wb35_reg *reg = &pHwData->reg;
231
232 if (pHwData->SurpriseRemove)
233 return;
234
Lars Lindleye5851c22010-04-02 10:57:35 +0200235 if (!enable) /* Due to SME and MLME are not suitable for 35 */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300236 return;
237
Lars Lindleye5851c22010-04-02 10:57:35 +0200238 reg->M00_MacControl &= ~0x04000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300239 if (enable)
Lars Lindleye5851c22010-04-02 10:57:35 +0200240 reg->M00_MacControl |= 0x04000000; /* The HW value */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300241
242 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
243}
244
Greg Kroah-Hartmanf02466f2009-01-05 10:46:00 -0800245static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
Pavel Machek66101de2008-10-01 14:36:56 +0200246{
Pekka Enbergcc180712008-10-30 16:14:35 +0200247 struct wbsoft_priv *priv = dev->priv;
Pekka Enberg440a2332009-12-18 23:08:18 +0200248 struct chan_info ch;
Greg Kroah-Hartmanf02466f2009-01-05 10:46:00 -0800249
Pavel Machek66101de2008-10-01 14:36:56 +0200250 printk("wbsoft_config called\n");
251
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300252 /* Should use channel_num, or something, as that is already pre-translated */
Pavel Machek66101de2008-10-01 14:36:56 +0200253 ch.band = 1;
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300254 ch.ChanNo = 1;
Pavel Machek66101de2008-10-01 14:36:56 +0200255
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200256 hal_set_current_channel(&priv->sHwData, ch);
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200257 hal_set_accept_broadcast(&priv->sHwData, 1);
Pekka Enberga32b9812009-04-08 11:14:04 +0300258 hal_set_accept_promiscuous(&priv->sHwData, 1);
259 hal_set_accept_multicast(&priv->sHwData, 1);
260 hal_set_accept_beacon(&priv->sHwData, 1);
261 hal_set_radio_mode(&priv->sHwData, 0);
Pavel Machek66101de2008-10-01 14:36:56 +0200262
263 return 0;
264}
265
Pavel Machek66101de2008-10-01 14:36:56 +0200266static u64 wbsoft_get_tsf(struct ieee80211_hw *dev)
267{
268 printk("wbsoft_get_tsf called\n");
269 return 0;
270}
271
272static const struct ieee80211_ops wbsoft_ops = {
273 .tx = wbsoft_tx,
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300274 .start = wbsoft_start,
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -0700275 .stop = wbsoft_stop,
Pavel Machek66101de2008-10-01 14:36:56 +0200276 .add_interface = wbsoft_add_interface,
277 .remove_interface = wbsoft_remove_interface,
278 .config = wbsoft_config,
Jeff Mahoney6d7fd642009-10-08 17:27:51 -0400279 .prepare_multicast = wbsoft_prepare_multicast,
Pavel Machek66101de2008-10-01 14:36:56 +0200280 .configure_filter = wbsoft_configure_filter,
Greg Kroah-Hartman68ab0c92008-10-21 10:41:45 -0700281 .get_stats = wbsoft_get_stats,
Pavel Machek66101de2008-10-01 14:36:56 +0200282 .get_tsf = wbsoft_get_tsf,
Pavel Machek66101de2008-10-01 14:36:56 +0200283};
284
Lars Lindleye5851c22010-04-02 10:57:35 +0200285static void hal_set_ethernet_address(struct hw_data *pHwData, u8 *current_address)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300286{
287 u32 ltmp[2];
288
289 if (pHwData->SurpriseRemove)
290 return;
291
292 memcpy(pHwData->CurrentMacAddress, current_address, ETH_ALEN);
293
294 ltmp[0] = cpu_to_le32(*(u32 *) pHwData->CurrentMacAddress);
Lars Lindleye5851c22010-04-02 10:57:35 +0200295 ltmp[1] = cpu_to_le32(*(u32 *) (pHwData->CurrentMacAddress + 4)) & 0xffff;
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300296
297 Wb35Reg_BurstWrite(pHwData, 0x03e8, ltmp, 2, AUTO_INCREMENT);
298}
299
Lars Lindleye5851c22010-04-02 10:57:35 +0200300static void hal_get_permanent_address(struct hw_data *pHwData, u8 *pethernet_address)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300301{
302 if (pHwData->SurpriseRemove)
303 return;
304
305 memcpy(pethernet_address, pHwData->PermanentMacAddress, 6);
306}
307
308static void hal_stop(struct hw_data *pHwData)
309{
310 struct wb35_reg *reg = &pHwData->reg;
311
312 pHwData->Wb35Rx.rx_halt = 1;
313 Wb35Rx_stop(pHwData);
314
315 pHwData->Wb35Tx.tx_halt = 1;
316 Wb35Tx_stop(pHwData);
317
Lars Lindleye5851c22010-04-02 10:57:35 +0200318 reg->D00_DmaControl &= ~0xc0000000; /* Tx Off, Rx Off */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300319 Wb35Reg_Write(pHwData, 0x0400, reg->D00_DmaControl);
320}
321
322static unsigned char hal_idle(struct hw_data *pHwData)
323{
324 struct wb35_reg *reg = &pHwData->reg;
325 struct wb_usb *pWbUsb = &pHwData->WbUsb;
326
327 if (!pHwData->SurpriseRemove
328 && (pWbUsb->DetectCount || reg->EP0vm_state != VM_STOP))
329 return false;
330
331 return true;
332}
333
334u8 hal_get_antenna_number(struct hw_data *pHwData)
335{
336 struct wb35_reg *reg = &pHwData->reg;
337
338 if ((reg->BB2C & BIT(11)) == 0)
339 return 0;
340 else
341 return 1;
342}
343
344/* 0 : radio on; 1: radio off */
Lars Lindleye5851c22010-04-02 10:57:35 +0200345static u8 hal_get_hw_radio_off(struct hw_data *pHwData)
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300346{
347 struct wb35_reg *reg = &pHwData->reg;
348
349 if (pHwData->SurpriseRemove)
350 return 1;
351
Lars Lindleye5851c22010-04-02 10:57:35 +0200352 /* read the bit16 of register U1B0 */
Pekka Enberg22a82bc2009-04-08 11:51:20 +0300353 Wb35Reg_Read(pHwData, 0x3b0, &reg->U1B0);
354 if ((reg->U1B0 & 0x00010000)) {
355 pHwData->CurrentRadioHw = 1;
356 return 1;
357 } else {
358 pHwData->CurrentRadioHw = 0;
359 return 0;
360 }
361}
362
Pekka Enberg833d0cd2009-04-08 11:14:06 +0300363static u8 LED_GRAY[20] = {
364 0, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 14, 13, 12, 11, 10, 8, 6, 4, 2
365};
366
367static u8 LED_GRAY2[30] = {
368 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369 0, 15, 14, 13, 12, 11, 10, 9, 8
370};
371
Pekka Enberg80767e62009-04-08 11:13:57 +0300372static void hal_led_control(unsigned long data)
373{
Pekka Enberga32b9812009-04-08 11:14:04 +0300374 struct wbsoft_priv *adapter = (struct wbsoft_priv *)data;
375 struct hw_data *pHwData = &adapter->sHwData;
Pekka Enberg80767e62009-04-08 11:13:57 +0300376 struct wb35_reg *reg = &pHwData->reg;
Pekka Enberga32b9812009-04-08 11:14:04 +0300377 u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT;
Pekka Enberga32b9812009-04-08 11:14:04 +0300378 u32 TimeInterval = 500, ltmp, ltmp2;
379 ltmp = 0;
Pekka Enberg80767e62009-04-08 11:13:57 +0300380
Pekka Enberga32b9812009-04-08 11:14:04 +0300381 if (pHwData->SurpriseRemove)
382 return;
Pekka Enberg80767e62009-04-08 11:13:57 +0300383
Pekka Enberga32b9812009-04-08 11:14:04 +0300384 if (pHwData->LED_control) {
Pekka Enberg80767e62009-04-08 11:13:57 +0300385 ltmp2 = pHwData->LED_control & 0xff;
Lars Lindleye5851c22010-04-02 10:57:35 +0200386 if (ltmp2 == 5) { /* 5 is WPS mode */
Pekka Enberg80767e62009-04-08 11:13:57 +0300387 TimeInterval = 100;
Pekka Enberga32b9812009-04-08 11:14:04 +0300388 ltmp2 = (pHwData->LED_control >> 8) & 0xff;
389 switch (ltmp2) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200390 case 1: /* [0.2 On][0.1 Off]... */
Pekka Enberga32b9812009-04-08 11:14:04 +0300391 pHwData->LED_Blinking %= 3;
Lars Lindleye5851c22010-04-02 10:57:35 +0200392 ltmp = 0x1010; /* Led 1 & 0 Green and Red */
393 if (pHwData->LED_Blinking == 2) /* Turn off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300394 ltmp = 0;
395 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200396 case 2: /* [0.1 On][0.1 Off]... */
Pekka Enberga32b9812009-04-08 11:14:04 +0300397 pHwData->LED_Blinking %= 2;
Lars Lindleye5851c22010-04-02 10:57:35 +0200398 ltmp = 0x0010; /* Led 0 red color */
399 if (pHwData->LED_Blinking) /* Turn off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300400 ltmp = 0;
401 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200402 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 +0300403 pHwData->LED_Blinking %= 15;
Lars Lindleye5851c22010-04-02 10:57:35 +0200404 ltmp = 0x0010; /* Led 0 red color */
405 if ((pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking % 2)) /* Turn off 0.6 sec */
Pekka Enberga32b9812009-04-08 11:14:04 +0300406 ltmp = 0;
407 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200408 case 4: /* [300 On][ off ] */
409 ltmp = 0x1000; /* Led 1 Green color */
Pekka Enberga32b9812009-04-08 11:14:04 +0300410 if (pHwData->LED_Blinking >= 3000)
Lars Lindleye5851c22010-04-02 10:57:35 +0200411 ltmp = 0; /* led maybe on after 300sec * 32bit counter overlap. */
Pekka Enberga32b9812009-04-08 11:14:04 +0300412 break;
Pekka Enberg80767e62009-04-08 11:13:57 +0300413 }
414 pHwData->LED_Blinking++;
415
416 reg->U1BC_LEDConfigure = ltmp;
Lars Lindleye5851c22010-04-02 10:57:35 +0200417 if (LEDSet != 7) { /* Only 111 mode has 2 LEDs on PCB. */
418 reg->U1BC_LEDConfigure |= (ltmp & 0xff) << 8; /* Copy LED result to each LED control register */
Pekka Enberga32b9812009-04-08 11:14:04 +0300419 reg->U1BC_LEDConfigure |= (ltmp & 0xff00) >> 8;
Pekka Enberg80767e62009-04-08 11:13:57 +0300420 }
Pekka Enberga32b9812009-04-08 11:14:04 +0300421 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
Pekka Enberg80767e62009-04-08 11:13:57 +0300422 }
Lars Lindleye5851c22010-04-02 10:57:35 +0200423 } else if (pHwData->CurrentRadioSw || pHwData->CurrentRadioHw) { /* If radio off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300424 if (reg->U1BC_LEDConfigure & 0x1010) {
Pekka Enberg80767e62009-04-08 11:13:57 +0300425 reg->U1BC_LEDConfigure &= ~0x1010;
Pekka Enberga32b9812009-04-08 11:14:04 +0300426 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
Pekka Enberg80767e62009-04-08 11:13:57 +0300427 }
Pekka Enberga32b9812009-04-08 11:14:04 +0300428 } else {
429 switch (LEDSet) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200430 case 4: /* [100] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing */
431 if (!pHwData->LED_LinkOn) { /* Blink only if not Link On */
432 /* Blinking if scanning is on progress */
Pekka Enberga32b9812009-04-08 11:14:04 +0300433 if (pHwData->LED_Scanning) {
434 if (pHwData->LED_Blinking == 0) {
Pekka Enberg80767e62009-04-08 11:13:57 +0300435 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200436 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300437 pHwData->LED_Blinking = 1;
438 TimeInterval = 300;
439 } else {
Pekka Enberg80767e62009-04-08 11:13:57 +0300440 reg->U1BC_LEDConfigure &= ~0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200441 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300442 pHwData->LED_Blinking = 0;
443 TimeInterval = 300;
444 }
445 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200446 /* Turn Off LED_0 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300447 if (reg->U1BC_LEDConfigure & 0x10) {
448 reg->U1BC_LEDConfigure &= ~0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200449 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberg80767e62009-04-08 11:13:57 +0300450 }
451 }
Pekka Enberga32b9812009-04-08 11:14:04 +0300452 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200453 /* Turn On LED_0 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300454 if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
455 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200456 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300457 }
458 }
459 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200460 case 6: /* [110] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing */
461 if (!pHwData->LED_LinkOn) { /* Blink only if not Link On */
462 /* Blinking if scanning is on progress */
Pekka Enberga32b9812009-04-08 11:14:04 +0300463 if (pHwData->LED_Scanning) {
464 if (pHwData->LED_Blinking == 0) {
465 reg->U1BC_LEDConfigure &= ~0xf;
466 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200467 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300468 pHwData->LED_Blinking = 1;
469 TimeInterval = 300;
470 } else {
471 reg->U1BC_LEDConfigure &= ~0x1f;
Lars Lindleye5851c22010-04-02 10:57:35 +0200472 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300473 pHwData->LED_Blinking = 0;
474 TimeInterval = 300;
475 }
476 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200477 /* Gray blinking if in disconnect state and not scanning */
Pekka Enberga32b9812009-04-08 11:14:04 +0300478 ltmp = reg->U1BC_LEDConfigure;
479 reg->U1BC_LEDConfigure &= ~0x1f;
Pekka Enberg833d0cd2009-04-08 11:14:06 +0300480 if (LED_GRAY2[(pHwData->LED_Blinking % 30)]) {
Pekka Enberga32b9812009-04-08 11:14:04 +0300481 reg->U1BC_LEDConfigure |= 0x10;
482 reg->U1BC_LEDConfigure |=
Pekka Enberg833d0cd2009-04-08 11:14:06 +0300483 LED_GRAY2[(pHwData->LED_Blinking % 30)];
Pekka Enberga32b9812009-04-08 11:14:04 +0300484 }
485 pHwData->LED_Blinking++;
486 if (reg->U1BC_LEDConfigure != ltmp)
Lars Lindleye5851c22010-04-02 10:57:35 +0200487 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300488 TimeInterval = 100;
489 }
490 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200491 /* Turn On LED_0 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300492 if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
493 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200494 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300495 }
496 }
497 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200498 case 5: /* [101] Only 1 Led be placed on PCB and use LED_1 for showing */
499 if (!pHwData->LED_LinkOn) { /* Blink only if not Link On */
500 /* Blinking if scanning is on progress */
Pekka Enberga32b9812009-04-08 11:14:04 +0300501 if (pHwData->LED_Scanning) {
502 if (pHwData->LED_Blinking == 0) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200503 reg->U1BC_LEDConfigure |= 0x1000;
504 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300505 pHwData->LED_Blinking = 1;
506 TimeInterval = 300;
507 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200508 reg->U1BC_LEDConfigure &= ~0x1000;
509 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300510 pHwData->LED_Blinking = 0;
511 TimeInterval = 300;
512 }
513 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200514 /* Turn Off LED_1 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300515 if (reg->U1BC_LEDConfigure & 0x1000) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200516 reg->U1BC_LEDConfigure &= ~0x1000;
517 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 Off */
Pekka Enberga32b9812009-04-08 11:14:04 +0300518 }
519 }
520 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200521 /* Is transmitting/receiving ?? */
Pekka Enberga32b9812009-04-08 11:14:04 +0300522 if ((adapter->RxByteCount !=
523 pHwData->RxByteCountLast)
524 || (adapter->TxByteCount !=
525 pHwData->TxByteCountLast)) {
526 if ((reg->U1BC_LEDConfigure & 0x3000) !=
527 0x3000) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200528 reg->U1BC_LEDConfigure |= 0x3000;
529 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300530 }
Lars Lindleye5851c22010-04-02 10:57:35 +0200531 /* Update variable */
Pekka Enberga32b9812009-04-08 11:14:04 +0300532 pHwData->RxByteCountLast =
533 adapter->RxByteCount;
534 pHwData->TxByteCountLast =
535 adapter->TxByteCount;
536 TimeInterval = 200;
537 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200538 /* Turn On LED_1 and blinking if transmitting/receiving */
Pekka Enberga32b9812009-04-08 11:14:04 +0300539 if ((reg->U1BC_LEDConfigure & 0x3000) !=
540 0x1000) {
541 reg->U1BC_LEDConfigure &=
542 ~0x3000;
543 reg->U1BC_LEDConfigure |=
544 0x1000;
Lars Lindleye5851c22010-04-02 10:57:35 +0200545 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
Pekka Enberga32b9812009-04-08 11:14:04 +0300546 }
547 }
548 }
549 break;
Lars Lindleye5851c22010-04-02 10:57:35 +0200550 default: /* Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active */
Pekka Enberga32b9812009-04-08 11:14:04 +0300551 if ((reg->U1BC_LEDConfigure & 0x3000) != 0x3000) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200552 reg->U1BC_LEDConfigure |= 0x3000; /* LED_1 is always on and event enable */
Pekka Enberga32b9812009-04-08 11:14:04 +0300553 Wb35Reg_Write(pHwData, 0x03bc,
554 reg->U1BC_LEDConfigure);
555 }
556
557 if (pHwData->LED_Blinking) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200558 /* Gray blinking */
Pekka Enberga32b9812009-04-08 11:14:04 +0300559 reg->U1BC_LEDConfigure &= ~0x0f;
560 reg->U1BC_LEDConfigure |= 0x10;
561 reg->U1BC_LEDConfigure |=
Pekka Enberg833d0cd2009-04-08 11:14:06 +0300562 LED_GRAY[(pHwData->LED_Blinking - 1) % 20];
Pekka Enberga32b9812009-04-08 11:14:04 +0300563 Wb35Reg_Write(pHwData, 0x03bc,
564 reg->U1BC_LEDConfigure);
565
566 pHwData->LED_Blinking += 2;
567 if (pHwData->LED_Blinking < 40)
568 TimeInterval = 100;
569 else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200570 pHwData->LED_Blinking = 0; /* Stop blinking */
Pekka Enberga32b9812009-04-08 11:14:04 +0300571 reg->U1BC_LEDConfigure &= ~0x0f;
572 Wb35Reg_Write(pHwData, 0x03bc,
573 reg->U1BC_LEDConfigure);
574 }
Pekka Enberg80767e62009-04-08 11:13:57 +0300575 break;
Pekka Enberga32b9812009-04-08 11:14:04 +0300576 }
577
578 if (pHwData->LED_LinkOn) {
Lars Lindleye5851c22010-04-02 10:57:35 +0200579 if (!(reg->U1BC_LEDConfigure & 0x10)) { /* Check the LED_0 */
580 /* Try to turn ON LED_0 after gray blinking */
Pekka Enberga32b9812009-04-08 11:14:04 +0300581 reg->U1BC_LEDConfigure |= 0x10;
Lars Lindleye5851c22010-04-02 10:57:35 +0200582 pHwData->LED_Blinking = 1; /* Start blinking */
Pekka Enberga32b9812009-04-08 11:14:04 +0300583 TimeInterval = 50;
584 }
585 } else {
Lars Lindleye5851c22010-04-02 10:57:35 +0200586 if (reg->U1BC_LEDConfigure & 0x10) { /* Check the LED_0 */
Pekka Enberga32b9812009-04-08 11:14:04 +0300587 reg->U1BC_LEDConfigure &= ~0x10;
588 Wb35Reg_Write(pHwData, 0x03bc,
589 reg->U1BC_LEDConfigure);
590 }
591 }
592 break;
Pekka Enberg80767e62009-04-08 11:13:57 +0300593 }
594
Lars Lindleye5851c22010-04-02 10:57:35 +0200595 /* Active send null packet to avoid AP disconnect */
Pekka Enberga32b9812009-04-08 11:14:04 +0300596 if (pHwData->LED_LinkOn) {
Pekka Enberg80767e62009-04-08 11:13:57 +0300597 pHwData->NullPacketCount += TimeInterval;
Pekka Enberga32b9812009-04-08 11:14:04 +0300598 if (pHwData->NullPacketCount >=
599 DEFAULT_NULL_PACKET_COUNT) {
Pekka Enberg80767e62009-04-08 11:13:57 +0300600 pHwData->NullPacketCount = 0;
601 }
602 }
603 }
604
605 pHwData->time_count += TimeInterval;
Lars Lindleye5851c22010-04-02 10:57:35 +0200606 Wb35Tx_CurrentTime(adapter, pHwData->time_count);
Pekka Enberg80767e62009-04-08 11:13:57 +0300607 pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(TimeInterval);
608 add_timer(&pHwData->LEDTimer);
609}
610
Pekka Enbergcfe31f82009-04-08 11:13:58 +0300611static int hal_init_hardware(struct ieee80211_hw *hw)
Pekka Enberg80767e62009-04-08 11:13:57 +0300612{
613 struct wbsoft_priv *priv = hw->priv;
Pekka Enberga32b9812009-04-08 11:14:04 +0300614 struct hw_data *pHwData = &priv->sHwData;
Pekka Enberg80767e62009-04-08 11:13:57 +0300615 u16 SoftwareSet;
616
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300617 pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME;
618 pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
Pekka Enberg80767e62009-04-08 11:13:57 +0300619
Pekka Enberg00e2e052009-04-08 11:13:59 +0300620 if (!Wb35Reg_initial(pHwData))
Pekka Enberga39ee672009-04-08 11:14:00 +0300621 goto error_reg_destroy;
Pekka Enberg80767e62009-04-08 11:13:57 +0300622
Pekka Enberg00e2e052009-04-08 11:13:59 +0300623 if (!Wb35Tx_initial(pHwData))
Pekka Enberga39ee672009-04-08 11:14:00 +0300624 goto error_tx_destroy;
Pekka Enberg80767e62009-04-08 11:13:57 +0300625
Pekka Enberg00e2e052009-04-08 11:13:59 +0300626 if (!Wb35Rx_initial(pHwData))
Pekka Enberga39ee672009-04-08 11:14:00 +0300627 goto error_rx_destroy;
Pekka Enberg80767e62009-04-08 11:13:57 +0300628
Pekka Enberg00e2e052009-04-08 11:13:59 +0300629 init_timer(&pHwData->LEDTimer);
630 pHwData->LEDTimer.function = hal_led_control;
Pekka Enberga32b9812009-04-08 11:14:04 +0300631 pHwData->LEDTimer.data = (unsigned long)priv;
Pekka Enberg00e2e052009-04-08 11:13:59 +0300632 pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(1000);
633 add_timer(&pHwData->LEDTimer);
Pekka Enberg80767e62009-04-08 11:13:57 +0300634
Pekka Enberga32b9812009-04-08 11:14:04 +0300635 SoftwareSet = hal_software_set(pHwData);
Pekka Enberg80767e62009-04-08 11:13:57 +0300636
Pekka Enberga32b9812009-04-08 11:14:04 +0300637#ifdef Vendor2
Lars Lindleye5851c22010-04-02 10:57:35 +0200638 /* Try to make sure the EEPROM contain */
Pekka Enberg00e2e052009-04-08 11:13:59 +0300639 SoftwareSet >>= 8;
Pekka Enberga32b9812009-04-08 11:14:04 +0300640 if (SoftwareSet != 0x82)
Pekka Enberg00e2e052009-04-08 11:13:59 +0300641 return false;
Pekka Enberga32b9812009-04-08 11:14:04 +0300642#endif
Pekka Enberg00e2e052009-04-08 11:13:59 +0300643
644 Wb35Rx_start(hw);
645 Wb35Tx_EP2VM_start(priv);
646
647 return 0;
648
Pekka Enberga39ee672009-04-08 11:14:00 +0300649error_rx_destroy:
650 Wb35Rx_destroy(pHwData);
651error_tx_destroy:
652 Wb35Tx_destroy(pHwData);
653error_reg_destroy:
654 Wb35Reg_destroy(pHwData);
655
Pekka Enberg80767e62009-04-08 11:13:57 +0300656 pHwData->SurpriseRemove = 1;
Pekka Enbergcfe31f82009-04-08 11:13:58 +0300657 return -EINVAL;
Pekka Enberg80767e62009-04-08 11:13:57 +0300658}
659
Pekka Enberg26598512009-04-08 11:13:56 +0300660static int wb35_hw_init(struct ieee80211_hw *hw)
Pekka Enberg912b2092008-10-30 18:12:02 +0200661{
662 struct wbsoft_priv *priv = hw->priv;
Pekka Enberga32b9812009-04-08 11:14:04 +0300663 struct hw_data *pHwData = &priv->sHwData;
664 u8 EEPROM_region;
665 u8 HwRadioOff;
666 u8 *pMacAddr2;
667 u8 *pMacAddr;
Pekka Enberg26598512009-04-08 11:13:56 +0300668 int err;
Pekka Enberg912b2092008-10-30 18:12:02 +0200669
Pekka Enberg9ca748c2009-04-08 11:14:03 +0300670 pHwData->phy_type = RF_DECIDE_BY_INF;
Pekka Enberg912b2092008-10-30 18:12:02 +0200671
Pekka Enberga32b9812009-04-08 11:14:04 +0300672 priv->Mds.TxRTSThreshold = DEFAULT_RTSThreshold;
673 priv->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
674
675 priv->sLocalPara.region_INF = REGION_AUTO;
676 priv->sLocalPara.TxRateMode = RATE_AUTO;
677 priv->sLocalPara.bMacOperationMode = MODE_802_11_BG;
678 priv->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE;
679 priv->sLocalPara.bPreambleMode = AUTO_MODE;
680 priv->sLocalPara.bWepKeyError = false;
681 priv->sLocalPara.bToSelfPacketReceived = false;
682 priv->sLocalPara.WepKeyDetectTimerCount = 2 * 100; /* 2 seconds */
683
684 priv->sLocalPara.RadioOffStatus.boSwRadioOff = false;
Pekka Enberg912b2092008-10-30 18:12:02 +0200685
Pekka Enbergcfe31f82009-04-08 11:13:58 +0300686 err = hal_init_hardware(hw);
687 if (err)
Pekka Enberg912b2092008-10-30 18:12:02 +0200688 goto error;
689
Pekka Enberga32b9812009-04-08 11:14:04 +0300690 EEPROM_region = hal_get_region_from_EEPROM(pHwData);
Pekka Enberg912b2092008-10-30 18:12:02 +0200691 if (EEPROM_region != REGION_AUTO)
692 priv->sLocalPara.region = EEPROM_region;
693 else {
694 if (priv->sLocalPara.region_INF != REGION_AUTO)
695 priv->sLocalPara.region = priv->sLocalPara.region_INF;
696 else
Pekka Enberga32b9812009-04-08 11:14:04 +0300697 priv->sLocalPara.region = REGION_USA; /* default setting */
Pekka Enberg912b2092008-10-30 18:12:02 +0200698 }
699
Pekka Enberg912b2092008-10-30 18:12:02 +0200700 Mds_initial(priv);
701
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300702 /*
703 * If no user-defined address in the registry, use the addresss
704 * "burned" on the NIC instead.
705 */
Pekka Enberg912b2092008-10-30 18:12:02 +0200706 pMacAddr = priv->sLocalPara.ThisMacAddress;
707 pMacAddr2 = priv->sLocalPara.PermanentAddress;
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300708
709 /* Reading ethernet address from EEPROM */
Pekka Enberga32b9812009-04-08 11:14:04 +0300710 hal_get_permanent_address(pHwData, priv->sLocalPara.PermanentAddress);
Pekka Enberg912b2092008-10-30 18:12:02 +0200711 if (memcmp(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) == 0)
712 memcpy(pMacAddr, pMacAddr2, MAC_ADDR_LENGTH);
713 else {
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300714 /* Set the user define MAC address */
Pekka Enberga32b9812009-04-08 11:14:04 +0300715 hal_set_ethernet_address(pHwData,
716 priv->sLocalPara.ThisMacAddress);
Pekka Enberg912b2092008-10-30 18:12:02 +0200717 }
718
Pekka Enberg912b2092008-10-30 18:12:02 +0200719 priv->sLocalPara.bAntennaNo = hal_get_antenna_number(pHwData);
720#ifdef _PE_STATE_DUMP_
Pekka Enberg0c59dba2009-01-08 11:31:59 +0200721 printk("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo);
Pekka Enberg912b2092008-10-30 18:12:02 +0200722#endif
Pekka Enberga32b9812009-04-08 11:14:04 +0300723 hal_get_hw_radio_off(pHwData);
Pekka Enberg912b2092008-10-30 18:12:02 +0200724
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300725 /* Waiting for HAL setting OK */
Pekka Enberg912b2092008-10-30 18:12:02 +0200726 while (!hal_idle(pHwData))
727 msleep(10);
728
729 MTO_Init(priv);
730
Pekka Enberga32b9812009-04-08 11:14:04 +0300731 HwRadioOff = hal_get_hw_radio_off(pHwData);
Pekka Enberg912b2092008-10-30 18:12:02 +0200732 priv->sLocalPara.RadioOffStatus.boHwRadioOff = !!HwRadioOff;
733
Pekka Enberga32b9812009-04-08 11:14:04 +0300734 hal_set_radio_mode(pHwData,
735 (unsigned char)(priv->sLocalPara.RadioOffStatus.
736 boSwRadioOff
737 || priv->sLocalPara.RadioOffStatus.
738 boHwRadioOff));
Pekka Enberg912b2092008-10-30 18:12:02 +0200739
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300740 /* Notify hal that the driver is ready now. */
741 hal_driver_init_OK(pHwData) = 1;
Pekka Enberg912b2092008-10-30 18:12:02 +0200742
743error:
Pekka Enberg26598512009-04-08 11:13:56 +0300744 return err;
Pekka Enberg912b2092008-10-30 18:12:02 +0200745}
746
Pekka Enberga32b9812009-04-08 11:14:04 +0300747static int wb35_probe(struct usb_interface *intf,
748 const struct usb_device_id *id_table)
Pavel Machek66101de2008-10-01 14:36:56 +0200749{
Pavel Machek66101de2008-10-01 14:36:56 +0200750 struct usb_device *udev = interface_to_usbdev(intf);
Pekka Enberga32b9812009-04-08 11:14:04 +0300751 struct usb_endpoint_descriptor *endpoint;
752 struct usb_host_interface *interface;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300753 struct ieee80211_hw *dev;
Pekka Enberga32b9812009-04-08 11:14:04 +0300754 struct wbsoft_priv *priv;
755 struct wb_usb *pWbUsb;
Pekka Enbergacfa5112009-01-30 11:32:47 +0200756 int nr, err;
Pekka Enberga32b9812009-04-08 11:14:04 +0300757 u32 ltmp;
Pavel Machek66101de2008-10-01 14:36:56 +0200758
759 usb_get_dev(udev);
760
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300761 /* Check the device if it already be opened */
Pekka Enberga32b9812009-04-08 11:14:04 +0300762 nr = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
763 0x01,
764 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
765 0x0, 0x400, &ltmp, 4, HZ * 100);
Pekka Enbergacfa5112009-01-30 11:32:47 +0200766 if (nr < 0) {
767 err = nr;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300768 goto error;
Pekka Enbergacfa5112009-01-30 11:32:47 +0200769 }
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300770
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300771 /* Is already initialized? */
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300772 ltmp = cpu_to_le32(ltmp);
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300773 if (ltmp) {
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300774 err = -EBUSY;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300775 goto error;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300776 }
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300777
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200778 dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
Pekka Enbergacfa5112009-01-30 11:32:47 +0200779 if (!dev) {
780 err = -ENOMEM;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300781 goto error;
Pekka Enbergacfa5112009-01-30 11:32:47 +0200782 }
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300783
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200784 priv = dev->priv;
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200785
Pekka Enberg912b2092008-10-30 18:12:02 +0200786 spin_lock_init(&priv->SpinLock);
787
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200788 pWbUsb = &priv->sHwData.WbUsb;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300789 pWbUsb->udev = udev;
790
Pekka Enberga32b9812009-04-08 11:14:04 +0300791 interface = intf->cur_altsetting;
792 endpoint = &interface->endpoint[0].desc;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300793
794 if (endpoint[2].wMaxPacketSize == 512) {
795 printk("[w35und] Working on USB 2.0\n");
796 pWbUsb->IsUsb20 = 1;
797 }
798
Pekka Enberg26598512009-04-08 11:13:56 +0300799 err = wb35_hw_init(dev);
800 if (err)
Pekka Enberg1e8a2b62008-10-30 16:14:38 +0200801 goto error_free_hw;
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300802
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300803 SET_IEEE80211_DEV(dev, &udev->dev);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300804 {
Pekka Enberga32b9812009-04-08 11:14:04 +0300805 struct hw_data *pHwData = &priv->sHwData;
806 unsigned char dev_addr[MAX_ADDR_LEN];
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300807 hal_get_permanent_address(pHwData, dev_addr);
808 SET_IEEE80211_PERM_ADDR(dev, dev_addr);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300809 }
Pavel Machek66101de2008-10-01 14:36:56 +0200810
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300811 dev->extra_tx_headroom = 12; /* FIXME */
Pavel Machek05e361c2009-01-30 10:05:25 +0100812 dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
813 dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
Pavel Machek66101de2008-10-01 14:36:56 +0200814
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300815 dev->channel_change_time = 1000;
Pavel Machek05e361c2009-01-30 10:05:25 +0100816 dev->max_signal = 100;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300817 dev->queues = 1;
818
Pekka Enberga36e0892008-10-28 00:20:03 +0200819 dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &wbsoft_band_2GHz;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300820
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300821 err = ieee80211_register_hw(dev);
822 if (err)
823 goto error_free_hw;
824
Pekka Enberg82fbb012009-04-16 14:43:14 +0300825 usb_set_intfdata(intf, dev);
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300826
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300827 return 0;
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300828
829error_free_hw:
830 ieee80211_free_hw(dev);
Pekka Enbergdc7e04f2008-10-21 12:14:58 +0300831error:
Pekka Enberg4af12e52008-10-27 23:29:31 +0200832 usb_put_dev(udev);
Pekka Enberg1523ddc2008-10-22 11:04:23 +0300833 return err;
Pavel Machek66101de2008-10-01 14:36:56 +0200834}
835
Pekka Enbergf592a852009-04-08 11:14:01 +0300836static void hal_halt(struct hw_data *pHwData)
837{
838 del_timer_sync(&pHwData->LEDTimer);
839 /* XXX: Wait for Timer DPC exit. */
840 msleep(100);
841 Wb35Rx_destroy(pHwData);
842 Wb35Tx_destroy(pHwData);
843 Wb35Reg_destroy(pHwData);
844}
845
Pekka Enberg912b2092008-10-30 18:12:02 +0200846static void wb35_hw_halt(struct wbsoft_priv *adapter)
847{
Pekka Enberga32b9812009-04-08 11:14:04 +0300848 Mds_Destroy(adapter);
Pekka Enberg912b2092008-10-30 18:12:02 +0200849
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300850 /* Turn off Rx and Tx hardware ability */
Pekka Enberga32b9812009-04-08 11:14:04 +0300851 hal_stop(&adapter->sHwData);
Pekka Enberg912b2092008-10-30 18:12:02 +0200852#ifdef _PE_USB_INI_DUMP_
Pekka Enberg0c59dba2009-01-08 11:31:59 +0200853 printk("[w35und] Hal_stop O.K.\n");
Pekka Enberg912b2092008-10-30 18:12:02 +0200854#endif
Pekka Enbergbdbb8832009-04-08 11:14:02 +0300855 /* Waiting Irp completed */
856 msleep(100);
Pekka Enberg912b2092008-10-30 18:12:02 +0200857
Pekka Enbergf592a852009-04-08 11:14:01 +0300858 hal_halt(&adapter->sHwData);
Pekka Enberg912b2092008-10-30 18:12:02 +0200859}
860
Pekka Enberg302bae82008-10-22 19:05:54 +0300861static void wb35_disconnect(struct usb_interface *intf)
Pavel Machek66101de2008-10-01 14:36:56 +0200862{
Pekka Enberg82fbb012009-04-16 14:43:14 +0300863 struct ieee80211_hw *hw = usb_get_intfdata(intf);
864 struct wbsoft_priv *priv = hw->priv;
Pavel Machek66101de2008-10-01 14:36:56 +0200865
Pekka Enberg912b2092008-10-30 18:12:02 +0200866 wb35_hw_halt(priv);
Pavel Machek66101de2008-10-01 14:36:56 +0200867
Pekka Enberg82fbb012009-04-16 14:43:14 +0300868 ieee80211_stop_queues(hw);
869 ieee80211_unregister_hw(hw);
870 ieee80211_free_hw(hw);
871
Pekka Enberg4af12e52008-10-27 23:29:31 +0200872 usb_set_intfdata(intf, NULL);
873 usb_put_dev(interface_to_usbdev(intf));
Pavel Machek66101de2008-10-01 14:36:56 +0200874}
875
Pekka Enbergdd38da42008-10-21 13:01:42 +0300876static struct usb_driver wb35_driver = {
877 .name = "w35und",
878 .id_table = wb35_table,
879 .probe = wb35_probe,
880 .disconnect = wb35_disconnect,
881};
Pavel Machek66101de2008-10-01 14:36:56 +0200882
Pekka Enbergdd38da42008-10-21 13:01:42 +0300883static int __init wb35_init(void)
884{
885 return usb_register(&wb35_driver);
886}
887
888static void __exit wb35_exit(void)
889{
890 usb_deregister(&wb35_driver);
891}
892
893module_init(wb35_init);
894module_exit(wb35_exit);