]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/winbond/wbusb.c
Staging: w35und: make led lookup tables static
[karo-tx-linux.git] / drivers / staging / winbond / wbusb.c
1 /*
2  * Copyright 2008 Pavel Machek <pavel@suse.cz>
3  *
4  * Distribute under GPLv2.
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>
11  */
12 #include <net/mac80211.h>
13 #include <linux/usb.h>
14
15 #include "core.h"
16 #include "mds_f.h"
17 #include "mlmetxrx_f.h"
18 #include "mto.h"
19 #include "wbhal_f.h"
20 #include "wblinux_f.h"
21
22 MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver");
23 MODULE_LICENSE("GPL");
24 MODULE_VERSION("0.1");
25
26 static struct usb_device_id wb35_table[] __devinitdata = {
27         { 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) },
34         { 0, }
35 };
36
37 MODULE_DEVICE_TABLE(usb, wb35_table);
38
39 static struct ieee80211_rate wbsoft_rates[] = {
40         { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
41 };
42
43 static struct ieee80211_channel wbsoft_channels[] = {
44         { .center_freq = 2412 },
45 };
46
47 static 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
54 static int wbsoft_add_interface(struct ieee80211_hw *dev,
55                                 struct ieee80211_if_init_conf *conf)
56 {
57         printk("wbsoft_add interface called\n");
58         return 0;
59 }
60
61 static void wbsoft_remove_interface(struct ieee80211_hw *dev,
62                                     struct ieee80211_if_init_conf *conf)
63 {
64         printk("wbsoft_remove interface called\n");
65 }
66
67 static void wbsoft_stop(struct ieee80211_hw *hw)
68 {
69         printk(KERN_INFO "%s called\n", __func__);
70 }
71
72 static int wbsoft_get_stats(struct ieee80211_hw *hw,
73                             struct ieee80211_low_level_stats *stats)
74 {
75         printk(KERN_INFO "%s called\n", __func__);
76         return 0;
77 }
78
79 static int wbsoft_get_tx_stats(struct ieee80211_hw *hw,
80                                struct ieee80211_tx_queue_stats *stats)
81 {
82         printk(KERN_INFO "%s called\n", __func__);
83         return 0;
84 }
85
86 static void wbsoft_configure_filter(struct ieee80211_hw *dev,
87                                     unsigned int changed_flags,
88                                     unsigned int *total_flags,
89                                     int mc_count, struct dev_mc_list *mclist)
90 {
91         unsigned int new_flags;
92
93         new_flags = 0;
94
95         if (*total_flags & FIF_PROMISC_IN_BSS)
96                 new_flags |= FIF_PROMISC_IN_BSS;
97         else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32))
98                 new_flags |= FIF_ALLMULTI;
99
100         dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
101
102         *total_flags = new_flags;
103 }
104
105 static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
106 {
107         struct wbsoft_priv *priv = dev->priv;
108
109         MLMESendFrame(priv, skb->data, skb->len, FRAME_TYPE_802_11_MANAGEMENT);
110
111         return NETDEV_TX_OK;
112 }
113
114 static int wbsoft_start(struct ieee80211_hw *dev)
115 {
116         struct wbsoft_priv *priv = dev->priv;
117
118         priv->enabled = true;
119
120         return 0;
121 }
122
123 static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
124 {
125         struct wbsoft_priv *priv = dev->priv;
126         struct ieee80211_conf *conf = &dev->conf;
127         ChanInfo ch;
128
129         printk("wbsoft_config called\n");
130
131         /* Should use channel_num, or something, as that is already pre-translated */
132         ch.band = 1;
133         ch.ChanNo = 1;
134
135         hal_set_current_channel(&priv->sHwData, ch);
136         hal_set_beacon_period(&priv->sHwData, conf->beacon_int);
137         hal_set_accept_broadcast(&priv->sHwData, 1);
138         hal_set_accept_promiscuous(&priv->sHwData, 1);
139         hal_set_accept_multicast(&priv->sHwData, 1);
140         hal_set_accept_beacon(&priv->sHwData, 1);
141         hal_set_radio_mode(&priv->sHwData, 0);
142
143         return 0;
144 }
145
146 static int wbsoft_config_interface(struct ieee80211_hw *dev,
147                                    struct ieee80211_vif *vif,
148                                    struct ieee80211_if_conf *conf)
149 {
150         printk("wbsoft_config_interface called\n");
151         return 0;
152 }
153
154 static u64 wbsoft_get_tsf(struct ieee80211_hw *dev)
155 {
156         printk("wbsoft_get_tsf called\n");
157         return 0;
158 }
159
160 static const struct ieee80211_ops wbsoft_ops = {
161         .tx                     = wbsoft_tx,
162         .start                  = wbsoft_start,
163         .stop                   = wbsoft_stop,
164         .add_interface          = wbsoft_add_interface,
165         .remove_interface       = wbsoft_remove_interface,
166         .config                 = wbsoft_config,
167         .config_interface       = wbsoft_config_interface,
168         .configure_filter       = wbsoft_configure_filter,
169         .get_stats              = wbsoft_get_stats,
170         .get_tx_stats           = wbsoft_get_tx_stats,
171         .get_tsf                = wbsoft_get_tsf,
172 };
173
174 static u8 LED_GRAY[20] = {
175         0, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 14, 13, 12, 11, 10, 8, 6, 4, 2
176 };
177
178 static u8 LED_GRAY2[30] = {
179         7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
180         0, 15, 14, 13, 12, 11, 10, 9, 8
181 };
182
183 static void hal_led_control(unsigned long data)
184 {
185         struct wbsoft_priv *adapter = (struct wbsoft_priv *)data;
186         struct hw_data *pHwData = &adapter->sHwData;
187         struct wb35_reg *reg = &pHwData->reg;
188         u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT;
189         u32 TimeInterval = 500, ltmp, ltmp2;
190         ltmp = 0;
191
192         if (pHwData->SurpriseRemove)
193                 return;
194
195         if (pHwData->LED_control) {
196                 ltmp2 = pHwData->LED_control & 0xff;
197                 if (ltmp2 == 5) // 5 is WPS mode
198                 {
199                         TimeInterval = 100;
200                         ltmp2 = (pHwData->LED_control >> 8) & 0xff;
201                         switch (ltmp2) {
202                         case 1: // [0.2 On][0.1 Off]...
203                                 pHwData->LED_Blinking %= 3;
204                                 ltmp = 0x1010;  // Led 1 & 0 Green and Red
205                                 if (pHwData->LED_Blinking == 2) // Turn off
206                                         ltmp = 0;
207                                 break;
208                         case 2: // [0.1 On][0.1 Off]...
209                                 pHwData->LED_Blinking %= 2;
210                                 ltmp = 0x0010;  // Led 0 red color
211                                 if (pHwData->LED_Blinking)      // Turn off
212                                         ltmp = 0;
213                                 break;
214                         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]...
215                                 pHwData->LED_Blinking %= 15;
216                                 ltmp = 0x0010;  // Led 0 red color
217                                 if ((pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking % 2))        // Turn off 0.6 sec
218                                         ltmp = 0;
219                                 break;
220                         case 4: // [300 On][ off ]
221                                 ltmp = 0x1000;  // Led 1 Green color
222                                 if (pHwData->LED_Blinking >= 3000)
223                                         ltmp = 0;       // led maybe on after 300sec * 32bit counter overlap.
224                                 break;
225                         }
226                         pHwData->LED_Blinking++;
227
228                         reg->U1BC_LEDConfigure = ltmp;
229                         if (LEDSet != 7)        // Only 111 mode has 2 LEDs on PCB.
230                         {
231                                 reg->U1BC_LEDConfigure |= (ltmp & 0xff) << 8;   // Copy LED result to each LED control register
232                                 reg->U1BC_LEDConfigure |= (ltmp & 0xff00) >> 8;
233                         }
234                         Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
235                 }
236         } else if (pHwData->CurrentRadioSw || pHwData->CurrentRadioHw)  // If radio off
237         {
238                 if (reg->U1BC_LEDConfigure & 0x1010) {
239                         reg->U1BC_LEDConfigure &= ~0x1010;
240                         Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure);
241                 }
242         } else {
243                 switch (LEDSet) {
244                 case 4: // [100] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing
245                         if (!pHwData->LED_LinkOn)       // Blink only if not Link On
246                         {
247                                 // Blinking if scanning is on progress
248                                 if (pHwData->LED_Scanning) {
249                                         if (pHwData->LED_Blinking == 0) {
250                                                 reg->U1BC_LEDConfigure |= 0x10;
251                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 On
252                                                 pHwData->LED_Blinking = 1;
253                                                 TimeInterval = 300;
254                                         } else {
255                                                 reg->U1BC_LEDConfigure &= ~0x10;
256                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off
257                                                 pHwData->LED_Blinking = 0;
258                                                 TimeInterval = 300;
259                                         }
260                                 } else {
261                                         //Turn Off LED_0
262                                         if (reg->U1BC_LEDConfigure & 0x10) {
263                                                 reg->U1BC_LEDConfigure &= ~0x10;
264                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off
265                                         }
266                                 }
267                         } else {
268                                 // Turn On LED_0
269                                 if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
270                                         reg->U1BC_LEDConfigure |= 0x10;
271                                         Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off
272                                 }
273                         }
274                         break;
275
276                 case 6: // [110] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing
277                         if (!pHwData->LED_LinkOn)       // Blink only if not Link On
278                         {
279                                 // Blinking if scanning is on progress
280                                 if (pHwData->LED_Scanning) {
281                                         if (pHwData->LED_Blinking == 0) {
282                                                 reg->U1BC_LEDConfigure &= ~0xf;
283                                                 reg->U1BC_LEDConfigure |= 0x10;
284                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 On
285                                                 pHwData->LED_Blinking = 1;
286                                                 TimeInterval = 300;
287                                         } else {
288                                                 reg->U1BC_LEDConfigure &= ~0x1f;
289                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off
290                                                 pHwData->LED_Blinking = 0;
291                                                 TimeInterval = 300;
292                                         }
293                                 } else {
294                                         // 20060901 Gray blinking if in disconnect state and not scanning
295                                         ltmp = reg->U1BC_LEDConfigure;
296                                         reg->U1BC_LEDConfigure &= ~0x1f;
297                                         if (LED_GRAY2[(pHwData->LED_Blinking % 30)]) {
298                                                 reg->U1BC_LEDConfigure |= 0x10;
299                                                 reg->U1BC_LEDConfigure |=
300                                                     LED_GRAY2[(pHwData->LED_Blinking % 30)];
301                                         }
302                                         pHwData->LED_Blinking++;
303                                         if (reg->U1BC_LEDConfigure != ltmp)
304                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off
305                                         TimeInterval = 100;
306                                 }
307                         } else {
308                                 // Turn On LED_0
309                                 if ((reg->U1BC_LEDConfigure & 0x10) == 0) {
310                                         reg->U1BC_LEDConfigure |= 0x10;
311                                         Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off
312                                 }
313                         }
314                         break;
315
316                 case 5: // [101] Only 1 Led be placed on PCB and use LED_1 for showing
317                         if (!pHwData->LED_LinkOn)       // Blink only if not Link On
318                         {
319                                 // Blinking if scanning is on progress
320                                 if (pHwData->LED_Scanning) {
321                                         if (pHwData->LED_Blinking == 0) {
322                                                 reg->U1BC_LEDConfigure |=
323                                                     0x1000;
324                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 On
325                                                 pHwData->LED_Blinking = 1;
326                                                 TimeInterval = 300;
327                                         } else {
328                                                 reg->U1BC_LEDConfigure &=
329                                                     ~0x1000;
330                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 Off
331                                                 pHwData->LED_Blinking = 0;
332                                                 TimeInterval = 300;
333                                         }
334                                 } else {
335                                         //Turn Off LED_1
336                                         if (reg->U1BC_LEDConfigure & 0x1000) {
337                                                 reg->U1BC_LEDConfigure &=
338                                                     ~0x1000;
339                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 Off
340                                         }
341                                 }
342                         } else {
343                                 // Is transmitting/receiving ??
344                                 if ((adapter->RxByteCount !=
345                                      pHwData->RxByteCountLast)
346                                     || (adapter->TxByteCount !=
347                                         pHwData->TxByteCountLast)) {
348                                         if ((reg->U1BC_LEDConfigure & 0x3000) !=
349                                             0x3000) {
350                                                 reg->U1BC_LEDConfigure |=
351                                                     0x3000;
352                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 On
353                                         }
354                                         // Update variable
355                                         pHwData->RxByteCountLast =
356                                             adapter->RxByteCount;
357                                         pHwData->TxByteCountLast =
358                                             adapter->TxByteCount;
359                                         TimeInterval = 200;
360                                 } else {
361                                         // Turn On LED_1 and blinking if transmitting/receiving
362                                         if ((reg->U1BC_LEDConfigure & 0x3000) !=
363                                             0x1000) {
364                                                 reg->U1BC_LEDConfigure &=
365                                                     ~0x3000;
366                                                 reg->U1BC_LEDConfigure |=
367                                                     0x1000;
368                                                 Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 On
369                                         }
370                                 }
371                         }
372                         break;
373
374                 default:        // Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active
375                         if ((reg->U1BC_LEDConfigure & 0x3000) != 0x3000) {
376                                 reg->U1BC_LEDConfigure |= 0x3000;       // LED_1 is always on and event enable
377                                 Wb35Reg_Write(pHwData, 0x03bc,
378                                               reg->U1BC_LEDConfigure);
379                         }
380
381                         if (pHwData->LED_Blinking) {
382                                 // Gray blinking
383                                 reg->U1BC_LEDConfigure &= ~0x0f;
384                                 reg->U1BC_LEDConfigure |= 0x10;
385                                 reg->U1BC_LEDConfigure |=
386                                     LED_GRAY[(pHwData->LED_Blinking - 1) % 20];
387                                 Wb35Reg_Write(pHwData, 0x03bc,
388                                               reg->U1BC_LEDConfigure);
389
390                                 pHwData->LED_Blinking += 2;
391                                 if (pHwData->LED_Blinking < 40)
392                                         TimeInterval = 100;
393                                 else {
394                                         pHwData->LED_Blinking = 0;      // Stop blinking
395                                         reg->U1BC_LEDConfigure &= ~0x0f;
396                                         Wb35Reg_Write(pHwData, 0x03bc,
397                                                       reg->U1BC_LEDConfigure);
398                                 }
399                                 break;
400                         }
401
402                         if (pHwData->LED_LinkOn) {
403                                 if (!(reg->U1BC_LEDConfigure & 0x10))   // Check the LED_0
404                                 {
405                                         //Try to turn ON LED_0 after gray blinking
406                                         reg->U1BC_LEDConfigure |= 0x10;
407                                         pHwData->LED_Blinking = 1;      //Start blinking
408                                         TimeInterval = 50;
409                                 }
410                         } else {
411                                 if (reg->U1BC_LEDConfigure & 0x10)      // Check the LED_0
412                                 {
413                                         reg->U1BC_LEDConfigure &= ~0x10;
414                                         Wb35Reg_Write(pHwData, 0x03bc,
415                                                       reg->U1BC_LEDConfigure);
416                                 }
417                         }
418                         break;
419                 }
420
421                 //20060828.1 Active send null packet to avoid AP disconnect
422                 if (pHwData->LED_LinkOn) {
423                         pHwData->NullPacketCount += TimeInterval;
424                         if (pHwData->NullPacketCount >=
425                             DEFAULT_NULL_PACKET_COUNT) {
426                                 pHwData->NullPacketCount = 0;
427                         }
428                 }
429         }
430
431         pHwData->time_count += TimeInterval;
432         Wb35Tx_CurrentTime(adapter, pHwData->time_count);       // 20060928 add
433         pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(TimeInterval);
434         add_timer(&pHwData->LEDTimer);
435 }
436
437 static int hal_init_hardware(struct ieee80211_hw *hw)
438 {
439         struct wbsoft_priv *priv = hw->priv;
440         struct hw_data *pHwData = &priv->sHwData;
441         u16 SoftwareSet;
442
443         pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME;
444         pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
445
446         if (!Wb35Reg_initial(pHwData))
447                 goto error_reg_destroy;
448
449         if (!Wb35Tx_initial(pHwData))
450                 goto error_tx_destroy;
451
452         if (!Wb35Rx_initial(pHwData))
453                 goto error_rx_destroy;
454
455         init_timer(&pHwData->LEDTimer);
456         pHwData->LEDTimer.function = hal_led_control;
457         pHwData->LEDTimer.data = (unsigned long)priv;
458         pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(1000);
459         add_timer(&pHwData->LEDTimer);
460
461         SoftwareSet = hal_software_set(pHwData);
462
463 #ifdef Vendor2
464         // Try to make sure the EEPROM contain
465         SoftwareSet >>= 8;
466         if (SoftwareSet != 0x82)
467                 return false;
468 #endif
469
470         Wb35Rx_start(hw);
471         Wb35Tx_EP2VM_start(priv);
472
473         return 0;
474
475 error_rx_destroy:
476         Wb35Rx_destroy(pHwData);
477 error_tx_destroy:
478         Wb35Tx_destroy(pHwData);
479 error_reg_destroy:
480         Wb35Reg_destroy(pHwData);
481
482         pHwData->SurpriseRemove = 1;
483         return -EINVAL;
484 }
485
486 static int wb35_hw_init(struct ieee80211_hw *hw)
487 {
488         struct wbsoft_priv *priv = hw->priv;
489         struct hw_data *pHwData = &priv->sHwData;
490         u8 EEPROM_region;
491         u8 HwRadioOff;
492         u8 *pMacAddr2;
493         u8 *pMacAddr;
494         int err;
495
496         pHwData->phy_type = RF_DECIDE_BY_INF;
497
498         priv->Mds.TxRTSThreshold                = DEFAULT_RTSThreshold;
499         priv->Mds.TxFragmentThreshold           = DEFAULT_FRAGMENT_THRESHOLD;
500
501         priv->sLocalPara.region_INF             = REGION_AUTO;
502         priv->sLocalPara.TxRateMode             = RATE_AUTO;
503         priv->sLocalPara.bMacOperationMode      = MODE_802_11_BG;
504         priv->sLocalPara.MTUsize                = MAX_ETHERNET_PACKET_SIZE;
505         priv->sLocalPara.bPreambleMode          = AUTO_MODE;
506         priv->sLocalPara.bWepKeyError           = false;
507         priv->sLocalPara.bToSelfPacketReceived  = false;
508         priv->sLocalPara.WepKeyDetectTimerCount = 2 * 100; /* 2 seconds */
509
510         priv->sLocalPara.RadioOffStatus.boSwRadioOff = false;
511
512         err = hal_init_hardware(hw);
513         if (err)
514                 goto error;
515
516         EEPROM_region = hal_get_region_from_EEPROM(pHwData);
517         if (EEPROM_region != REGION_AUTO)
518                 priv->sLocalPara.region = EEPROM_region;
519         else {
520                 if (priv->sLocalPara.region_INF != REGION_AUTO)
521                         priv->sLocalPara.region = priv->sLocalPara.region_INF;
522                 else
523                         priv->sLocalPara.region = REGION_USA;   /* default setting */
524         }
525
526         // Get Software setting flag from hal
527         priv->sLocalPara.boAntennaDiversity = false;
528         if (hal_software_set(pHwData) & 0x00000001)
529                 priv->sLocalPara.boAntennaDiversity = true;
530
531         Mds_initial(priv);
532
533         /*
534          * If no user-defined address in the registry, use the addresss
535          * "burned" on the NIC instead.
536          */
537         pMacAddr = priv->sLocalPara.ThisMacAddress;
538         pMacAddr2 = priv->sLocalPara.PermanentAddress;
539
540         /* Reading ethernet address from EEPROM */
541         hal_get_permanent_address(pHwData, priv->sLocalPara.PermanentAddress);
542         if (memcmp(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) == 0)
543                 memcpy(pMacAddr, pMacAddr2, MAC_ADDR_LENGTH);
544         else {
545                 /* Set the user define MAC address */
546                 hal_set_ethernet_address(pHwData,
547                                          priv->sLocalPara.ThisMacAddress);
548         }
549
550         priv->sLocalPara.bAntennaNo = hal_get_antenna_number(pHwData);
551 #ifdef _PE_STATE_DUMP_
552         printk("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo);
553 #endif
554         hal_get_hw_radio_off(pHwData);
555
556         /* Waiting for HAL setting OK */
557         while (!hal_idle(pHwData))
558                 msleep(10);
559
560         MTO_Init(priv);
561
562         HwRadioOff = hal_get_hw_radio_off(pHwData);
563         priv->sLocalPara.RadioOffStatus.boHwRadioOff = !!HwRadioOff;
564
565         hal_set_radio_mode(pHwData,
566                            (unsigned char)(priv->sLocalPara.RadioOffStatus.
567                                            boSwRadioOff
568                                            || priv->sLocalPara.RadioOffStatus.
569                                            boHwRadioOff));
570
571         /* Notify hal that the driver is ready now. */
572         hal_driver_init_OK(pHwData) = 1;
573
574 error:
575         return err;
576 }
577
578 static int wb35_probe(struct usb_interface *intf,
579                       const struct usb_device_id *id_table)
580 {
581         struct usb_device *udev = interface_to_usbdev(intf);
582         struct usb_endpoint_descriptor *endpoint;
583         struct usb_host_interface *interface;
584         struct ieee80211_hw *dev;
585         struct wbsoft_priv *priv;
586         struct wb_usb *pWbUsb;
587         int nr, err;
588         u32 ltmp;
589
590         usb_get_dev(udev);
591
592         /* Check the device if it already be opened */
593         nr = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
594                              0x01,
595                              USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
596                              0x0, 0x400, &ltmp, 4, HZ * 100);
597         if (nr < 0) {
598                 err = nr;
599                 goto error;
600         }
601
602         /* Is already initialized? */
603         ltmp = cpu_to_le32(ltmp);
604         if (ltmp) {
605                 err = -EBUSY;
606                 goto error;
607         }
608
609         dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
610         if (!dev) {
611                 err = -ENOMEM;
612                 goto error;
613         }
614
615         priv = dev->priv;
616
617         spin_lock_init(&priv->SpinLock);
618
619         pWbUsb = &priv->sHwData.WbUsb;
620         pWbUsb->udev = udev;
621
622         interface = intf->cur_altsetting;
623         endpoint = &interface->endpoint[0].desc;
624
625         if (endpoint[2].wMaxPacketSize == 512) {
626                 printk("[w35und] Working on USB 2.0\n");
627                 pWbUsb->IsUsb20 = 1;
628         }
629
630         err = wb35_hw_init(dev);
631         if (err)
632                 goto error_free_hw;
633
634         SET_IEEE80211_DEV(dev, &udev->dev);
635         {
636                 struct hw_data *pHwData = &priv->sHwData;
637                 unsigned char dev_addr[MAX_ADDR_LEN];
638                 hal_get_permanent_address(pHwData, dev_addr);
639                 SET_IEEE80211_PERM_ADDR(dev, dev_addr);
640         }
641
642         dev->extra_tx_headroom = 12;    /* FIXME */
643         dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
644         dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
645
646         dev->channel_change_time = 1000;
647         dev->max_signal = 100;
648         dev->queues = 1;
649
650         dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &wbsoft_band_2GHz;
651
652         err = ieee80211_register_hw(dev);
653         if (err)
654                 goto error_free_hw;
655
656         usb_set_intfdata(intf, dev);
657
658         return 0;
659
660 error_free_hw:
661         ieee80211_free_hw(dev);
662 error:
663         usb_put_dev(udev);
664         return err;
665 }
666
667 static void hal_halt(struct hw_data *pHwData)
668 {
669         del_timer_sync(&pHwData->LEDTimer);
670         /* XXX: Wait for Timer DPC exit. */
671         msleep(100);
672         Wb35Rx_destroy(pHwData);
673         Wb35Tx_destroy(pHwData);
674         Wb35Reg_destroy(pHwData);
675 }
676
677 static void wb35_hw_halt(struct wbsoft_priv *adapter)
678 {
679         Mds_Destroy(adapter);
680
681         /* Turn off Rx and Tx hardware ability */
682         hal_stop(&adapter->sHwData);
683 #ifdef _PE_USB_INI_DUMP_
684         printk("[w35und] Hal_stop O.K.\n");
685 #endif
686         /* Waiting Irp completed */
687         msleep(100);
688
689         hal_halt(&adapter->sHwData);
690 }
691
692 static void wb35_disconnect(struct usb_interface *intf)
693 {
694         struct ieee80211_hw *hw = usb_get_intfdata(intf);
695         struct wbsoft_priv *priv = hw->priv;
696
697         wb35_hw_halt(priv);
698
699         ieee80211_stop_queues(hw);
700         ieee80211_unregister_hw(hw);
701         ieee80211_free_hw(hw);
702
703         usb_set_intfdata(intf, NULL);
704         usb_put_dev(interface_to_usbdev(intf));
705 }
706
707 static struct usb_driver wb35_driver = {
708         .name           = "w35und",
709         .id_table       = wb35_table,
710         .probe          = wb35_probe,
711         .disconnect     = wb35_disconnect,
712 };
713
714 static int __init wb35_init(void)
715 {
716         return usb_register(&wb35_driver);
717 }
718
719 static void __exit wb35_exit(void)
720 {
721         usb_deregister(&wb35_driver);
722 }
723
724 module_init(wb35_init);
725 module_exit(wb35_exit);