diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/main.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/main.c | 266 |
1 files changed, 53 insertions, 213 deletions
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 48b4d95219fb..4c7491ec3f2b 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c | |||
@@ -26,21 +26,6 @@ | |||
26 | 26 | ||
27 | const char driver_version[] = "mwifiex " VERSION " (%s) "; | 27 | const char driver_version[] = "mwifiex " VERSION " (%s) "; |
28 | 28 | ||
29 | static struct mwifiex_bss_attr mwifiex_bss_sta[] = { | ||
30 | {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0}, | ||
31 | }; | ||
32 | |||
33 | static int drv_mode = DRV_MODE_STA; | ||
34 | |||
35 | /* Supported drv_mode table */ | ||
36 | static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { | ||
37 | { | ||
38 | .drv_mode = DRV_MODE_STA, | ||
39 | .intf_num = ARRAY_SIZE(mwifiex_bss_sta), | ||
40 | .bss_attr = mwifiex_bss_sta, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | /* | 29 | /* |
45 | * This function registers the device and performs all the necessary | 30 | * This function registers the device and performs all the necessary |
46 | * initializations. | 31 | * initializations. |
@@ -57,7 +42,6 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { | |||
57 | * proper cleanup before exiting. | 42 | * proper cleanup before exiting. |
58 | */ | 43 | */ |
59 | static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, | 44 | static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, |
60 | struct mwifiex_drv_mode *drv_mode_ptr, | ||
61 | void **padapter) | 45 | void **padapter) |
62 | { | 46 | { |
63 | struct mwifiex_adapter *adapter; | 47 | struct mwifiex_adapter *adapter; |
@@ -78,44 +62,20 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, | |||
78 | goto error; | 62 | goto error; |
79 | 63 | ||
80 | adapter->priv_num = 0; | 64 | adapter->priv_num = 0; |
81 | for (i = 0; i < drv_mode_ptr->intf_num; i++) { | ||
82 | adapter->priv[i] = NULL; | ||
83 | |||
84 | if (!drv_mode_ptr->bss_attr[i].active) | ||
85 | continue; | ||
86 | |||
87 | /* Allocate memory for private structure */ | ||
88 | adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), | ||
89 | GFP_KERNEL); | ||
90 | if (!adapter->priv[i]) { | ||
91 | dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n", | ||
92 | __func__, i); | ||
93 | goto error; | ||
94 | } | ||
95 | 65 | ||
96 | adapter->priv_num++; | 66 | /* Allocate memory for private structure */ |
97 | adapter->priv[i]->adapter = adapter; | 67 | adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private), |
98 | /* Save bss_type, frame_type & bss_priority */ | 68 | GFP_KERNEL); |
99 | adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type; | 69 | if (!adapter->priv[0]) { |
100 | adapter->priv[i]->frame_type = | 70 | dev_err(adapter->dev, "%s: failed to alloc priv[0]\n", |
101 | drv_mode_ptr->bss_attr[i].frame_type; | 71 | __func__); |
102 | adapter->priv[i]->bss_priority = | 72 | goto error; |
103 | drv_mode_ptr->bss_attr[i].bss_priority; | ||
104 | |||
105 | if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) | ||
106 | adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; | ||
107 | else if (drv_mode_ptr->bss_attr[i].bss_type == | ||
108 | MWIFIEX_BSS_TYPE_UAP) | ||
109 | adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; | ||
110 | |||
111 | /* Save bss_index & bss_num */ | ||
112 | adapter->priv[i]->bss_index = i; | ||
113 | adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num; | ||
114 | } | 73 | } |
115 | adapter->drv_mode = drv_mode_ptr; | ||
116 | 74 | ||
117 | if (mwifiex_init_lock_list(adapter)) | 75 | adapter->priv_num++; |
118 | goto error; | 76 | |
77 | adapter->priv[0]->adapter = adapter; | ||
78 | mwifiex_init_lock_list(adapter); | ||
119 | 79 | ||
120 | init_timer(&adapter->cmd_timer); | 80 | init_timer(&adapter->cmd_timer); |
121 | adapter->cmd_timer.function = mwifiex_cmd_timeout_func; | 81 | adapter->cmd_timer.function = mwifiex_cmd_timeout_func; |
@@ -126,9 +86,9 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, | |||
126 | error: | 86 | error: |
127 | dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); | 87 | dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); |
128 | 88 | ||
129 | mwifiex_free_lock_list(adapter); | 89 | for (i = 0; i < adapter->priv_num; i++) |
130 | for (i = 0; i < drv_mode_ptr->intf_num; i++) | ||
131 | kfree(adapter->priv[i]); | 90 | kfree(adapter->priv[i]); |
91 | |||
132 | kfree(adapter); | 92 | kfree(adapter); |
133 | 93 | ||
134 | return -1; | 94 | return -1; |
@@ -316,38 +276,6 @@ exit_main_proc: | |||
316 | } | 276 | } |
317 | 277 | ||
318 | /* | 278 | /* |
319 | * This function initializes the software. | ||
320 | * | ||
321 | * The main work includes allocating and initializing the adapter structure | ||
322 | * and initializing the private structures. | ||
323 | */ | ||
324 | static int | ||
325 | mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **padapter) | ||
326 | { | ||
327 | int i; | ||
328 | struct mwifiex_drv_mode *drv_mode_ptr; | ||
329 | |||
330 | /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ | ||
331 | drv_mode_ptr = NULL; | ||
332 | for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) { | ||
333 | if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) { | ||
334 | drv_mode_ptr = &mwifiex_drv_mode_tbl[i]; | ||
335 | break; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | if (!drv_mode_ptr) { | ||
340 | pr_err("invalid drv_mode=%d\n", drv_mode); | ||
341 | return -1; | ||
342 | } | ||
343 | |||
344 | if (mwifiex_register(card, if_ops, drv_mode_ptr, padapter)) | ||
345 | return -1; | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * This function frees the adapter structure. | 279 | * This function frees the adapter structure. |
352 | * | 280 | * |
353 | * Additionally, this closes the netlink socket, frees the timers | 281 | * Additionally, this closes the netlink socket, frees the timers |
@@ -649,8 +577,8 @@ static const struct net_device_ops mwifiex_netdev_ops = { | |||
649 | * | 577 | * |
650 | * In addition, the CFG80211 work queue is also created. | 578 | * In addition, the CFG80211 work queue is also created. |
651 | */ | 579 | */ |
652 | static void | 580 | void mwifiex_init_priv_params(struct mwifiex_private *priv, |
653 | mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) | 581 | struct net_device *dev) |
654 | { | 582 | { |
655 | dev->netdev_ops = &mwifiex_netdev_ops; | 583 | dev->netdev_ops = &mwifiex_netdev_ops; |
656 | /* Initialize private structure */ | 584 | /* Initialize private structure */ |
@@ -664,118 +592,6 @@ mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) | |||
664 | } | 592 | } |
665 | 593 | ||
666 | /* | 594 | /* |
667 | * This function adds a new logical interface. | ||
668 | * | ||
669 | * It allocates, initializes and registers the interface by performing | ||
670 | * the following opearations - | ||
671 | * - Allocate a new net device structure | ||
672 | * - Assign device name | ||
673 | * - Register the new device with CFG80211 subsystem | ||
674 | * - Initialize semaphore and private structure | ||
675 | * - Register the new device with kernel | ||
676 | * - Create the complete debug FS structure if configured | ||
677 | */ | ||
678 | static struct mwifiex_private *mwifiex_add_interface( | ||
679 | struct mwifiex_adapter *adapter, | ||
680 | u8 bss_index, u8 bss_type) | ||
681 | { | ||
682 | struct net_device *dev; | ||
683 | struct mwifiex_private *priv; | ||
684 | void *mdev_priv; | ||
685 | |||
686 | dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", | ||
687 | ether_setup, 1); | ||
688 | if (!dev) { | ||
689 | dev_err(adapter->dev, "no memory available for netdevice\n"); | ||
690 | goto error; | ||
691 | } | ||
692 | |||
693 | if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, | ||
694 | adapter->priv[bss_index]) != 0) { | ||
695 | dev_err(adapter->dev, "cannot register netdevice with cfg80211\n"); | ||
696 | goto error; | ||
697 | } | ||
698 | /* Save the priv pointer in netdev */ | ||
699 | priv = adapter->priv[bss_index]; | ||
700 | mdev_priv = netdev_priv(dev); | ||
701 | *((unsigned long *) mdev_priv) = (unsigned long) priv; | ||
702 | |||
703 | priv->netdev = dev; | ||
704 | |||
705 | sema_init(&priv->async_sem, 1); | ||
706 | priv->scan_pending_on_block = false; | ||
707 | |||
708 | mwifiex_init_priv_params(priv, dev); | ||
709 | |||
710 | SET_NETDEV_DEV(dev, adapter->dev); | ||
711 | |||
712 | /* Register network device */ | ||
713 | if (register_netdev(dev)) { | ||
714 | dev_err(adapter->dev, "cannot register virtual network device\n"); | ||
715 | goto error; | ||
716 | } | ||
717 | |||
718 | dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); | ||
719 | #ifdef CONFIG_DEBUG_FS | ||
720 | mwifiex_dev_debugfs_init(priv); | ||
721 | #endif | ||
722 | return priv; | ||
723 | error: | ||
724 | if (dev) | ||
725 | free_netdev(dev); | ||
726 | return NULL; | ||
727 | } | ||
728 | |||
729 | /* | ||
730 | * This function removes a logical interface. | ||
731 | * | ||
732 | * It deregisters, resets and frees the interface by performing | ||
733 | * the following operations - | ||
734 | * - Disconnect the device if connected, send wireless event to | ||
735 | * notify applications. | ||
736 | * - Remove the debug FS structure if configured | ||
737 | * - Unregister the device from kernel | ||
738 | * - Free the net device structure | ||
739 | * - Cancel all works and destroy work queue | ||
740 | * - Unregister and free the wireless device from CFG80211 subsystem | ||
741 | */ | ||
742 | static void | ||
743 | mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) | ||
744 | { | ||
745 | struct net_device *dev; | ||
746 | struct mwifiex_private *priv = adapter->priv[bss_index]; | ||
747 | |||
748 | if (!priv) | ||
749 | return; | ||
750 | dev = priv->netdev; | ||
751 | |||
752 | if (priv->media_connected) | ||
753 | priv->media_connected = false; | ||
754 | |||
755 | #ifdef CONFIG_DEBUG_FS | ||
756 | mwifiex_dev_debugfs_remove(priv); | ||
757 | #endif | ||
758 | /* Last reference is our one */ | ||
759 | dev_dbg(adapter->dev, "info: %s: refcnt = %d\n", | ||
760 | dev->name, netdev_refcnt_read(dev)); | ||
761 | |||
762 | if (dev->reg_state == NETREG_REGISTERED) | ||
763 | unregister_netdev(dev); | ||
764 | |||
765 | /* Clear the priv in adapter */ | ||
766 | priv->netdev = NULL; | ||
767 | if (dev) | ||
768 | free_netdev(dev); | ||
769 | |||
770 | cancel_work_sync(&priv->cfg_workqueue); | ||
771 | flush_workqueue(priv->workqueue); | ||
772 | destroy_workqueue(priv->workqueue); | ||
773 | wiphy_unregister(priv->wdev->wiphy); | ||
774 | wiphy_free(priv->wdev->wiphy); | ||
775 | kfree(priv->wdev); | ||
776 | } | ||
777 | |||
778 | /* | ||
779 | * This function check if command is pending. | 595 | * This function check if command is pending. |
780 | */ | 596 | */ |
781 | int is_command_pending(struct mwifiex_adapter *adapter) | 597 | int is_command_pending(struct mwifiex_adapter *adapter) |
@@ -847,14 +663,14 @@ int | |||
847 | mwifiex_add_card(void *card, struct semaphore *sem, | 663 | mwifiex_add_card(void *card, struct semaphore *sem, |
848 | struct mwifiex_if_ops *if_ops) | 664 | struct mwifiex_if_ops *if_ops) |
849 | { | 665 | { |
850 | int i; | ||
851 | struct mwifiex_adapter *adapter; | 666 | struct mwifiex_adapter *adapter; |
852 | char fmt[64]; | 667 | char fmt[64]; |
668 | struct mwifiex_private *priv; | ||
853 | 669 | ||
854 | if (down_interruptible(sem)) | 670 | if (down_interruptible(sem)) |
855 | goto exit_sem_err; | 671 | goto exit_sem_err; |
856 | 672 | ||
857 | if (mwifiex_init_sw(card, if_ops, (void **)&adapter)) { | 673 | if (mwifiex_register(card, if_ops, (void **)&adapter)) { |
858 | pr_err("%s: software init failed\n", __func__); | 674 | pr_err("%s: software init failed\n", __func__); |
859 | goto err_init_sw; | 675 | goto err_init_sw; |
860 | } | 676 | } |
@@ -888,14 +704,26 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
888 | goto err_init_fw; | 704 | goto err_init_fw; |
889 | } | 705 | } |
890 | 706 | ||
891 | /* Add interfaces */ | 707 | priv = adapter->priv[0]; |
892 | for (i = 0; i < adapter->drv_mode->intf_num; i++) { | 708 | |
893 | if (!mwifiex_add_interface(adapter, i, | 709 | if (mwifiex_register_cfg80211(priv) != 0) { |
894 | adapter->drv_mode->bss_attr[i].bss_type)) { | 710 | dev_err(adapter->dev, "cannot register netdevice" |
895 | goto err_add_intf; | 711 | " with cfg80211\n"); |
896 | } | 712 | goto err_init_fw; |
713 | } | ||
714 | |||
715 | rtnl_lock(); | ||
716 | /* Create station interface by default */ | ||
717 | if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d", | ||
718 | NL80211_IFTYPE_STATION, NULL, NULL)) { | ||
719 | rtnl_unlock(); | ||
720 | dev_err(adapter->dev, "cannot create default station" | ||
721 | " interface\n"); | ||
722 | goto err_add_intf; | ||
897 | } | 723 | } |
898 | 724 | ||
725 | rtnl_unlock(); | ||
726 | |||
899 | up(sem); | 727 | up(sem); |
900 | 728 | ||
901 | mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); | 729 | mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); |
@@ -904,8 +732,9 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
904 | return 0; | 732 | return 0; |
905 | 733 | ||
906 | err_add_intf: | 734 | err_add_intf: |
907 | for (i = 0; i < adapter->priv_num; i++) | 735 | rtnl_lock(); |
908 | mwifiex_remove_interface(adapter, i); | 736 | mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); |
737 | rtnl_unlock(); | ||
909 | err_init_fw: | 738 | err_init_fw: |
910 | pr_debug("info: %s: unregister device\n", __func__); | 739 | pr_debug("info: %s: unregister device\n", __func__); |
911 | adapter->if_ops.unregister_dev(adapter); | 740 | adapter->if_ops.unregister_dev(adapter); |
@@ -960,7 +789,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) | |||
960 | /* Stop data */ | 789 | /* Stop data */ |
961 | for (i = 0; i < adapter->priv_num; i++) { | 790 | for (i = 0; i < adapter->priv_num; i++) { |
962 | priv = adapter->priv[i]; | 791 | priv = adapter->priv[i]; |
963 | if (priv) { | 792 | if (priv && priv->netdev) { |
964 | if (!netif_queue_stopped(priv->netdev)) | 793 | if (!netif_queue_stopped(priv->netdev)) |
965 | netif_stop_queue(priv->netdev); | 794 | netif_stop_queue(priv->netdev); |
966 | if (netif_carrier_ok(priv->netdev)) | 795 | if (netif_carrier_ok(priv->netdev)) |
@@ -985,9 +814,20 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) | |||
985 | atomic_read(&adapter->cmd_pending)); | 814 | atomic_read(&adapter->cmd_pending)); |
986 | } | 815 | } |
987 | 816 | ||
988 | /* Remove interface */ | 817 | for (i = 0; i < adapter->priv_num; i++) { |
989 | for (i = 0; i < adapter->priv_num; i++) | 818 | priv = adapter->priv[i]; |
990 | mwifiex_remove_interface(adapter, i); | 819 | |
820 | if (!priv) | ||
821 | continue; | ||
822 | |||
823 | rtnl_lock(); | ||
824 | mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); | ||
825 | rtnl_unlock(); | ||
826 | } | ||
827 | |||
828 | wiphy_unregister(priv->wdev->wiphy); | ||
829 | wiphy_free(priv->wdev->wiphy); | ||
830 | kfree(priv->wdev); | ||
991 | 831 | ||
992 | mwifiex_terminate_workqueue(adapter); | 832 | mwifiex_terminate_workqueue(adapter); |
993 | 833 | ||