pvrusb2: reduce stack usage pvr2_eeprom_analyze()
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / winbond / wbusb.c
CommitLineData
66101de1 1/*
a2531293 2 * Copyright 2008 Pavel Machek <pavel@ucw.cz>
66101de1
PM
3 *
4 * Distribute under GPLv2.
7c49a0ac
PE
5 *
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>
66101de1 11 */
66101de1 12#include <net/mac80211.h>
80aba536 13#include <linux/usb.h>
45296236 14#include <linux/module.h>
80aba536 15
cc180710 16#include "core.h"
912b209f 17#include "mds_f.h"
64328c87 18#include "mto.h"
b5ef0761 19#include "wbhal.h"
72ca8819
PE
20#include "wb35reg_f.h"
21#include "wb35tx_f.h"
22#include "wb35rx_f.h"
66101de1 23
7b9a79bf 24MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver");
66101de1
PM
25MODULE_LICENSE("GPL");
26MODULE_VERSION("0.1");
27
43a34695 28static const struct usb_device_id wb35_table[] = {
a32b9810
PE
29 { 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) },
68ab0c96 36 { 0, }
66101de1
PM
37};
38
dd38da46 39MODULE_DEVICE_TABLE(usb, wb35_table);
66101de1 40
68ab0c96 41static struct ieee80211_rate wbsoft_rates[] = {
66101de1
PM
42 { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
43};
44
68ab0c96 45static struct ieee80211_channel wbsoft_channels[] = {
a32b9810 46 { .center_freq = 2412 },
66101de1
PM
47};
48
a36e0894
PE
49static 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
4074e77c
PE
56static 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
66101de1 69static int wbsoft_add_interface(struct ieee80211_hw *dev,
a71b676f 70 struct ieee80211_vif *vif)
66101de1 71{
4074e77c
PE
72 struct wbsoft_priv *priv = dev->priv;
73
a71b676f 74 hal_set_beacon_period(&priv->sHwData, vif->bss_conf.beacon_int);
4074e77c 75
66101de1
PM
76 return 0;
77}
78
79static void wbsoft_remove_interface(struct ieee80211_hw *dev,
a71b676f 80 struct ieee80211_vif *vif)
66101de1 81{
66101de1
PM
82}
83
68ab0c96 84static void wbsoft_stop(struct ieee80211_hw *hw)
66101de1 85{
68ab0c96
GKH
86}
87
88static int wbsoft_get_stats(struct ieee80211_hw *hw,
89 struct ieee80211_low_level_stats *stats)
90{
68ab0c96
GKH
91 return 0;
92}
93
22bedad3
JP
94static u64 wbsoft_prepare_multicast(struct ieee80211_hw *hw,
95 struct netdev_hw_addr_list *mc_list)
6d7fd647 96{
22bedad3 97 return netdev_hw_addr_list_count(mc_list);
6d7fd647
JM
98}
99
66101de1 100static void wbsoft_configure_filter(struct ieee80211_hw *dev,
a32b9810
PE
101 unsigned int changed_flags,
102 unsigned int *total_flags,
6d7fd647 103 u64 multicast)
66101de1 104{
6ab32127 105 unsigned int new_flags;
66101de1
PM
106
107 new_flags = 0;
108
6ab32127 109 if (*total_flags & FIF_PROMISC_IN_BSS)
66101de1 110 new_flags |= FIF_PROMISC_IN_BSS;
6d7fd647 111 else if ((*total_flags & FIF_ALLMULTI) || (multicast > 32))
66101de1 112 new_flags |= FIF_ALLMULTI;
66101de1
PM
113
114 dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
115
116 *total_flags = new_flags;
117}
118
36323f81
TH
119static void wbsoft_tx(struct ieee80211_hw *dev,
120 struct ieee80211_tx_control *control,
121 struct sk_buff *skb)
66101de1 122{
cc180710
PE
123 struct wbsoft_priv *priv = dev->priv;
124
11c9a55d
PE
125 if (priv->sMlmeFrame.IsInUsed != PACKET_FREE_TO_USE) {
126 priv->sMlmeFrame.wNumTxMMPDUDiscarded++;
7bb45683
JB
127 kfree_skb(skb);
128 return;
11c9a55d
PE
129 }
130
131 priv->sMlmeFrame.IsInUsed = PACKET_COME_FROM_MLME;
132
133 priv->sMlmeFrame.pMMPDU = skb->data;
134 priv->sMlmeFrame.DataType = FRAME_TYPE_802_11_MANAGEMENT;
135 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);
66101de1
PM
144}
145
66101de1
PM
146static int wbsoft_start(struct ieee80211_hw *dev)
147{
c930e0c0
PE
148 struct wbsoft_priv *priv = dev->priv;
149
150 priv->enabled = true;
151
66101de1
PM
152 return 0;
153}
154
22a82bcd
PE
155static 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
e5851c20
LL
162 if (radio_off) { /* disable Baseband receive off */
163 pHwData->CurrentRadioSw = 1; /* off */
22a82bcd
PE
164 reg->M24_MacControl &= 0xffffffbf;
165 } else {
e5851c20 166 pHwData->CurrentRadioSw = 0; /* on */
22a82bcd
PE
167 reg->M24_MacControl |= 0x00000040;
168 }
169 Wb35Reg_Write(pHwData, 0x0824, reg->M24_MacControl);
170}
171
e5851c20 172static void hal_set_current_channel_ex(struct hw_data *pHwData, struct chan_info channel)
22a82bcd
PE
173{
174 struct wb35_reg *reg = &pHwData->reg;
175
176 if (pHwData->SurpriseRemove)
177 return;
178
e5851c20 179 RFSynthesizer_SwitchingChannel(pHwData, channel); /* Switch channel */
22a82bcd
PE
180 pHwData->Channel = channel.ChanNo;
181 pHwData->band = channel.band;
e5851c20 182 reg->M28_MacControl &= ~0xff; /* Clean channel information field */
22a82bcd
PE
183 reg->M28_MacControl |= channel.ChanNo;
184 Wb35Reg_WriteWithCallbackValue(pHwData, 0x0828, reg->M28_MacControl,
e5851c20
LL
185 (s8 *) &channel,
186 sizeof(struct chan_info));
22a82bcd
PE
187}
188
440a233d 189static void hal_set_current_channel(struct hw_data *pHwData, struct chan_info channel)
22a82bcd
PE
190{
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
e5851c20 201 reg->M00_MacControl &= ~0x02000000; /* The HW value */
22a82bcd
PE
202
203 if (enable)
e5851c20 204 reg->M00_MacControl |= 0x02000000; /* The HW value */
22a82bcd
PE
205
206 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
207}
208
e5851c20 209/* For wep key error detection, we need to accept broadcast packets to be received temporary. */
22a82bcd
PE
210static 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;
e5851c20 216
22a82bcd
PE
217 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
e5851c20 233 reg->M00_MacControl &= ~0x01000000; /* The HW value */
22a82bcd 234 if (enable)
e5851c20 235 reg->M00_MacControl |= 0x01000000; /* The HW value */
22a82bcd
PE
236 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
e5851c20 246 if (!enable) /* Due to SME and MLME are not suitable for 35 */
22a82bcd
PE
247 return;
248
e5851c20 249 reg->M00_MacControl &= ~0x04000000; /* The HW value */
22a82bcd 250 if (enable)
e5851c20 251 reg->M00_MacControl |= 0x04000000; /* The HW value */
22a82bcd
PE
252
253 Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl);
254}
255
f02466fc 256static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
66101de1 257{
cc180710 258 struct wbsoft_priv *priv = dev->priv;
440a233d 259 struct chan_info ch;
f02466fc 260
bdbb8839 261 /* Should use channel_num, or something, as that is already pre-translated */
66101de1 262 ch.band = 1;
bdbb8839 263 ch.ChanNo = 1;
66101de1 264
1e8a2b60 265 hal_set_current_channel(&priv->sHwData, ch);
1e8a2b60 266 hal_set_accept_broadcast(&priv->sHwData, 1);
a32b9810
PE
267 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);
66101de1
PM
271
272 return 0;
273}
274
37a41b4a 275static u64 wbsoft_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
66101de1 276{
66101de1
PM
277 return 0;
278}
279
280static const struct ieee80211_ops wbsoft_ops = {
281 .tx = wbsoft_tx,
bdbb8839 282 .start = wbsoft_start,
68ab0c96 283 .stop = wbsoft_stop,
66101de1
PM
284 .add_interface = wbsoft_add_interface,
285 .remove_interface = wbsoft_remove_interface,
286 .config = wbsoft_config,
6d7fd647 287 .prepare_multicast = wbsoft_prepare_multicast,
66101de1 288 .configure_filter = wbsoft_configure_filter,
68ab0c96 289 .get_stats = wbsoft_get_stats,
66101de1 290 .get_tsf = wbsoft_get_tsf,
66101de1
PM
291};
292
e5851c20 293static void hal_set_ethernet_address(struct hw_data *pHwData, u8 *current_address)
22a82bcd
PE
294{
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);
e5851c20 303 ltmp[1] = cpu_to_le32(*(u32 *) (pHwData->CurrentMacAddress + 4)) & 0xffff;
22a82bcd
PE
304
305 Wb35Reg_BurstWrite(pHwData, 0x03e8, ltmp, 2, AUTO_INCREMENT);
306}
307
e5851c20 308static void hal_get_permanent_address(struct hw_data *pHwData, u8 *pethernet_address)
22a82bcd
PE
309{
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
e5851c20 326 reg->D00_DmaControl &= ~0xc0000000; /* Tx Off, Rx Off */
22a82bcd
PE
327 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;
22a82bcd 333
9be98819 334 if (!pHwData->SurpriseRemove && reg->EP0vm_state != VM_STOP)
22a82bcd
PE
335 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 */
e5851c20 351static u8 hal_get_hw_radio_off(struct hw_data *pHwData)
22a82bcd
PE
352{
353 struct wb35_reg *reg = &pHwData->reg;
354
355 if (pHwData->SurpriseRemove)
356 return 1;
357
e5851c20 358 /* read the bit16 of register U1B0 */
22a82bcd
PE
359 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
833d0cd3
PE
369static 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
80767e6e
PE
378static void hal_led_control(unsigned long data)
379{
a32b9810
PE
380 struct wbsoft_priv *adapter = (struct wbsoft_priv *)data;
381 struct hw_data *pHwData = &adapter->sHwData;
80767e6e 382 struct wb35_reg *reg = &pHwData->reg;
a32b9810 383 u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT;
a32b9810
PE
384 u32 TimeInterval = 500, ltmp, ltmp2;
385 ltmp = 0;
80767e6e 386
a32b9810
PE
387 if (pHwData->SurpriseRemove)
388 return;
80767e6e 389
a32b9810 390 if (pHwData->LED_control) {
80767e6e 391 ltmp2 = pHwData->LED_control & 0xff;
e5851c20 392 if (ltmp2 == 5) { /* 5 is WPS mode */
80767e6e 393 TimeInterval = 100;
a32b9810
PE
394 ltmp2 = (pHwData->LED_control >> 8) & 0xff;
395 switch (ltmp2) {
e5851c20 396 case 1: /* [0.2 On][0.1 Off]... */
a32b9810 397 pHwData->LED_Blinking %= 3;
e5851c20
LL
398 ltmp = 0x1010; /* Led 1 & 0 Green and Red */
399 if (pHwData->LED_Blinking == 2) /* Turn off */
a32b9810
PE
400 ltmp = 0;
401 break;
e5851c20 402 case 2: /* [0.1 On][0.1 Off]... */
a32b9810 403 pHwData->LED_Blinking %= 2;
e5851c20
LL
404 ltmp = 0x0010; /* Led 0 red color */
405 if (pHwData->LED_Blinking) /* Turn off */
a32b9810
PE
406 ltmp = 0;
407 break;
e5851c20 408 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]... */
a32b9810 409 pHwData->LED_Blinking %= 15;
e5851c20
LL
410 ltmp = 0x0010; /* Led 0 red color */
411 if ((pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking % 2)) /* Turn off 0.6 sec */
a32b9810
PE
412 ltmp = 0;
413 break;
e5851c20
LL
414 case 4: /* [300 On][ off ] */
415 ltmp = 0x1000; /* Led 1 Green color */
a32b9810 416 if (pHwData->LED_Blinking >= 3000)
e5851c20 417 ltmp = 0; /* led maybe on after 300sec * 32bit counter overlap. */
a32b9810 418 break;
80767e6e
PE
419 }
420 pHwData->LED_Blinking++;
421
422 reg->U1BC_LEDConfigure = ltmp;
e5851c20
LL
423 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 */
a32b9810 425 reg->U1BC_LEDConfigure |= (ltmp & 0xff00) >> 8;
80767e6e 426 }
a32b9810 427 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
80767e6e 428 }
e5851c20 429 } else if (pHwData->CurrentRadioSw || pHwData->CurrentRadioHw) { /* If radio off */
a32b9810 430 if (reg->U1BC_LEDConfigure & 0x1010) {
80767e6e 431 reg->U1BC_LEDConfigure &= ~0x1010;
a32b9810 432 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
80767e6e 433 }
a32b9810
PE
434 } else {
435 switch (LEDSet) {
e5851c20
LL
436 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 */
a32b9810
PE
439 if (pHwData->LED_Scanning) {
440 if (pHwData->LED_Blinking == 0) {
441 reg->U1BC_LEDConfigure |= 0x10;
e5851c20 442 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 On */
a32b9810
PE
443 pHwData->LED_Blinking = 1;
444 TimeInterval = 300;
445 } else {
446 reg->U1BC_LEDConfigure &= ~0x10;
e5851c20 447 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
a32b9810
PE
448 pHwData->LED_Blinking = 0;
449 TimeInterval = 300;
80767e6e 450 }
a32b9810 451 } else {
e5851c20 452 /* Turn Off LED_0 */
a32b9810
PE
453 if (reg->U1BC_LEDConfigure & 0x10) {
454 reg->U1BC_LEDConfigure &= ~0x10;
e5851c20 455 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
80767e6e
PE
456 }
457 }
a32b9810 458 } else {
e5851c20 459 /* Turn On LED_0 */
a32b9810
PE
460 if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
461 reg->U1BC_LEDConfigure |= 0x10;
e5851c20 462 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
80767e6e 463 }
a32b9810
PE
464 }
465 break;
e5851c20
LL
466 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 */
a32b9810
PE
469 if (pHwData->LED_Scanning) {
470 if (pHwData->LED_Blinking == 0) {
471 reg->U1BC_LEDConfigure &= ~0xf;
472 reg->U1BC_LEDConfigure |= 0x10;
e5851c20 473 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 On */
a32b9810
PE
474 pHwData->LED_Blinking = 1;
475 TimeInterval = 300;
476 } else {
80767e6e 477 reg->U1BC_LEDConfigure &= ~0x1f;
e5851c20 478 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
a32b9810
PE
479 pHwData->LED_Blinking = 0;
480 TimeInterval = 300;
80767e6e 481 }
a32b9810 482 } else {
e5851c20 483 /* Gray blinking if in disconnect state and not scanning */
a32b9810
PE
484 ltmp = reg->U1BC_LEDConfigure;
485 reg->U1BC_LEDConfigure &= ~0x1f;
833d0cd3 486 if (LED_GRAY2[(pHwData->LED_Blinking % 30)]) {
80767e6e 487 reg->U1BC_LEDConfigure |= 0x10;
a32b9810 488 reg->U1BC_LEDConfigure |=
833d0cd3 489 LED_GRAY2[(pHwData->LED_Blinking % 30)];
80767e6e 490 }
a32b9810
PE
491 pHwData->LED_Blinking++;
492 if (reg->U1BC_LEDConfigure != ltmp)
e5851c20 493 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
a32b9810 494 TimeInterval = 100;
80767e6e 495 }
a32b9810 496 } else {
e5851c20 497 /* Turn On LED_0 */
a32b9810
PE
498 if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
499 reg->U1BC_LEDConfigure |= 0x10;
e5851c20 500 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_0 Off */
a32b9810
PE
501 }
502 }
503 break;
e5851c20
LL
504 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 */
a32b9810
PE
507 if (pHwData->LED_Scanning) {
508 if (pHwData->LED_Blinking == 0) {
e5851c20
LL
509 reg->U1BC_LEDConfigure |= 0x1000;
510 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
a32b9810
PE
511 pHwData->LED_Blinking = 1;
512 TimeInterval = 300;
513 } else {
e5851c20
LL
514 reg->U1BC_LEDConfigure &= ~0x1000;
515 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 Off */
a32b9810
PE
516 pHwData->LED_Blinking = 0;
517 TimeInterval = 300;
80767e6e 518 }
a32b9810 519 } else {
e5851c20 520 /* Turn Off LED_1 */
a32b9810 521 if (reg->U1BC_LEDConfigure & 0x1000) {
e5851c20
LL
522 reg->U1BC_LEDConfigure &= ~0x1000;
523 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 Off */
80767e6e
PE
524 }
525 }
a32b9810 526 } else {
e5851c20 527 /* Is transmitting/receiving ?? */
a32b9810
PE
528 if ((adapter->RxByteCount !=
529 pHwData->RxByteCountLast)
530 || (adapter->TxByteCount !=
531 pHwData->TxByteCountLast)) {
532 if ((reg->U1BC_LEDConfigure & 0x3000) !=
533 0x3000) {
e5851c20
LL
534 reg->U1BC_LEDConfigure |= 0x3000;
535 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
80767e6e 536 }
e5851c20 537 /* Update variable */
a32b9810
PE
538 pHwData->RxByteCountLast =
539 adapter->RxByteCount;
540 pHwData->TxByteCountLast =
541 adapter->TxByteCount;
542 TimeInterval = 200;
543 } else {
e5851c20 544 /* Turn On LED_1 and blinking if transmitting/receiving */
a32b9810
PE
545 if ((reg->U1BC_LEDConfigure & 0x3000) !=
546 0x1000) {
547 reg->U1BC_LEDConfigure &=
548 ~0x3000;
549 reg->U1BC_LEDConfigure |=
550 0x1000;
e5851c20 551 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); /* LED_1 On */
80767e6e
PE
552 }
553 }
a32b9810
PE
554 }
555 break;
e5851c20 556 default: /* Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active */
a32b9810 557 if ((reg->U1BC_LEDConfigure & 0x3000) != 0x3000) {
e5851c20 558 reg->U1BC_LEDConfigure |= 0x3000; /* LED_1 is always on and event enable */
a32b9810
PE
559 Wb35Reg_Write(pHwData, 0x03bc,
560 reg->U1BC_LEDConfigure);
561 }
80767e6e 562
a32b9810 563 if (pHwData->LED_Blinking) {
e5851c20 564 /* Gray blinking */
a32b9810
PE
565 reg->U1BC_LEDConfigure &= ~0x0f;
566 reg->U1BC_LEDConfigure |= 0x10;
567 reg->U1BC_LEDConfigure |=
833d0cd3 568 LED_GRAY[(pHwData->LED_Blinking - 1) % 20];
a32b9810
PE
569 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 {
e5851c20 576 pHwData->LED_Blinking = 0; /* Stop blinking */
80767e6e 577 reg->U1BC_LEDConfigure &= ~0x0f;
a32b9810
PE
578 Wb35Reg_Write(pHwData, 0x03bc,
579 reg->U1BC_LEDConfigure);
80767e6e 580 }
a32b9810
PE
581 break;
582 }
80767e6e 583
a32b9810 584 if (pHwData->LED_LinkOn) {
e5851c20
LL
585 if (!(reg->U1BC_LEDConfigure & 0x10)) { /* Check the LED_0 */
586 /* Try to turn ON LED_0 after gray blinking */
a32b9810 587 reg->U1BC_LEDConfigure |= 0x10;
e5851c20 588 pHwData->LED_Blinking = 1; /* Start blinking */
a32b9810 589 TimeInterval = 50;
80767e6e 590 }
a32b9810 591 } else {
e5851c20 592 if (reg->U1BC_LEDConfigure & 0x10) { /* Check the LED_0 */
a32b9810
PE
593 reg->U1BC_LEDConfigure &= ~0x10;
594 Wb35Reg_Write(pHwData, 0x03bc,
595 reg->U1BC_LEDConfigure);
80767e6e 596 }
a32b9810
PE
597 }
598 break;
80767e6e 599 }
80767e6e
PE
600 }
601
602 pHwData->time_count += TimeInterval;
e5851c20 603 Wb35Tx_CurrentTime(adapter, pHwData->time_count);
80767e6e
PE
604 pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(TimeInterval);
605 add_timer(&pHwData->LEDTimer);
606}
607
cfe31f81 608static int hal_init_hardware(struct ieee80211_hw *hw)
80767e6e
PE
609{
610 struct wbsoft_priv *priv = hw->priv;
a32b9810 611 struct hw_data *pHwData = &priv->sHwData;
80767e6e
PE
612 u16 SoftwareSet;
613
bdbb8839
PE
614 pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME;
615 pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
80767e6e 616
00e2e05d 617 if (!Wb35Reg_initial(pHwData))
a39ee671 618 goto error_reg_destroy;
00e2e05d 619
00e2e05d 620 if (!Wb35Tx_initial(pHwData))
a39ee671 621 goto error_tx_destroy;
00e2e05d 622
00e2e05d 623 if (!Wb35Rx_initial(pHwData))
a39ee671 624 goto error_rx_destroy;
00e2e05d 625
00e2e05d
PE
626 init_timer(&pHwData->LEDTimer);
627 pHwData->LEDTimer.function = hal_led_control;
a32b9810 628 pHwData->LEDTimer.data = (unsigned long)priv;
00e2e05d
PE
629 pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(1000);
630 add_timer(&pHwData->LEDTimer);
631
a32b9810 632 SoftwareSet = hal_software_set(pHwData);
00e2e05d 633
00e2e05d
PE
634 Wb35Rx_start(hw);
635 Wb35Tx_EP2VM_start(priv);
636
637 return 0;
80767e6e 638
a39ee671
PE
639error_rx_destroy:
640 Wb35Rx_destroy(pHwData);
641error_tx_destroy:
642 Wb35Tx_destroy(pHwData);
643error_reg_destroy:
644 Wb35Reg_destroy(pHwData);
645
80767e6e 646 pHwData->SurpriseRemove = 1;
cfe31f81 647 return -EINVAL;
80767e6e
PE
648}
649
26598511 650static int wb35_hw_init(struct ieee80211_hw *hw)
912b209f
PE
651{
652 struct wbsoft_priv *priv = hw->priv;
a32b9810
PE
653 struct hw_data *pHwData = &priv->sHwData;
654 u8 EEPROM_region;
655 u8 HwRadioOff;
656 u8 *pMacAddr2;
657 u8 *pMacAddr;
26598511 658 int err;
912b209f 659
9ca748ce 660 pHwData->phy_type = RF_DECIDE_BY_INF;
912b209f 661
a32b9810
PE
662 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;
912b209f 675
cfe31f81
PE
676 err = hal_init_hardware(hw);
677 if (err)
912b209f
PE
678 goto error;
679
a32b9810 680 EEPROM_region = hal_get_region_from_EEPROM(pHwData);
912b209f
PE
681 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
a32b9810 687 priv->sLocalPara.region = REGION_USA; /* default setting */
912b209f
PE
688 }
689
912b209f
PE
690 Mds_initial(priv);
691
bdbb8839 692 /*
f69b0d64 693 * If no user-defined address in the registry, use the address
bdbb8839
PE
694 * "burned" on the NIC instead.
695 */
912b209f
PE
696 pMacAddr = priv->sLocalPara.ThisMacAddress;
697 pMacAddr2 = priv->sLocalPara.PermanentAddress;
bdbb8839
PE
698
699 /* Reading ethernet address from EEPROM */
a32b9810 700 hal_get_permanent_address(pHwData, priv->sLocalPara.PermanentAddress);
912b209f
PE
701 if (memcmp(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) == 0)
702 memcpy(pMacAddr, pMacAddr2, MAC_ADDR_LENGTH);
703 else {
bdbb8839 704 /* Set the user define MAC address */
a32b9810
PE
705 hal_set_ethernet_address(pHwData,
706 priv->sLocalPara.ThisMacAddress);
912b209f
PE
707 }
708
912b209f 709 priv->sLocalPara.bAntennaNo = hal_get_antenna_number(pHwData);
a32b9810 710 hal_get_hw_radio_off(pHwData);
912b209f 711
bdbb8839 712 /* Waiting for HAL setting OK */
912b209f
PE
713 while (!hal_idle(pHwData))
714 msleep(10);
715
716 MTO_Init(priv);
717
a32b9810 718 HwRadioOff = hal_get_hw_radio_off(pHwData);
912b209f
PE
719 priv->sLocalPara.RadioOffStatus.boHwRadioOff = !!HwRadioOff;
720
a32b9810
PE
721 hal_set_radio_mode(pHwData,
722 (unsigned char)(priv->sLocalPara.RadioOffStatus.
723 boSwRadioOff
724 || priv->sLocalPara.RadioOffStatus.
725 boHwRadioOff));
912b209f 726
bdbb8839
PE
727 /* Notify hal that the driver is ready now. */
728 hal_driver_init_OK(pHwData) = 1;
912b209f
PE
729
730error:
26598511 731 return err;
912b209f
PE
732}
733
a32b9810
PE
734static int wb35_probe(struct usb_interface *intf,
735 const struct usb_device_id *id_table)
66101de1 736{
66101de1 737 struct usb_device *udev = interface_to_usbdev(intf);
a32b9810
PE
738 struct usb_endpoint_descriptor *endpoint;
739 struct usb_host_interface *interface;
1523ddc4 740 struct ieee80211_hw *dev;
a32b9810 741 struct wbsoft_priv *priv;
6594ac5d 742 int err;
a32b9810 743 u32 ltmp;
66101de1
PM
744
745 usb_get_dev(udev);
746
bdbb8839 747 /* Check the device if it already be opened */
6594ac5d 748 err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
a32b9810
PE
749 0x01,
750 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
751 0x0, 0x400, &ltmp, 4, HZ * 100);
6594ac5d 752 if (err < 0)
dc7e04fe 753 goto error;
66101de1 754
bdbb8839 755 /* Is already initialized? */
dc7e04fe 756 ltmp = cpu_to_le32(ltmp);
bdbb8839 757 if (ltmp) {
1523ddc4 758 err = -EBUSY;
dc7e04fe 759 goto error;
1523ddc4 760 }
66101de1 761
1e8a2b60 762 dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
acfa5110
PE
763 if (!dev) {
764 err = -ENOMEM;
1523ddc4 765 goto error;
acfa5110 766 }
66101de1 767
1e8a2b60 768 priv = dev->priv;
1e8a2b60 769
2894c6cd 770 priv->sHwData.udev = udev;
66101de1 771
a32b9810
PE
772 interface = intf->cur_altsetting;
773 endpoint = &interface->endpoint[0].desc;
66101de1 774
26598511
PE
775 err = wb35_hw_init(dev);
776 if (err)
1e8a2b60 777 goto error_free_hw;
66101de1 778
1523ddc4
PE
779 SET_IEEE80211_DEV(dev, &udev->dev);
780 {
a32b9810
PE
781 struct hw_data *pHwData = &priv->sHwData;
782 unsigned char dev_addr[MAX_ADDR_LEN];
1523ddc4
PE
783 hal_get_permanent_address(pHwData, dev_addr);
784 SET_IEEE80211_PERM_ADDR(dev, dev_addr);
785 }
66101de1 786
1523ddc4 787 dev->extra_tx_headroom = 12; /* FIXME */
05e361ca
PM
788 dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
789 dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
66101de1 790
1523ddc4 791 dev->channel_change_time = 1000;
05e361ca 792 dev->max_signal = 100;
1523ddc4 793 dev->queues = 1;
dc7e04fe 794
a36e0894 795 dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &wbsoft_band_2GHz;
66101de1 796
1523ddc4
PE
797 err = ieee80211_register_hw(dev);
798 if (err)
799 goto error_free_hw;
66101de1 800
82fbb01c 801 usb_set_intfdata(intf, dev);
66101de1 802
dc7e04fe 803 return 0;
1523ddc4
PE
804
805error_free_hw:
806 ieee80211_free_hw(dev);
dc7e04fe 807error:
4af12e55 808 usb_put_dev(udev);
1523ddc4 809 return err;
66101de1
PM
810}
811
f592a859
PE
812static void hal_halt(struct hw_data *pHwData)
813{
814 del_timer_sync(&pHwData->LEDTimer);
815 /* XXX: Wait for Timer DPC exit. */
816 msleep(100);
817 Wb35Rx_destroy(pHwData);
818 Wb35Tx_destroy(pHwData);
819 Wb35Reg_destroy(pHwData);
820}
821
912b209f
PE
822static void wb35_hw_halt(struct wbsoft_priv *adapter)
823{
bdbb8839 824 /* Turn off Rx and Tx hardware ability */
a32b9810 825 hal_stop(&adapter->sHwData);
bdbb8839
PE
826 /* Waiting Irp completed */
827 msleep(100);
912b209f 828
f592a859 829 hal_halt(&adapter->sHwData);
912b209f
PE
830}
831
302bae85 832static void wb35_disconnect(struct usb_interface *intf)
66101de1 833{
82fbb01c
PE
834 struct ieee80211_hw *hw = usb_get_intfdata(intf);
835 struct wbsoft_priv *priv = hw->priv;
66101de1 836
912b209f 837 wb35_hw_halt(priv);
66101de1 838
82fbb01c
PE
839 ieee80211_stop_queues(hw);
840 ieee80211_unregister_hw(hw);
841 ieee80211_free_hw(hw);
842
4af12e55
PE
843 usb_set_intfdata(intf, NULL);
844 usb_put_dev(interface_to_usbdev(intf));
66101de1
PM
845}
846
dd38da46
PE
847static struct usb_driver wb35_driver = {
848 .name = "w35und",
849 .id_table = wb35_table,
850 .probe = wb35_probe,
851 .disconnect = wb35_disconnect,
852};
853
bac2c126 854module_usb_driver(wb35_driver);