1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  ******************************************************************************/
15 #define _HCI_INTF_C_
16 
17 #include <drv_types.h>
18 #include <rtw_debug.h>
19 #include <linux/jiffies.h>
20 
21 #ifndef dev_to_sdio_func
22 #define dev_to_sdio_func(d)     container_of(d, struct sdio_func, dev)
23 #endif
24 
25 static const struct sdio_device_id sdio_ids[] =
26 {
27 	{ SDIO_DEVICE(0x024c, 0x0523), },
28 	{ SDIO_DEVICE(0x024c, 0x0623), },
29 	{ SDIO_DEVICE(0x024c, 0x0626), },
30 	{ SDIO_DEVICE(0x024c, 0xb723), },
31 	{ /* end: all zeroes */				},
32 };
33 static const struct acpi_device_id acpi_ids[] = {
34 	{"OBDA8723", 0x0000},
35 	{}
36 };
37 
38 MODULE_DEVICE_TABLE(sdio, sdio_ids);
39 MODULE_DEVICE_TABLE(acpi, acpi_ids);
40 
41 static int rtw_drv_init(struct sdio_func *func, const struct sdio_device_id *id);
42 static void rtw_dev_remove(struct sdio_func *func);
43 static int rtw_sdio_resume(struct device *dev);
44 static int rtw_sdio_suspend(struct device *dev);
45 
46 static const struct dev_pm_ops rtw_sdio_pm_ops = {
47 	.suspend	= rtw_sdio_suspend,
48 	.resume	= rtw_sdio_resume,
49 };
50 
51 struct sdio_drv_priv {
52 	struct sdio_driver r871xs_drv;
53 	int drv_registered;
54 };
55 
56 static struct sdio_drv_priv sdio_drvpriv = {
57 	.r871xs_drv.probe = rtw_drv_init,
58 	.r871xs_drv.remove = rtw_dev_remove,
59 	.r871xs_drv.name = "rtl8723bs",
60 	.r871xs_drv.id_table = sdio_ids,
61 	.r871xs_drv.drv = {
62 		.pm = &rtw_sdio_pm_ops,
63 	}
64 };
65 
66 static void sd_sync_int_hdl(struct sdio_func *func)
67 {
68 	struct dvobj_priv *psdpriv;
69 
70 
71 	psdpriv = sdio_get_drvdata(func);
72 
73 	if (!psdpriv->if1) {
74 		DBG_871X("%s if1 == NULL\n", __func__);
75 		return;
76 	}
77 
78 	rtw_sdio_set_irq_thd(psdpriv, current);
79 	sd_int_hdl(psdpriv->if1);
80 	rtw_sdio_set_irq_thd(psdpriv, NULL);
81 }
82 
83 static int sdio_alloc_irq(struct dvobj_priv *dvobj)
84 {
85 	PSDIO_DATA psdio_data;
86 	struct sdio_func *func;
87 	int err;
88 
89 	psdio_data = &dvobj->intf_data;
90 	func = psdio_data->func;
91 
92 	sdio_claim_host(func);
93 
94 	err = sdio_claim_irq(func, &sd_sync_int_hdl);
95 	if (err)
96 	{
97 		dvobj->drv_dbg.dbg_sdio_alloc_irq_error_cnt++;
98 		printk(KERN_CRIT "%s: sdio_claim_irq FAIL(%d)!\n", __func__, err);
99 	}
100 	else
101 	{
102 		dvobj->drv_dbg.dbg_sdio_alloc_irq_cnt++;
103 		dvobj->irq_alloc = 1;
104 	}
105 
106 	sdio_release_host(func);
107 
108 	return err?_FAIL:_SUCCESS;
109 }
110 
111 static void sdio_free_irq(struct dvobj_priv *dvobj)
112 {
113     PSDIO_DATA psdio_data;
114     struct sdio_func *func;
115     int err;
116 
117     if (dvobj->irq_alloc) {
118         psdio_data = &dvobj->intf_data;
119         func = psdio_data->func;
120 
121         if (func) {
122             sdio_claim_host(func);
123             err = sdio_release_irq(func);
124             if (err)
125             {
126 				dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++;
127 				DBG_871X_LEVEL(_drv_err_,"%s: sdio_release_irq FAIL(%d)!\n", __func__, err);
128             }
129             else
130 		dvobj->drv_dbg.dbg_sdio_free_irq_cnt++;
131             sdio_release_host(func);
132         }
133         dvobj->irq_alloc = 0;
134     }
135 }
136 
137 #ifdef CONFIG_GPIO_WAKEUP
138 extern unsigned int oob_irq;
139 static irqreturn_t gpio_hostwakeup_irq_thread(int irq, void *data)
140 {
141 	struct adapter *padapter = data;
142 	DBG_871X_LEVEL(_drv_always_, "gpio_hostwakeup_irq_thread\n");
143 	/* Disable interrupt before calling handler */
144 	/* disable_irq_nosync(oob_irq); */
145 	rtw_lock_suspend_timeout(HZ/2);
146 	return IRQ_HANDLED;
147 }
148 
149 static u8 gpio_hostwakeup_alloc_irq(struct adapter *padapter)
150 {
151 	int err;
152 	if (oob_irq == 0) {
153 		DBG_871X("oob_irq ZERO!\n");
154 		return _FAIL;
155 	}
156 	/* dont set it IRQF_TRIGGER_LOW, or wowlan */
157 	/* power is high after suspend */
158 	/* and failing can prevent can not sleep issue if */
159 	/* wifi gpio12 pin is not linked with CPU */
160 	err = request_threaded_irq(oob_irq, gpio_hostwakeup_irq_thread, NULL,
161 		/* IRQF_TRIGGER_LOW | IRQF_ONESHOT, */
162 		IRQF_TRIGGER_FALLING,
163 		"rtw_wifi_gpio_wakeup", padapter);
164 	if (err < 0) {
165 		DBG_871X("Oops: can't allocate gpio irq %d err:%d\n", oob_irq, err);
166 		return false;
167 	} else {
168 		DBG_871X("allocate gpio irq %d ok\n", oob_irq);
169 	}
170 
171 	enable_irq_wake(oob_irq);
172 	return _SUCCESS;
173 }
174 
175 static void gpio_hostwakeup_free_irq(struct adapter *padapter)
176 {
177 	if (oob_irq == 0)
178 		return;
179 
180 	disable_irq_wake(oob_irq);
181 	free_irq(oob_irq, padapter);
182 }
183 #endif
184 
185 static u32 sdio_init(struct dvobj_priv *dvobj)
186 {
187 	PSDIO_DATA psdio_data;
188 	struct sdio_func *func;
189 	int err;
190 
191 	psdio_data = &dvobj->intf_data;
192 	func = psdio_data->func;
193 
194 	/* 3 1. init SDIO bus */
195 	sdio_claim_host(func);
196 
197 	err = sdio_enable_func(func);
198 	if (err) {
199 		dvobj->drv_dbg.dbg_sdio_init_error_cnt++;
200 		DBG_8192C(KERN_CRIT "%s: sdio_enable_func FAIL(%d)!\n", __func__, err);
201 		goto release;
202 	}
203 
204 	err = sdio_set_block_size(func, 512);
205 	if (err) {
206 		dvobj->drv_dbg.dbg_sdio_init_error_cnt++;
207 		DBG_8192C(KERN_CRIT "%s: sdio_set_block_size FAIL(%d)!\n", __func__, err);
208 		goto release;
209 	}
210 	psdio_data->block_transfer_len = 512;
211 	psdio_data->tx_block_mode = 1;
212 	psdio_data->rx_block_mode = 1;
213 
214 release:
215 	sdio_release_host(func);
216 
217 	if (err)
218 		return _FAIL;
219 	return _SUCCESS;
220 }
221 
222 static void sdio_deinit(struct dvobj_priv *dvobj)
223 {
224 	struct sdio_func *func;
225 	int err;
226 
227 
228 	RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+sdio_deinit\n"));
229 
230 	func = dvobj->intf_data.func;
231 
232 	if (func) {
233 		sdio_claim_host(func);
234 		err = sdio_disable_func(func);
235 		if (err)
236 		{
237 			dvobj->drv_dbg.dbg_sdio_deinit_error_cnt++;
238 			DBG_8192C(KERN_ERR "%s: sdio_disable_func(%d)\n", __func__, err);
239 		}
240 
241 		if (dvobj->irq_alloc) {
242 			err = sdio_release_irq(func);
243 			if (err)
244 			{
245 				dvobj->drv_dbg.dbg_sdio_free_irq_error_cnt++;
246 				DBG_8192C(KERN_ERR "%s: sdio_release_irq(%d)\n", __func__, err);
247 			}
248 			else
249 				dvobj->drv_dbg.dbg_sdio_free_irq_cnt++;
250 		}
251 
252 		sdio_release_host(func);
253 	}
254 }
255 static struct dvobj_priv *sdio_dvobj_init(struct sdio_func *func)
256 {
257 	int status = _FAIL;
258 	struct dvobj_priv *dvobj = NULL;
259 	PSDIO_DATA psdio;
260 
261 	dvobj = devobj_init();
262 	if (dvobj == NULL) {
263 		goto exit;
264 	}
265 
266 	sdio_set_drvdata(func, dvobj);
267 
268 	psdio = &dvobj->intf_data;
269 	psdio->func = func;
270 
271 	if (sdio_init(dvobj) != _SUCCESS) {
272 		RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!\n", __func__));
273 		goto free_dvobj;
274 	}
275 	rtw_reset_continual_io_error(dvobj);
276 	status = _SUCCESS;
277 
278 free_dvobj:
279 	if (status != _SUCCESS && dvobj) {
280 		sdio_set_drvdata(func, NULL);
281 
282 		devobj_deinit(dvobj);
283 
284 		dvobj = NULL;
285 	}
286 exit:
287 	return dvobj;
288 }
289 
290 static void sdio_dvobj_deinit(struct sdio_func *func)
291 {
292 	struct dvobj_priv *dvobj = sdio_get_drvdata(func);
293 
294 	sdio_set_drvdata(func, NULL);
295 	if (dvobj) {
296 		sdio_deinit(dvobj);
297 		devobj_deinit(dvobj);
298 	}
299 	return;
300 }
301 
302 void rtw_set_hal_ops(struct adapter *padapter)
303 {
304 	/* alloc memory for HAL DATA */
305 	rtw_hal_data_init(padapter);
306 
307 	rtl8723bs_set_hal_ops(padapter);
308 }
309 
310 static void sd_intf_start(struct adapter *padapter)
311 {
312 	if (padapter == NULL) {
313 		DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__);
314 		return;
315 	}
316 
317 	/*  hal dep */
318 	rtw_hal_enable_interrupt(padapter);
319 }
320 
321 static void sd_intf_stop(struct adapter *padapter)
322 {
323 	if (padapter == NULL) {
324 		DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__);
325 		return;
326 	}
327 
328 	/*  hal dep */
329 	rtw_hal_disable_interrupt(padapter);
330 }
331 
332 
333 static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct sdio_device_id  *pdid)
334 {
335 	int status = _FAIL;
336 	struct net_device *pnetdev;
337 	struct adapter *padapter = NULL;
338 	PSDIO_DATA psdio = &dvobj->intf_data;
339 
340 	padapter = (struct adapter *)vzalloc(sizeof(*padapter));
341 	if (padapter == NULL) {
342 		goto exit;
343 	}
344 
345 	padapter->dvobj = dvobj;
346 	dvobj->if1 = padapter;
347 
348 	padapter->bDriverStopped =true;
349 
350 	dvobj->padapters = padapter;
351 	padapter->iface_id = 0;
352 
353 	/* 3 1. init network device data */
354 	pnetdev = rtw_init_netdev(padapter);
355 	if (!pnetdev)
356 		goto free_adapter;
357 
358 	SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj));
359 
360 	padapter = rtw_netdev_priv(pnetdev);
361 
362 	rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj));
363 
364 	/* 3 3. init driver special setting, interface, OS and hardware relative */
365 
366 	/* 4 3.1 set hardware operation functions */
367 	rtw_set_hal_ops(padapter);
368 
369 
370 	/* 3 5. initialize Chip version */
371 	padapter->intf_start = &sd_intf_start;
372 	padapter->intf_stop = &sd_intf_stop;
373 
374 	padapter->intf_init = &sdio_init;
375 	padapter->intf_deinit = &sdio_deinit;
376 	padapter->intf_alloc_irq = &sdio_alloc_irq;
377 	padapter->intf_free_irq = &sdio_free_irq;
378 
379 	if (rtw_init_io_priv(padapter, sdio_set_intf_ops) == _FAIL)
380 	{
381 		RT_TRACE(_module_hci_intfs_c_, _drv_err_,
382 			("rtw_drv_init: Can't init io_priv\n"));
383 		goto free_hal_data;
384 	}
385 
386 	rtw_hal_read_chip_version(padapter);
387 
388 	rtw_hal_chip_configure(padapter);
389 
390 	rtw_btcoex_Initialize(padapter);
391 
392 	/* 3 6. read efuse/eeprom data */
393 	rtw_hal_read_chip_info(padapter);
394 
395 	/* 3 7. init driver common data */
396 	if (rtw_init_drv_sw(padapter) == _FAIL) {
397 		RT_TRACE(_module_hci_intfs_c_, _drv_err_,
398 			 ("rtw_drv_init: Initialize driver software resource Failed!\n"));
399 		goto free_hal_data;
400 	}
401 
402 	/* 3 8. get WLan MAC address */
403 	/*  set mac addr */
404 	rtw_macaddr_cfg(&psdio->func->dev, padapter->eeprompriv.mac_addr);
405 
406 	rtw_hal_disable_interrupt(padapter);
407 
408 	DBG_871X("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n"
409 		, padapter->bDriverStopped
410 		, padapter->bSurpriseRemoved
411 		, padapter->bup
412 		, padapter->hw_init_completed
413 	);
414 
415 	status = _SUCCESS;
416 
417 free_hal_data:
418 	if (status != _SUCCESS && padapter->HalData)
419 		kfree(padapter->HalData);
420 
421 	if (status != _SUCCESS) {
422 		rtw_wdev_unregister(padapter->rtw_wdev);
423 		rtw_wdev_free(padapter->rtw_wdev);
424 	}
425 
426 free_adapter:
427 	if (status != _SUCCESS) {
428 		if (pnetdev)
429 			rtw_free_netdev(pnetdev);
430 		else
431 			vfree((u8 *)padapter);
432 		padapter = NULL;
433 	}
434 exit:
435 	return padapter;
436 }
437 
438 static void rtw_sdio_if1_deinit(struct adapter *if1)
439 {
440 	struct net_device *pnetdev = if1->pnetdev;
441 	struct mlme_priv *pmlmepriv = &if1->mlmepriv;
442 
443 	if (check_fwstate(pmlmepriv, _FW_LINKED))
444 		rtw_disassoc_cmd(if1, 0, false);
445 
446 	free_mlme_ap_info(if1);
447 
448 #ifdef CONFIG_GPIO_WAKEUP
449 	gpio_hostwakeup_free_irq(if1);
450 #endif
451 
452 	rtw_cancel_all_timer(if1);
453 
454 #ifdef CONFIG_WOWLAN
455 	adapter_to_pwrctl(if1)->wowlan_mode =false;
456 	DBG_871X_LEVEL(_drv_always_, "%s wowlan_mode:%d\n", __func__, adapter_to_pwrctl(if1)->wowlan_mode);
457 #endif /* CONFIG_WOWLAN */
458 
459 	rtw_dev_unload(if1);
460 	DBG_871X("+r871xu_dev_remove, hw_init_completed =%d\n", if1->hw_init_completed);
461 
462 	if (if1->rtw_wdev) {
463 		rtw_wdev_free(if1->rtw_wdev);
464 	}
465 
466 	rtw_free_drv_sw(if1);
467 
468 	if (pnetdev)
469 		rtw_free_netdev(pnetdev);
470 }
471 
472 /*
473  * drv_init() - a device potentially for us
474  *
475  * notes: drv_init() is called when the bus driver has located a card for us to support.
476  *        We accept the new device by returning 0.
477  */
478 static int rtw_drv_init(
479 	struct sdio_func *func,
480 	const struct sdio_device_id *id)
481 {
482 	int status = _FAIL;
483 	struct adapter *if1 = NULL, *if2 = NULL;
484 	struct dvobj_priv *dvobj;
485 
486 	dvobj = sdio_dvobj_init(func);
487 	if (dvobj == NULL) {
488 		RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("initialize device object priv Failed!\n"));
489 		goto exit;
490 	}
491 
492 	if1 = rtw_sdio_if1_init(dvobj, id);
493 	if (if1 == NULL) {
494 		DBG_871X("rtw_init_primarystruct adapter Failed!\n");
495 		goto free_dvobj;
496 	}
497 
498 	/* dev_alloc_name && register_netdev */
499 	status = rtw_drv_register_netdev(if1);
500 	if (status != _SUCCESS) {
501 		goto free_if2;
502 	}
503 
504 	if (sdio_alloc_irq(dvobj) != _SUCCESS)
505 		goto free_if2;
506 
507 #ifdef	CONFIG_GPIO_WAKEUP
508 	gpio_hostwakeup_alloc_irq(if1);
509 #endif
510 
511 	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-871x_drv - drv_init, success!\n"));
512 
513 	rtw_ndev_notifier_register();
514 	status = _SUCCESS;
515 
516 free_if2:
517 	if (status != _SUCCESS && if2) {
518 	}
519 	if (status != _SUCCESS && if1) {
520 		rtw_sdio_if1_deinit(if1);
521 	}
522 free_dvobj:
523 	if (status != _SUCCESS)
524 		sdio_dvobj_deinit(func);
525 exit:
526 	return status == _SUCCESS?0:-ENODEV;
527 }
528 
529 static void rtw_dev_remove(struct sdio_func *func)
530 {
531 	struct dvobj_priv *dvobj = sdio_get_drvdata(func);
532 	struct adapter *padapter = dvobj->if1;
533 
534 	RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_remove\n"));
535 
536 	dvobj->processing_dev_remove = true;
537 
538 	rtw_unregister_netdevs(dvobj);
539 
540 	if (padapter->bSurpriseRemoved == false) {
541 		int err;
542 
543 		/* test surprise remove */
544 		sdio_claim_host(func);
545 		sdio_readb(func, 0, &err);
546 		sdio_release_host(func);
547 		if (err == -ENOMEDIUM) {
548 			padapter->bSurpriseRemoved = true;
549 			DBG_871X(KERN_NOTICE "%s: device had been removed!\n", __func__);
550 		}
551 	}
552 
553 	rtw_ps_deny(padapter, PS_DENY_DRV_REMOVE);
554 
555 	rtw_pm_set_ips(padapter, IPS_NONE);
556 	rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
557 
558 	LeaveAllPowerSaveMode(padapter);
559 
560 	rtw_btcoex_HaltNotify(padapter);
561 
562 	rtw_sdio_if1_deinit(padapter);
563 
564 	sdio_dvobj_deinit(func);
565 
566 	RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_remove\n"));
567 }
568 
569 extern int pm_netdev_open(struct net_device *pnetdev, u8 bnormal);
570 extern int pm_netdev_close(struct net_device *pnetdev, u8 bnormal);
571 
572 static int rtw_sdio_suspend(struct device *dev)
573 {
574 	struct sdio_func *func =dev_to_sdio_func(dev);
575 	struct dvobj_priv *psdpriv = sdio_get_drvdata(func);
576 	struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv);
577 	struct adapter *padapter = psdpriv->if1;
578 	struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
579 
580 	if (padapter->bDriverStopped == true)
581 	{
582 		DBG_871X("%s bDriverStopped = %d\n", __func__, padapter->bDriverStopped);
583 		return 0;
584 	}
585 
586 	if (pwrpriv->bInSuspend == true)
587 	{
588 		DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend);
589 		pdbgpriv->dbg_suspend_error_cnt++;
590 		return 0;
591 	}
592 
593 	return rtw_suspend_common(padapter);
594 }
595 
596 static int rtw_resume_process(struct adapter *padapter)
597 {
598 	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
599 	struct dvobj_priv *psdpriv = padapter->dvobj;
600 	struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
601 
602 	if (pwrpriv->bInSuspend == false)
603 	{
604 		pdbgpriv->dbg_resume_error_cnt++;
605 		DBG_871X("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend);
606 		return -1;
607 	}
608 
609 	return rtw_resume_common(padapter);
610 }
611 
612 static int rtw_sdio_resume(struct device *dev)
613 {
614 	struct sdio_func *func =dev_to_sdio_func(dev);
615 	struct dvobj_priv *psdpriv = sdio_get_drvdata(func);
616 	struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv);
617 	struct adapter *padapter = psdpriv->if1;
618 	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
619 	int ret = 0;
620 	struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
621 
622 	DBG_871X("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
623 
624 	pdbgpriv->dbg_resume_cnt++;
625 
626 	if (pwrpriv->bInternalAutoSuspend)
627 	{
628 		ret = rtw_resume_process(padapter);
629 	}
630 	else
631 	{
632 		if (pwrpriv->wowlan_mode || pwrpriv->wowlan_ap_mode)
633 		{
634 			ret = rtw_resume_process(padapter);
635 		}
636 		else
637 		{
638 			ret = rtw_resume_process(padapter);
639 		}
640 	}
641 	pmlmeext->last_scan_time = jiffies;
642 	DBG_871X("<========  %s return %d\n", __func__, ret);
643 	return ret;
644 
645 }
646 
647 static int __init rtw_drv_entry(void)
648 {
649 	int ret = 0;
650 
651 	DBG_871X_LEVEL(_drv_always_, "module init start\n");
652 	dump_drv_version(RTW_DBGDUMP);
653 #ifdef BTCOEXVERSION
654 	DBG_871X_LEVEL(_drv_always_, "rtl8723bs BT-Coex version = %s\n", BTCOEXVERSION);
655 #endif /*  BTCOEXVERSION */
656 
657 	sdio_drvpriv.drv_registered = true;
658 	rtw_drv_proc_init();
659 
660 	ret = sdio_register_driver(&sdio_drvpriv.r871xs_drv);
661 	if (ret != 0)
662 	{
663 		sdio_drvpriv.drv_registered = false;
664 		rtw_drv_proc_deinit();
665 		rtw_ndev_notifier_unregister();
666 		DBG_871X("%s: register driver failed!!(%d)\n", __func__, ret);
667 		goto exit;
668 	}
669 
670 	goto exit;
671 
672 exit:
673 	DBG_871X_LEVEL(_drv_always_, "module init ret =%d\n", ret);
674 	return ret;
675 }
676 
677 static void __exit rtw_drv_halt(void)
678 {
679 	DBG_871X_LEVEL(_drv_always_, "module exit start\n");
680 
681 	sdio_drvpriv.drv_registered = false;
682 
683 	sdio_unregister_driver(&sdio_drvpriv.r871xs_drv);
684 
685 	rtw_drv_proc_deinit();
686 	rtw_ndev_notifier_unregister();
687 
688 	DBG_871X_LEVEL(_drv_always_, "module exit success\n");
689 
690 	rtw_mstat_dump(RTW_DBGDUMP);
691 }
692 
693 
694 module_init(rtw_drv_entry);
695 module_exit(rtw_drv_halt);
696