]>
Commit | Line | Data |
---|---|---|
2865d42c LF |
1 | /****************************************************************************** |
2 | * os_intfs.c | |
3 | * | |
4 | * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. | |
5 | * Linux device driver for RTL8192SU | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of version 2 of the GNU General Public License as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along with | |
17 | * this program; if not, write to the Free Software Foundation, Inc., | |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | |
19 | * | |
20 | * Modifications for inclusion into the Linux staging tree are | |
21 | * Copyright(c) 2010 Larry Finger. All rights reserved. | |
22 | * | |
23 | * Contact information: | |
24 | * WLAN FAE <wlanfae@realtek.com>. | |
25 | * Larry Finger <Larry.Finger@lwfinger.net> | |
26 | * | |
27 | ******************************************************************************/ | |
28 | ||
29 | #define _OS_INTFS_C_ | |
30 | ||
31 | #include <linux/module.h> | |
2865d42c | 32 | #include <linux/kthread.h> |
8c213fa5 | 33 | #include <linux/firmware.h> |
2865d42c LF |
34 | #include "osdep_service.h" |
35 | #include "drv_types.h" | |
36 | #include "xmit_osdep.h" | |
37 | #include "recv_osdep.h" | |
38 | #include "rtl871x_ioctl.h" | |
39 | #include "usb_osintf.h" | |
40 | ||
41 | MODULE_LICENSE("GPL"); | |
42 | MODULE_DESCRIPTION("rtl871x wireless lan driver"); | |
43 | MODULE_AUTHOR("Larry Finger"); | |
44 | ||
45 | static char ifname[IFNAMSIZ] = "wlan%d"; | |
46 | ||
47 | /* module param defaults */ | |
48 | static int chip_version = RTL8712_2ndCUT; | |
49 | static int rfintfs = HWPI; | |
50 | static int lbkmode = RTL8712_AIR_TRX; | |
51 | static int hci = RTL8712_USB; | |
52 | static int ampdu_enable = 1;/*for enable tx_ampdu*/ | |
53 | ||
be10ac2b | 54 | /* The video_mode variable is for video mode.*/ |
2865d42c LF |
55 | /* It may be specify when inserting module with video_mode=1 parameter.*/ |
56 | static int video_mode = 1; /* enable video mode*/ | |
57 | ||
58 | /*Ndis802_11Infrastructure; infra, ad-hoc, auto*/ | |
59 | static int network_mode = Ndis802_11IBSS; | |
60 | static int channel = 1;/*ad-hoc support requirement*/ | |
61 | static int wireless_mode = WIRELESS_11BG; | |
62 | static int vrtl_carrier_sense = AUTO_VCS; | |
63 | static int vcs_type = RTS_CTS; | |
64 | static int frag_thresh = 2346; | |
65 | static int preamble = PREAMBLE_LONG;/*long, short, auto*/ | |
66 | static int scan_mode = 1;/*active, passive*/ | |
67 | static int adhoc_tx_pwr = 1; | |
68 | static int soft_ap; | |
69 | static int smart_ps = 1; | |
70 | static int power_mgnt = PS_MODE_ACTIVE; | |
71 | static int radio_enable = 1; | |
72 | static int long_retry_lmt = 7; | |
73 | static int short_retry_lmt = 7; | |
74 | static int busy_thresh = 40; | |
75 | static int ack_policy = NORMAL_ACK; | |
76 | static int mp_mode; | |
77 | static int software_encrypt; | |
78 | static int software_decrypt; | |
79 | ||
80 | static int wmm_enable;/* default is set to disable the wmm.*/ | |
81 | static int uapsd_enable; | |
82 | static int uapsd_max_sp = NO_LIMIT; | |
83 | static int uapsd_acbk_en; | |
84 | static int uapsd_acbe_en; | |
85 | static int uapsd_acvi_en; | |
86 | static int uapsd_acvo_en; | |
87 | ||
88 | static int ht_enable = 1; | |
89 | static int cbw40_enable = 1; | |
90 | static int rf_config = RTL8712_RF_1T2R; /* 1T2R*/ | |
91 | static int low_power; | |
92 | /* mac address to use instead of the one stored in Efuse */ | |
93 | char *r8712_initmac; | |
94 | static char *initmac; | |
d19b8647 LF |
95 | /* if wifi_test = 1, driver will disable the turbo mode and pass it to |
96 | * firmware private. | |
97 | */ | |
e1656648 | 98 | static int wifi_test; |
2865d42c LF |
99 | |
100 | module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR); | |
d19b8647 | 101 | module_param(wifi_test, int, 0644); |
2865d42c LF |
102 | module_param(initmac, charp, 0644); |
103 | module_param(video_mode, int, 0644); | |
104 | module_param(chip_version, int, 0644); | |
105 | module_param(rfintfs, int, 0644); | |
106 | module_param(lbkmode, int, 0644); | |
107 | module_param(hci, int, 0644); | |
108 | module_param(network_mode, int, 0644); | |
109 | module_param(channel, int, 0644); | |
110 | module_param(mp_mode, int, 0644); | |
111 | module_param(wmm_enable, int, 0644); | |
112 | module_param(vrtl_carrier_sense, int, 0644); | |
113 | module_param(vcs_type, int, 0644); | |
114 | module_param(busy_thresh, int, 0644); | |
115 | module_param(ht_enable, int, 0644); | |
116 | module_param(cbw40_enable, int, 0644); | |
117 | module_param(ampdu_enable, int, 0644); | |
118 | module_param(rf_config, int, 0644); | |
119 | module_param(power_mgnt, int, 0644); | |
120 | module_param(low_power, int, 0644); | |
121 | ||
122 | MODULE_PARM_DESC(ifname, " Net interface name, wlan%d=default"); | |
123 | MODULE_PARM_DESC(initmac, "MAC-Address, default: use FUSE"); | |
124 | ||
125 | static uint loadparam(struct _adapter *padapter, struct net_device *pnetdev); | |
126 | static int netdev_open(struct net_device *pnetdev); | |
127 | static int netdev_close(struct net_device *pnetdev); | |
128 | ||
129 | static uint loadparam(struct _adapter *padapter, struct net_device *pnetdev) | |
130 | { | |
131 | uint status = _SUCCESS; | |
132 | struct registry_priv *registry_par = &padapter->registrypriv; | |
133 | ||
134 | registry_par->chip_version = (u8)chip_version; | |
135 | registry_par->rfintfs = (u8)rfintfs; | |
136 | registry_par->lbkmode = (u8)lbkmode; | |
137 | registry_par->hci = (u8)hci; | |
138 | registry_par->network_mode = (u8)network_mode; | |
139 | memcpy(registry_par->ssid.Ssid, "ANY", 3); | |
140 | registry_par->ssid.SsidLength = 3; | |
141 | registry_par->channel = (u8)channel; | |
142 | registry_par->wireless_mode = (u8)wireless_mode; | |
77e73e8c | 143 | registry_par->vrtl_carrier_sense = (u8)vrtl_carrier_sense; |
2865d42c LF |
144 | registry_par->vcs_type = (u8)vcs_type; |
145 | registry_par->frag_thresh = (u16)frag_thresh; | |
146 | registry_par->preamble = (u8)preamble; | |
147 | registry_par->scan_mode = (u8)scan_mode; | |
148 | registry_par->adhoc_tx_pwr = (u8)adhoc_tx_pwr; | |
149 | registry_par->soft_ap = (u8)soft_ap; | |
150 | registry_par->smart_ps = (u8)smart_ps; | |
151 | registry_par->power_mgnt = (u8)power_mgnt; | |
152 | registry_par->radio_enable = (u8)radio_enable; | |
153 | registry_par->long_retry_lmt = (u8)long_retry_lmt; | |
154 | registry_par->short_retry_lmt = (u8)short_retry_lmt; | |
155 | registry_par->busy_thresh = (u16)busy_thresh; | |
156 | registry_par->ack_policy = (u8)ack_policy; | |
157 | registry_par->mp_mode = (u8)mp_mode; | |
158 | registry_par->software_encrypt = (u8)software_encrypt; | |
159 | registry_par->software_decrypt = (u8)software_decrypt; | |
160 | /*UAPSD*/ | |
161 | registry_par->wmm_enable = (u8)wmm_enable; | |
162 | registry_par->uapsd_enable = (u8)uapsd_enable; | |
163 | registry_par->uapsd_max_sp = (u8)uapsd_max_sp; | |
164 | registry_par->uapsd_acbk_en = (u8)uapsd_acbk_en; | |
165 | registry_par->uapsd_acbe_en = (u8)uapsd_acbe_en; | |
166 | registry_par->uapsd_acvi_en = (u8)uapsd_acvi_en; | |
167 | registry_par->uapsd_acvo_en = (u8)uapsd_acvo_en; | |
168 | registry_par->ht_enable = (u8)ht_enable; | |
169 | registry_par->cbw40_enable = (u8)cbw40_enable; | |
170 | registry_par->ampdu_enable = (u8)ampdu_enable; | |
171 | registry_par->rf_config = (u8)rf_config; | |
172 | registry_par->low_power = (u8)low_power; | |
d19b8647 | 173 | registry_par->wifi_test = (u8) wifi_test; |
2865d42c LF |
174 | r8712_initmac = initmac; |
175 | return status; | |
176 | } | |
177 | ||
178 | static int r871x_net_set_mac_address(struct net_device *pnetdev, void *p) | |
179 | { | |
8f47c28b | 180 | struct _adapter *padapter = netdev_priv(pnetdev); |
2865d42c LF |
181 | struct sockaddr *addr = p; |
182 | ||
183 | if (padapter->bup == false) | |
184 | memcpy(pnetdev->dev_addr, addr->sa_data, ETH_ALEN); | |
185 | return 0; | |
186 | } | |
187 | ||
188 | static struct net_device_stats *r871x_net_get_stats(struct net_device *pnetdev) | |
189 | { | |
8f47c28b | 190 | struct _adapter *padapter = netdev_priv(pnetdev); |
2865d42c LF |
191 | struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); |
192 | struct recv_priv *precvpriv = &(padapter->recvpriv); | |
193 | ||
194 | padapter->stats.tx_packets = pxmitpriv->tx_pkts; | |
195 | padapter->stats.rx_packets = precvpriv->rx_pkts; | |
196 | padapter->stats.tx_dropped = pxmitpriv->tx_drop; | |
197 | padapter->stats.rx_dropped = precvpriv->rx_drop; | |
198 | padapter->stats.tx_bytes = pxmitpriv->tx_bytes; | |
199 | padapter->stats.rx_bytes = precvpriv->rx_bytes; | |
200 | return &padapter->stats; | |
201 | } | |
202 | ||
203 | static const struct net_device_ops rtl8712_netdev_ops = { | |
204 | .ndo_open = netdev_open, | |
205 | .ndo_stop = netdev_close, | |
206 | .ndo_start_xmit = r8712_xmit_entry, | |
207 | .ndo_set_mac_address = r871x_net_set_mac_address, | |
208 | .ndo_get_stats = r871x_net_get_stats, | |
209 | .ndo_do_ioctl = r871x_ioctl, | |
210 | }; | |
211 | ||
212 | struct net_device *r8712_init_netdev(void) | |
213 | { | |
214 | struct _adapter *padapter; | |
215 | struct net_device *pnetdev; | |
216 | ||
217 | pnetdev = alloc_etherdev(sizeof(struct _adapter)); | |
218 | if (!pnetdev) | |
219 | return NULL; | |
220 | if (dev_alloc_name(pnetdev, ifname) < 0) { | |
221 | strcpy(ifname, "wlan%d"); | |
222 | dev_alloc_name(pnetdev, ifname); | |
223 | } | |
8f47c28b | 224 | padapter = netdev_priv(pnetdev); |
2865d42c | 225 | padapter->pnetdev = pnetdev; |
87a573ad | 226 | pr_info("r8712u: register rtl8712_netdev_ops to netdev_ops\n"); |
2865d42c LF |
227 | pnetdev->netdev_ops = &rtl8712_netdev_ops; |
228 | pnetdev->watchdog_timeo = HZ; /* 1 second timeout */ | |
229 | pnetdev->wireless_handlers = (struct iw_handler_def *) | |
230 | &r871x_handlers_def; | |
231 | /*step 2.*/ | |
232 | loadparam(padapter, pnetdev); | |
233 | netif_carrier_off(pnetdev); | |
234 | padapter->pid = 0; /* Initial the PID value used for HW PBC.*/ | |
235 | return pnetdev; | |
236 | } | |
237 | ||
238 | static u32 start_drv_threads(struct _adapter *padapter) | |
239 | { | |
f170168b | 240 | padapter->cmdThread = kthread_run(r8712_cmd_thread, padapter, "%s", |
2865d42c | 241 | padapter->pnetdev->name); |
b16aad35 | 242 | if (IS_ERR(padapter->cmdThread)) |
2865d42c LF |
243 | return _FAIL; |
244 | return _SUCCESS; | |
245 | } | |
246 | ||
247 | void r8712_stop_drv_threads(struct _adapter *padapter) | |
248 | { | |
be10ac2b | 249 | /*Below is to terminate r8712_cmd_thread & event_thread...*/ |
2865d42c LF |
250 | up(&padapter->cmdpriv.cmd_queue_sema); |
251 | if (padapter->cmdThread) | |
252 | _down_sema(&padapter->cmdpriv.terminate_cmdthread_sema); | |
253 | padapter->cmdpriv.cmd_seq = 1; | |
254 | } | |
255 | ||
256 | static void start_drv_timers(struct _adapter *padapter) | |
257 | { | |
c703c750 VT |
258 | mod_timer(&padapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, |
259 | jiffies + msecs_to_jiffies(5000)); | |
260 | mod_timer(&padapter->mlmepriv.wdg_timer, | |
261 | jiffies + msecs_to_jiffies(2000)); | |
2865d42c LF |
262 | } |
263 | ||
6c19d86b | 264 | void r8712_stop_drv_timers(struct _adapter *padapter) |
2865d42c | 265 | { |
6501c8e7 VT |
266 | del_timer_sync(&padapter->mlmepriv.assoc_timer); |
267 | del_timer_sync(&padapter->securitypriv.tkip_timer); | |
268 | del_timer_sync(&padapter->mlmepriv.scan_to_timer); | |
269 | del_timer_sync(&padapter->mlmepriv.dhcp_timer); | |
270 | del_timer_sync(&padapter->mlmepriv.wdg_timer); | |
271 | del_timer_sync(&padapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer); | |
2865d42c LF |
272 | } |
273 | ||
274 | static u8 init_default_value(struct _adapter *padapter) | |
275 | { | |
276 | u8 ret = _SUCCESS; | |
277 | struct registry_priv *pregistrypriv = &padapter->registrypriv; | |
278 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
279 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
280 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
281 | ||
282 | /*xmit_priv*/ | |
283 | pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; | |
284 | pxmitpriv->vcs = pregistrypriv->vcs_type; | |
285 | pxmitpriv->vcs_type = pregistrypriv->vcs_type; | |
286 | pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; | |
287 | pxmitpriv->frag_len = pregistrypriv->frag_thresh; | |
ee5b1aad AB |
288 | /* mlme_priv */ |
289 | /* Maybe someday we should rename this variable to "active_mode"(Jeff)*/ | |
290 | pmlmepriv->passive_mode = 1; /* 1: active, 0: passive. */ | |
2865d42c LF |
291 | /*ht_priv*/ |
292 | { | |
293 | int i; | |
294 | struct ht_priv *phtpriv = &pmlmepriv->htpriv; | |
295 | ||
296 | phtpriv->ampdu_enable = false;/*set to disabled*/ | |
297 | for (i = 0; i < 16; i++) | |
298 | phtpriv->baddbareq_issued[i] = false; | |
299 | } | |
300 | /*security_priv*/ | |
301 | psecuritypriv->sw_encrypt = pregistrypriv->software_encrypt; | |
302 | psecuritypriv->sw_decrypt = pregistrypriv->software_decrypt; | |
303 | psecuritypriv->binstallGrpkey = _FAIL; | |
304 | /*pwrctrl_priv*/ | |
305 | /*registry_priv*/ | |
306 | r8712_init_registrypriv_dev_network(padapter); | |
307 | r8712_update_registrypriv_dev_network(padapter); | |
308 | /*misc.*/ | |
309 | return ret; | |
310 | } | |
311 | ||
312 | u8 r8712_init_drv_sw(struct _adapter *padapter) | |
313 | { | |
314 | if ((r8712_init_cmd_priv(&padapter->cmdpriv)) == _FAIL) | |
315 | return _FAIL; | |
316 | padapter->cmdpriv.padapter = padapter; | |
317 | if ((r8712_init_evt_priv(&padapter->evtpriv)) == _FAIL) | |
318 | return _FAIL; | |
319 | if (r8712_init_mlme_priv(padapter) == _FAIL) | |
320 | return _FAIL; | |
321 | _r8712_init_xmit_priv(&padapter->xmitpriv, padapter); | |
322 | _r8712_init_recv_priv(&padapter->recvpriv, padapter); | |
323 | memset((unsigned char *)&padapter->securitypriv, 0, | |
324 | sizeof(struct security_priv)); | |
e922df7d VT |
325 | setup_timer(&padapter->securitypriv.tkip_timer, |
326 | r8712_use_tkipkey_handler, (unsigned long)padapter); | |
2865d42c LF |
327 | _r8712_init_sta_priv(&padapter->stapriv); |
328 | padapter->stapriv.padapter = padapter; | |
329 | r8712_init_bcmc_stainfo(padapter); | |
330 | r8712_init_pwrctrl_priv(padapter); | |
2865d42c LF |
331 | mp871xinit(padapter); |
332 | if (init_default_value(padapter) != _SUCCESS) | |
333 | return _FAIL; | |
334 | r8712_InitSwLeds(padapter); | |
335 | return _SUCCESS; | |
336 | } | |
337 | ||
338 | u8 r8712_free_drv_sw(struct _adapter *padapter) | |
339 | { | |
340 | struct net_device *pnetdev = (struct net_device *)padapter->pnetdev; | |
341 | ||
342 | r8712_free_cmd_priv(&padapter->cmdpriv); | |
343 | r8712_free_evt_priv(&padapter->evtpriv); | |
344 | r8712_DeInitSwLeds(padapter); | |
345 | r8712_free_mlme_priv(&padapter->mlmepriv); | |
346 | r8712_free_io_queue(padapter); | |
347 | _free_xmit_priv(&padapter->xmitpriv); | |
22649bb2 | 348 | _r8712_free_sta_priv(&padapter->stapriv); |
2865d42c LF |
349 | _r8712_free_recv_priv(&padapter->recvpriv); |
350 | mp871xdeinit(padapter); | |
351 | if (pnetdev) | |
7bcd9ce6 | 352 | free_netdev(pnetdev); |
2865d42c LF |
353 | return _SUCCESS; |
354 | } | |
355 | ||
356 | ||
357 | static void enable_video_mode(struct _adapter *padapter, int cbw40_value) | |
358 | { | |
359 | /* bit 8: | |
360 | * 1 -> enable video mode to 96B AP | |
361 | * 0 -> disable video mode to 96B AP | |
362 | * bit 9: | |
363 | * 1 -> enable 40MHz mode | |
364 | * 0 -> disable 40MHz mode | |
365 | * bit 10: | |
366 | * 1 -> enable STBC | |
367 | * 0 -> disable STBC | |
368 | */ | |
369 | u32 intcmd = 0xf4000500; /* enable bit8, bit10*/ | |
370 | ||
371 | if (cbw40_value) { | |
372 | /* if the driver supports the 40M bandwidth, | |
373 | * we can enable the bit 9.*/ | |
374 | intcmd |= 0x200; | |
375 | } | |
376 | r8712_fw_cmd(padapter, intcmd); | |
377 | } | |
378 | ||
a5ee6529 AB |
379 | /** |
380 | * | |
381 | * This function intends to handle the activation of an interface | |
382 | * i.e. when it is brought Up/Active from a Down state. | |
383 | * | |
384 | */ | |
2865d42c LF |
385 | static int netdev_open(struct net_device *pnetdev) |
386 | { | |
8f47c28b | 387 | struct _adapter *padapter = netdev_priv(pnetdev); |
2865d42c | 388 | |
8c213fa5 | 389 | mutex_lock(&padapter->mutex_start); |
2865d42c LF |
390 | if (padapter->bup == false) { |
391 | padapter->bDriverStopped = false; | |
392 | padapter->bSurpriseRemoved = false; | |
393 | padapter->bup = true; | |
394 | if (rtl871x_hal_init(padapter) != _SUCCESS) | |
395 | goto netdev_open_error; | |
396 | if (r8712_initmac == NULL) | |
397 | /* Use the mac address stored in the Efuse */ | |
398 | memcpy(pnetdev->dev_addr, | |
399 | padapter->eeprompriv.mac_addr, ETH_ALEN); | |
400 | else { | |
401 | /* We have to inform f/w to use user-supplied MAC | |
402 | * address. | |
403 | */ | |
404 | msleep(200); | |
405 | r8712_setMacAddr_cmd(padapter, (u8 *)pnetdev->dev_addr); | |
406 | /* | |
407 | * The "myid" function will get the wifi mac address | |
408 | * from eeprompriv structure instead of netdev | |
409 | * structure. So, we have to overwrite the mac_addr | |
410 | * stored in the eeprompriv structure. In this case, | |
411 | * the real mac address won't be used anymore. So that, | |
412 | * the eeprompriv.mac_addr should store the mac which | |
413 | * users specify. | |
414 | */ | |
415 | memcpy(padapter->eeprompriv.mac_addr, | |
416 | pnetdev->dev_addr, ETH_ALEN); | |
417 | } | |
418 | if (start_drv_threads(padapter) != _SUCCESS) | |
419 | goto netdev_open_error; | |
420 | if (padapter->dvobjpriv.inirp_init == NULL) | |
421 | goto netdev_open_error; | |
422 | else | |
423 | padapter->dvobjpriv.inirp_init(padapter); | |
424 | r8712_set_ps_mode(padapter, padapter->registrypriv.power_mgnt, | |
425 | padapter->registrypriv.smart_ps); | |
426 | } | |
427 | if (!netif_queue_stopped(pnetdev)) | |
428 | netif_start_queue(pnetdev); | |
429 | else | |
430 | netif_wake_queue(pnetdev); | |
431 | ||
432 | if (video_mode) | |
433 | enable_video_mode(padapter, cbw40_enable); | |
434 | /* start driver mlme relation timer */ | |
435 | start_drv_timers(padapter); | |
436 | padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK); | |
8c213fa5 | 437 | mutex_unlock(&padapter->mutex_start); |
2865d42c LF |
438 | return 0; |
439 | netdev_open_error: | |
440 | padapter->bup = false; | |
441 | netif_carrier_off(pnetdev); | |
442 | netif_stop_queue(pnetdev); | |
8c213fa5 | 443 | mutex_unlock(&padapter->mutex_start); |
2865d42c LF |
444 | return -1; |
445 | } | |
446 | ||
a5ee6529 AB |
447 | /** |
448 | * | |
449 | * This function intends to handle the shutdown of an interface | |
450 | * i.e. when it is brought Down from an Up/Active state. | |
451 | * | |
452 | */ | |
2865d42c LF |
453 | static int netdev_close(struct net_device *pnetdev) |
454 | { | |
8f47c28b | 455 | struct _adapter *padapter = netdev_priv(pnetdev); |
2865d42c LF |
456 | |
457 | /* Close LED*/ | |
458 | padapter->ledpriv.LedControlHandler(padapter, LED_CTL_POWER_OFF); | |
459 | msleep(200); | |
460 | ||
461 | /*s1.*/ | |
462 | if (pnetdev) { | |
463 | if (!netif_queue_stopped(pnetdev)) | |
464 | netif_stop_queue(pnetdev); | |
465 | } | |
466 | /*s2.*/ | |
467 | /*s2-1. issue disassoc_cmd to fw*/ | |
468 | r8712_disassoc_cmd(padapter); | |
469 | /*s2-2. indicate disconnect to os*/ | |
470 | r8712_ind_disconnect(padapter); | |
471 | /*s2-3.*/ | |
472 | r8712_free_assoc_resources(padapter); | |
473 | /*s2-4.*/ | |
474 | r8712_free_network_queue(padapter); | |
2865d42c LF |
475 | return 0; |
476 | } | |
477 | ||
478 | #include "mlme_osdep.h" |