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