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 | ||
127 | ch.band = 1; | |
128 | ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */ | |
129 | ||
130 | ||
1e8a2b60 PE |
131 | hal_set_current_channel(&priv->sHwData, ch); |
132 | hal_set_beacon_period(&priv->sHwData, conf->beacon_int); | |
133 | // hal_set_cap_info(&priv->sHwData, ?? ); | |
8e41b4b6 | 134 | // hal_set_ssid(struct hw_data * pHwData, u8 * pssid, u8 ssid_len); ?? |
1e8a2b60 PE |
135 | hal_set_accept_broadcast(&priv->sHwData, 1); |
136 | hal_set_accept_promiscuous(&priv->sHwData, 1); | |
137 | hal_set_accept_multicast(&priv->sHwData, 1); | |
138 | hal_set_accept_beacon(&priv->sHwData, 1); | |
139 | hal_set_radio_mode(&priv->sHwData, 0); | |
8e41b4b6 PE |
140 | //hal_set_antenna_number( struct hw_data * pHwData, u8 number ) |
141 | //hal_set_rf_power(struct hw_data * pHwData, u8 PowerIndex) | |
66101de1 PM |
142 | |
143 | ||
1e8a2b60 | 144 | // hal_start_bss(&priv->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ?? |
66101de1 | 145 | |
8e41b4b6 | 146 | //void hal_set_rates(struct hw_data * pHwData, u8 * pbss_rates, |
66101de1 PM |
147 | // u8 length, unsigned char basic_rate_set) |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
152 | static int wbsoft_config_interface(struct ieee80211_hw *dev, | |
153 | struct ieee80211_vif *vif, | |
154 | struct ieee80211_if_conf *conf) | |
155 | { | |
156 | printk("wbsoft_config_interface called\n"); | |
157 | return 0; | |
158 | } | |
159 | ||
160 | static u64 wbsoft_get_tsf(struct ieee80211_hw *dev) | |
161 | { | |
162 | printk("wbsoft_get_tsf called\n"); | |
163 | return 0; | |
164 | } | |
165 | ||
166 | static const struct ieee80211_ops wbsoft_ops = { | |
167 | .tx = wbsoft_tx, | |
912b209f | 168 | .start = wbsoft_start, /* Start can be pretty much empty as we do wb35_hw_init() during probe? */ |
68ab0c96 | 169 | .stop = wbsoft_stop, |
66101de1 PM |
170 | .add_interface = wbsoft_add_interface, |
171 | .remove_interface = wbsoft_remove_interface, | |
172 | .config = wbsoft_config, | |
173 | .config_interface = wbsoft_config_interface, | |
174 | .configure_filter = wbsoft_configure_filter, | |
68ab0c96 GKH |
175 | .get_stats = wbsoft_get_stats, |
176 | .get_tx_stats = wbsoft_get_tx_stats, | |
66101de1 PM |
177 | .get_tsf = wbsoft_get_tsf, |
178 | // conf_tx: hal_set_cwmin()/hal_set_cwmax; | |
179 | }; | |
180 | ||
80767e6e PE |
181 | static void hal_halt(struct hw_data *pHwData, void *ppa_data) |
182 | { | |
183 | switch( pHwData->InitialResource ) | |
184 | { | |
185 | case 4: | |
186 | case 3: del_timer_sync(&pHwData->LEDTimer); | |
187 | msleep(100); // Wait for Timer DPC exit 940623.2 | |
188 | Wb35Rx_destroy( pHwData ); // Release the Rx | |
189 | case 2: Wb35Tx_destroy( pHwData ); // Release the Tx | |
190 | case 1: Wb35Reg_destroy( pHwData ); // Release the Wb35 Regisster resources | |
191 | } | |
192 | } | |
193 | ||
194 | static void hal_led_control(unsigned long data) | |
195 | { | |
196 | struct wbsoft_priv *adapter = (struct wbsoft_priv *) data; | |
197 | struct hw_data * pHwData = &adapter->sHwData; | |
198 | struct wb35_reg *reg = &pHwData->reg; | |
199 | u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT; | |
200 | u8 LEDgray[20] = { 0,3,4,6,8,10,11,12,13,14,15,14,13,12,11,10,8,6,4,2 }; | |
201 | 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 }; | |
202 | u32 TimeInterval = 500, ltmp, ltmp2; | |
203 | ltmp=0; | |
204 | ||
205 | if( pHwData->SurpriseRemove ) return; | |
206 | ||
207 | if( pHwData->LED_control ) { | |
208 | ltmp2 = pHwData->LED_control & 0xff; | |
209 | if( ltmp2 == 5 ) // 5 is WPS mode | |
210 | { | |
211 | TimeInterval = 100; | |
212 | ltmp2 = (pHwData->LED_control>>8) & 0xff; | |
213 | switch( ltmp2 ) | |
214 | { | |
215 | case 1: // [0.2 On][0.1 Off]... | |
216 | pHwData->LED_Blinking %= 3; | |
217 | ltmp = 0x1010; // Led 1 & 0 Green and Red | |
218 | if( pHwData->LED_Blinking == 2 ) // Turn off | |
219 | ltmp = 0; | |
220 | break; | |
221 | case 2: // [0.1 On][0.1 Off]... | |
222 | pHwData->LED_Blinking %= 2; | |
223 | ltmp = 0x0010; // Led 0 red color | |
224 | if( pHwData->LED_Blinking ) // Turn off | |
225 | ltmp = 0; | |
226 | break; | |
227 | 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]... | |
228 | pHwData->LED_Blinking %= 15; | |
229 | ltmp = 0x0010; // Led 0 red color | |
230 | if( (pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking%2) ) // Turn off 0.6 sec | |
231 | ltmp = 0; | |
232 | break; | |
233 | case 4: // [300 On][ off ] | |
234 | ltmp = 0x1000; // Led 1 Green color | |
235 | if( pHwData->LED_Blinking >= 3000 ) | |
236 | ltmp = 0; // led maybe on after 300sec * 32bit counter overlap. | |
237 | break; | |
238 | } | |
239 | pHwData->LED_Blinking++; | |
240 | ||
241 | reg->U1BC_LEDConfigure = ltmp; | |
242 | if( LEDSet != 7 ) // Only 111 mode has 2 LEDs on PCB. | |
243 | { | |
244 | reg->U1BC_LEDConfigure |= (ltmp &0xff)<<8; // Copy LED result to each LED control register | |
245 | reg->U1BC_LEDConfigure |= (ltmp &0xff00)>>8; | |
246 | } | |
247 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); | |
248 | } | |
249 | } | |
250 | else if( pHwData->CurrentRadioSw || pHwData->CurrentRadioHw ) // If radio off | |
251 | { | |
252 | if( reg->U1BC_LEDConfigure & 0x1010 ) | |
253 | { | |
254 | reg->U1BC_LEDConfigure &= ~0x1010; | |
255 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); | |
256 | } | |
257 | } | |
258 | else | |
259 | { | |
260 | switch( LEDSet ) | |
261 | { | |
262 | case 4: // [100] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing | |
263 | if( !pHwData->LED_LinkOn ) // Blink only if not Link On | |
264 | { | |
265 | // Blinking if scanning is on progress | |
266 | if( pHwData->LED_Scanning ) | |
267 | { | |
268 | if( pHwData->LED_Blinking == 0 ) | |
269 | { | |
270 | reg->U1BC_LEDConfigure |= 0x10; | |
271 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 On | |
272 | pHwData->LED_Blinking = 1; | |
273 | TimeInterval = 300; | |
274 | } | |
275 | else | |
276 | { | |
277 | reg->U1BC_LEDConfigure &= ~0x10; | |
278 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off | |
279 | pHwData->LED_Blinking = 0; | |
280 | TimeInterval = 300; | |
281 | } | |
282 | } | |
283 | else | |
284 | { | |
285 | //Turn Off LED_0 | |
286 | if( reg->U1BC_LEDConfigure & 0x10 ) | |
287 | { | |
288 | reg->U1BC_LEDConfigure &= ~0x10; | |
289 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off | |
290 | } | |
291 | } | |
292 | } | |
293 | else | |
294 | { | |
295 | // Turn On LED_0 | |
296 | if( (reg->U1BC_LEDConfigure & 0x10) == 0 ) | |
297 | { | |
298 | reg->U1BC_LEDConfigure |= 0x10; | |
299 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off | |
300 | } | |
301 | } | |
302 | break; | |
303 | ||
304 | case 6: // [110] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing | |
305 | if( !pHwData->LED_LinkOn ) // Blink only if not Link On | |
306 | { | |
307 | // Blinking if scanning is on progress | |
308 | if( pHwData->LED_Scanning ) | |
309 | { | |
310 | if( pHwData->LED_Blinking == 0 ) | |
311 | { | |
312 | reg->U1BC_LEDConfigure &= ~0xf; | |
313 | reg->U1BC_LEDConfigure |= 0x10; | |
314 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 On | |
315 | pHwData->LED_Blinking = 1; | |
316 | TimeInterval = 300; | |
317 | } | |
318 | else | |
319 | { | |
320 | reg->U1BC_LEDConfigure &= ~0x1f; | |
321 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off | |
322 | pHwData->LED_Blinking = 0; | |
323 | TimeInterval = 300; | |
324 | } | |
325 | } | |
326 | else | |
327 | { | |
328 | // 20060901 Gray blinking if in disconnect state and not scanning | |
329 | ltmp = reg->U1BC_LEDConfigure; | |
330 | reg->U1BC_LEDConfigure &= ~0x1f; | |
331 | if( LEDgray2[(pHwData->LED_Blinking%30)] ) | |
332 | { | |
333 | reg->U1BC_LEDConfigure |= 0x10; | |
334 | reg->U1BC_LEDConfigure |= LEDgray2[ (pHwData->LED_Blinking%30) ]; | |
335 | } | |
336 | pHwData->LED_Blinking++; | |
337 | if( reg->U1BC_LEDConfigure != ltmp ) | |
338 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off | |
339 | TimeInterval = 100; | |
340 | } | |
341 | } | |
342 | else | |
343 | { | |
344 | // Turn On LED_0 | |
345 | if( (reg->U1BC_LEDConfigure & 0x10) == 0 ) | |
346 | { | |
347 | reg->U1BC_LEDConfigure |= 0x10; | |
348 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off | |
349 | } | |
350 | } | |
351 | break; | |
352 | ||
353 | case 5: // [101] Only 1 Led be placed on PCB and use LED_1 for showing | |
354 | if( !pHwData->LED_LinkOn ) // Blink only if not Link On | |
355 | { | |
356 | // Blinking if scanning is on progress | |
357 | if( pHwData->LED_Scanning ) | |
358 | { | |
359 | if( pHwData->LED_Blinking == 0 ) | |
360 | { | |
361 | reg->U1BC_LEDConfigure |= 0x1000; | |
362 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 On | |
363 | pHwData->LED_Blinking = 1; | |
364 | TimeInterval = 300; | |
365 | } | |
366 | else | |
367 | { | |
368 | reg->U1BC_LEDConfigure &= ~0x1000; | |
369 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 Off | |
370 | pHwData->LED_Blinking = 0; | |
371 | TimeInterval = 300; | |
372 | } | |
373 | } | |
374 | else | |
375 | { | |
376 | //Turn Off LED_1 | |
377 | if( reg->U1BC_LEDConfigure & 0x1000 ) | |
378 | { | |
379 | reg->U1BC_LEDConfigure &= ~0x1000; | |
380 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 Off | |
381 | } | |
382 | } | |
383 | } | |
384 | else | |
385 | { | |
386 | // Is transmitting/receiving ?? | |
387 | if( (adapter->RxByteCount != pHwData->RxByteCountLast ) || | |
388 | (adapter->TxByteCount != pHwData->TxByteCountLast ) ) | |
389 | { | |
390 | if( (reg->U1BC_LEDConfigure & 0x3000) != 0x3000 ) | |
391 | { | |
392 | reg->U1BC_LEDConfigure |= 0x3000; | |
393 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 On | |
394 | } | |
395 | ||
396 | // Update variable | |
397 | pHwData->RxByteCountLast = adapter->RxByteCount; | |
398 | pHwData->TxByteCountLast = adapter->TxByteCount; | |
399 | TimeInterval = 200; | |
400 | } | |
401 | else | |
402 | { | |
403 | // Turn On LED_1 and blinking if transmitting/receiving | |
404 | if( (reg->U1BC_LEDConfigure & 0x3000) != 0x1000 ) | |
405 | { | |
406 | reg->U1BC_LEDConfigure &= ~0x3000; | |
407 | reg->U1BC_LEDConfigure |= 0x1000; | |
408 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 On | |
409 | } | |
410 | } | |
411 | } | |
412 | break; | |
413 | ||
414 | default: // Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active | |
415 | if( (reg->U1BC_LEDConfigure & 0x3000) != 0x3000 ) | |
416 | { | |
417 | reg->U1BC_LEDConfigure |= 0x3000;// LED_1 is always on and event enable | |
418 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); | |
419 | } | |
420 | ||
421 | if( pHwData->LED_Blinking ) | |
422 | { | |
423 | // Gray blinking | |
424 | reg->U1BC_LEDConfigure &= ~0x0f; | |
425 | reg->U1BC_LEDConfigure |= 0x10; | |
426 | reg->U1BC_LEDConfigure |= LEDgray[ (pHwData->LED_Blinking-1)%20 ]; | |
427 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); | |
428 | ||
429 | pHwData->LED_Blinking += 2; | |
430 | if( pHwData->LED_Blinking < 40 ) | |
431 | TimeInterval = 100; | |
432 | else | |
433 | { | |
434 | pHwData->LED_Blinking = 0; // Stop blinking | |
435 | reg->U1BC_LEDConfigure &= ~0x0f; | |
436 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); | |
437 | } | |
438 | break; | |
439 | } | |
440 | ||
441 | if( pHwData->LED_LinkOn ) | |
442 | { | |
443 | if( !(reg->U1BC_LEDConfigure & 0x10) ) // Check the LED_0 | |
444 | { | |
445 | //Try to turn ON LED_0 after gray blinking | |
446 | reg->U1BC_LEDConfigure |= 0x10; | |
447 | pHwData->LED_Blinking = 1; //Start blinking | |
448 | TimeInterval = 50; | |
449 | } | |
450 | } | |
451 | else | |
452 | { | |
453 | if( reg->U1BC_LEDConfigure & 0x10 ) // Check the LED_0 | |
454 | { | |
455 | reg->U1BC_LEDConfigure &= ~0x10; | |
456 | Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); | |
457 | } | |
458 | } | |
459 | break; | |
460 | } | |
461 | ||
462 | //20060828.1 Active send null packet to avoid AP disconnect | |
463 | if( pHwData->LED_LinkOn ) | |
464 | { | |
465 | pHwData->NullPacketCount += TimeInterval; | |
466 | if( pHwData->NullPacketCount >= DEFAULT_NULL_PACKET_COUNT ) | |
467 | { | |
468 | pHwData->NullPacketCount = 0; | |
469 | } | |
470 | } | |
471 | } | |
472 | ||
473 | pHwData->time_count += TimeInterval; | |
474 | Wb35Tx_CurrentTime(adapter, pHwData->time_count); // 20060928 add | |
475 | pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(TimeInterval); | |
476 | add_timer(&pHwData->LEDTimer); | |
477 | } | |
478 | ||
479 | static u8 hal_init_hardware(struct ieee80211_hw *hw) | |
480 | { | |
481 | struct wbsoft_priv *priv = hw->priv; | |
482 | struct hw_data * pHwData = &priv->sHwData; | |
483 | u16 SoftwareSet; | |
484 | ||
485 | // Initial the variable | |
486 | pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME; // Setting Rx maximum MSDU life time | |
487 | pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; // Setting default fragment threshold | |
488 | ||
489 | pHwData->InitialResource = 1; | |
490 | if( Wb35Reg_initial(pHwData)) { | |
491 | pHwData->InitialResource = 2; | |
492 | if (Wb35Tx_initial(pHwData)) { | |
493 | pHwData->InitialResource = 3; | |
494 | if (Wb35Rx_initial(pHwData)) { | |
495 | pHwData->InitialResource = 4; | |
496 | init_timer(&pHwData->LEDTimer); | |
497 | pHwData->LEDTimer.function = hal_led_control; | |
498 | pHwData->LEDTimer.data = (unsigned long) priv; | |
499 | pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(1000); | |
500 | add_timer(&pHwData->LEDTimer); | |
501 | ||
502 | // | |
503 | // For restrict to vendor's hardware | |
504 | // | |
505 | SoftwareSet = hal_software_set( pHwData ); | |
506 | ||
507 | #ifdef Vendor2 | |
508 | // Try to make sure the EEPROM contain | |
509 | SoftwareSet >>= 8; | |
510 | if( SoftwareSet != 0x82 ) | |
511 | return false; | |
512 | #endif | |
513 | ||
514 | Wb35Rx_start(hw); | |
515 | Wb35Tx_EP2VM_start(priv); | |
516 | ||
517 | return true; | |
518 | } | |
519 | } | |
520 | } | |
521 | ||
522 | pHwData->SurpriseRemove = 1; | |
523 | return false; | |
524 | } | |
525 | ||
26598511 | 526 | static int wb35_hw_init(struct ieee80211_hw *hw) |
912b209f PE |
527 | { |
528 | struct wbsoft_priv *priv = hw->priv; | |
8e41b4b6 | 529 | struct hw_data * pHwData; |
912b209f PE |
530 | u8 *pMacAddr; |
531 | u8 *pMacAddr2; | |
912b209f PE |
532 | u8 EEPROM_region; |
533 | u8 HwRadioOff; | |
26598511 | 534 | int err; |
912b209f PE |
535 | |
536 | // | |
537 | // Setting default value for Linux | |
538 | // | |
539 | priv->sLocalPara.region_INF = REGION_AUTO; | |
540 | priv->sLocalPara.TxRateMode = RATE_AUTO; | |
541 | priv->sLocalPara.bMacOperationMode = MODE_802_11_BG; // B/G mode | |
542 | priv->Mds.TxRTSThreshold = DEFAULT_RTSThreshold; | |
543 | priv->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; | |
544 | hal_set_phy_type( &priv->sHwData, RF_WB_242_1 ); | |
545 | priv->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE; | |
546 | priv->sLocalPara.bPreambleMode = AUTO_MODE; | |
547 | priv->sLocalPara.RadioOffStatus.boSwRadioOff = false; | |
548 | pHwData = &priv->sHwData; | |
549 | hal_set_phy_type( pHwData, RF_DECIDE_BY_INF ); | |
550 | ||
912b209f PE |
551 | //added by ws for wep key error detection |
552 | priv->sLocalPara.bWepKeyError= false; | |
553 | priv->sLocalPara.bToSelfPacketReceived = false; | |
554 | priv->sLocalPara.WepKeyDetectTimerCount= 2 * 100; /// 2 seconds | |
555 | ||
556 | // Initial USB hal | |
912b209f | 557 | pHwData = &priv->sHwData; |
26598511 PE |
558 | if (!hal_init_hardware(hw)) { |
559 | err = -EINVAL; | |
912b209f | 560 | goto error; |
26598511 | 561 | } |
912b209f PE |
562 | |
563 | EEPROM_region = hal_get_region_from_EEPROM( pHwData ); | |
564 | if (EEPROM_region != REGION_AUTO) | |
565 | priv->sLocalPara.region = EEPROM_region; | |
566 | else { | |
567 | if (priv->sLocalPara.region_INF != REGION_AUTO) | |
568 | priv->sLocalPara.region = priv->sLocalPara.region_INF; | |
569 | else | |
570 | priv->sLocalPara.region = REGION_USA; //default setting | |
571 | } | |
572 | ||
573 | // Get Software setting flag from hal | |
574 | priv->sLocalPara.boAntennaDiversity = false; | |
575 | if (hal_software_set(pHwData) & 0x00000001) | |
576 | priv->sLocalPara.boAntennaDiversity = true; | |
577 | ||
912b209f | 578 | // For MDS module |
912b209f PE |
579 | Mds_initial(priv); |
580 | ||
581 | //======================================= | |
582 | // Initialize the SME, SCAN, MLME, ROAM | |
583 | //======================================= | |
912b209f PE |
584 | |
585 | // If no user-defined address in the registry, use the addresss "burned" on the NIC instead. | |
586 | pMacAddr = priv->sLocalPara.ThisMacAddress; | |
587 | pMacAddr2 = priv->sLocalPara.PermanentAddress; | |
588 | hal_get_permanent_address( pHwData, priv->sLocalPara.PermanentAddress );// Reading ethernet address from EEPROM | |
589 | if (memcmp(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) == 0) | |
590 | memcpy(pMacAddr, pMacAddr2, MAC_ADDR_LENGTH); | |
591 | else { | |
592 | // Set the user define MAC address | |
593 | hal_set_ethernet_address(pHwData, priv->sLocalPara.ThisMacAddress); | |
594 | } | |
595 | ||
596 | //get current antenna | |
597 | priv->sLocalPara.bAntennaNo = hal_get_antenna_number(pHwData); | |
598 | #ifdef _PE_STATE_DUMP_ | |
0c59dbaa | 599 | printk("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo); |
912b209f PE |
600 | #endif |
601 | hal_get_hw_radio_off( pHwData ); | |
602 | ||
603 | // Waiting for HAL setting OK | |
604 | while (!hal_idle(pHwData)) | |
605 | msleep(10); | |
606 | ||
607 | MTO_Init(priv); | |
608 | ||
609 | HwRadioOff = hal_get_hw_radio_off( pHwData ); | |
610 | priv->sLocalPara.RadioOffStatus.boHwRadioOff = !!HwRadioOff; | |
611 | ||
612 | hal_set_radio_mode( pHwData, (unsigned char)(priv->sLocalPara.RadioOffStatus.boSwRadioOff || priv->sLocalPara.RadioOffStatus.boHwRadioOff) ); | |
613 | ||
614 | hal_driver_init_OK(pHwData) = 1; // Notify hal that the driver is ready now. | |
615 | //set a tx power for reference..... | |
616 | // sme_set_tx_power_level(priv, 12); FIXME? | |
26598511 | 617 | return 0; |
912b209f PE |
618 | |
619 | error: | |
26598511 | 620 | hal_halt(pHwData, NULL); |
912b209f | 621 | |
26598511 | 622 | return err; |
912b209f PE |
623 | } |
624 | ||
302bae85 | 625 | static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table) |
66101de1 | 626 | { |
eb62f3ea | 627 | struct wb_usb *pWbUsb; |
66101de1 PM |
628 | struct usb_host_interface *interface; |
629 | struct usb_endpoint_descriptor *endpoint; | |
66101de1 PM |
630 | u32 ltmp; |
631 | struct usb_device *udev = interface_to_usbdev(intf); | |
1523ddc4 PE |
632 | struct wbsoft_priv *priv; |
633 | struct ieee80211_hw *dev; | |
acfa5110 | 634 | int nr, err; |
66101de1 PM |
635 | |
636 | usb_get_dev(udev); | |
637 | ||
dc7e04fe | 638 | // 20060630.2 Check the device if it already be opened |
acfa5110 PE |
639 | nr = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ), |
640 | 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, | |
641 | 0x0, 0x400, <mp, 4, HZ*100 ); | |
642 | if (nr < 0) { | |
643 | err = nr; | |
dc7e04fe | 644 | goto error; |
acfa5110 | 645 | } |
66101de1 | 646 | |
dc7e04fe | 647 | ltmp = cpu_to_le32(ltmp); |
1523ddc4 PE |
648 | if (ltmp) { // Is already initialized? |
649 | err = -EBUSY; | |
dc7e04fe | 650 | goto error; |
1523ddc4 | 651 | } |
66101de1 | 652 | |
1e8a2b60 | 653 | dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops); |
acfa5110 PE |
654 | if (!dev) { |
655 | err = -ENOMEM; | |
1523ddc4 | 656 | goto error; |
acfa5110 | 657 | } |
66101de1 | 658 | |
1e8a2b60 | 659 | priv = dev->priv; |
1e8a2b60 | 660 | |
912b209f PE |
661 | spin_lock_init(&priv->SpinLock); |
662 | ||
1e8a2b60 | 663 | pWbUsb = &priv->sHwData.WbUsb; |
dc7e04fe | 664 | pWbUsb->udev = udev; |
66101de1 | 665 | |
dc7e04fe PE |
666 | interface = intf->cur_altsetting; |
667 | endpoint = &interface->endpoint[0].desc; | |
66101de1 | 668 | |
dc7e04fe PE |
669 | if (endpoint[2].wMaxPacketSize == 512) { |
670 | printk("[w35und] Working on USB 2.0\n"); | |
671 | pWbUsb->IsUsb20 = 1; | |
672 | } | |
66101de1 | 673 | |
26598511 PE |
674 | err = wb35_hw_init(dev); |
675 | if (err) | |
1e8a2b60 | 676 | goto error_free_hw; |
66101de1 | 677 | |
1523ddc4 PE |
678 | SET_IEEE80211_DEV(dev, &udev->dev); |
679 | { | |
8e41b4b6 | 680 | struct hw_data * pHwData = &priv->sHwData; |
9ce922fd | 681 | unsigned char dev_addr[MAX_ADDR_LEN]; |
1523ddc4 PE |
682 | hal_get_permanent_address(pHwData, dev_addr); |
683 | SET_IEEE80211_PERM_ADDR(dev, dev_addr); | |
684 | } | |
66101de1 | 685 | |
1523ddc4 | 686 | dev->extra_tx_headroom = 12; /* FIXME */ |
05e361ca PM |
687 | dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; |
688 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | |
66101de1 | 689 | |
1523ddc4 | 690 | dev->channel_change_time = 1000; |
05e361ca | 691 | dev->max_signal = 100; |
1523ddc4 | 692 | dev->queues = 1; |
dc7e04fe | 693 | |
a36e0894 | 694 | dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &wbsoft_band_2GHz; |
66101de1 | 695 | |
1523ddc4 PE |
696 | err = ieee80211_register_hw(dev); |
697 | if (err) | |
698 | goto error_free_hw; | |
66101de1 | 699 | |
82fbb01c | 700 | usb_set_intfdata(intf, dev); |
66101de1 | 701 | |
dc7e04fe | 702 | return 0; |
1523ddc4 PE |
703 | |
704 | error_free_hw: | |
705 | ieee80211_free_hw(dev); | |
dc7e04fe | 706 | error: |
4af12e55 | 707 | usb_put_dev(udev); |
1523ddc4 | 708 | return err; |
66101de1 PM |
709 | } |
710 | ||
912b209f PE |
711 | static void wb35_hw_halt(struct wbsoft_priv *adapter) |
712 | { | |
912b209f PE |
713 | Mds_Destroy( adapter ); |
714 | ||
715 | // Turn off Rx and Tx hardware ability | |
716 | hal_stop( &adapter->sHwData ); | |
717 | #ifdef _PE_USB_INI_DUMP_ | |
0c59dbaa | 718 | printk("[w35und] Hal_stop O.K.\n"); |
912b209f PE |
719 | #endif |
720 | msleep(100);// Waiting Irp completed | |
721 | ||
912b209f PE |
722 | // Halt the HAL |
723 | hal_halt(&adapter->sHwData, NULL); | |
724 | } | |
725 | ||
726 | ||
302bae85 | 727 | static void wb35_disconnect(struct usb_interface *intf) |
66101de1 | 728 | { |
82fbb01c PE |
729 | struct ieee80211_hw *hw = usb_get_intfdata(intf); |
730 | struct wbsoft_priv *priv = hw->priv; | |
66101de1 | 731 | |
912b209f | 732 | wb35_hw_halt(priv); |
66101de1 | 733 | |
82fbb01c PE |
734 | ieee80211_stop_queues(hw); |
735 | ieee80211_unregister_hw(hw); | |
736 | ieee80211_free_hw(hw); | |
737 | ||
4af12e55 PE |
738 | usb_set_intfdata(intf, NULL); |
739 | usb_put_dev(interface_to_usbdev(intf)); | |
66101de1 PM |
740 | } |
741 | ||
dd38da46 PE |
742 | static struct usb_driver wb35_driver = { |
743 | .name = "w35und", | |
744 | .id_table = wb35_table, | |
745 | .probe = wb35_probe, | |
746 | .disconnect = wb35_disconnect, | |
747 | }; | |
748 | ||
749 | static int __init wb35_init(void) | |
750 | { | |
751 | return usb_register(&wb35_driver); | |
752 | } | |
753 | ||
754 | static void __exit wb35_exit(void) | |
755 | { | |
756 | usb_deregister(&wb35_driver); | |
757 | } | |
66101de1 | 758 | |
dd38da46 PE |
759 | module_init(wb35_init); |
760 | module_exit(wb35_exit); |