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