aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/if_sdio.c
diff options
context:
space:
mode:
authorBing Zhao <bzhao@marvell.com>2009-06-01 21:04:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-06-03 14:05:16 -0400
commit6bc61f4d8e2fa3d54017c29b58603e8771158a25 (patch)
treea527be05a193d1ef4b223322b4af6d83c69f64cb /drivers/net/wireless/libertas/if_sdio.c
parent328d84fb3614d006254c990a6224ce437147a5ac (diff)
libertas: improve function init/shutdown handling for SD8688
This patch is to incorporate Dan Williams' comments for commit: "libertas: implement function init/shutdown commands for SD8688" 1. remove fn_init_required and fn_shutdown_required variables from lbs_private structure. If required, __lbs_cmd() will be called directly to send function init/shutdown command for SD8688 in if_sdio_probe() or if_sdio_remove() callback. 2. add global variable "user_rmmod" to distinguish between the module removal case and the card removal case. This flag will be checked in if_sdio_remove() against SD8688 card to determine whether or not the function shutdown command needs to be sent. 3. remove "card" from if_sdio_model structure as it cannot store card pointers for multiple cards. Besides, it's no longer needed to store the "card" pointer with changes #1 & #2 above. Signed-off-by: Bing Zhao <bzhao@marvell.com> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/if_sdio.c')
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c76
1 files changed, 47 insertions, 29 deletions
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index a7e3fc119b70..8cdb88c6ca28 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -39,8 +39,24 @@
39#include "decl.h" 39#include "decl.h"
40#include "defs.h" 40#include "defs.h"
41#include "dev.h" 41#include "dev.h"
42#include "cmd.h"
42#include "if_sdio.h" 43#include "if_sdio.h"
43 44
45/* The if_sdio_remove() callback function is called when
46 * user removes this module from kernel space or ejects
47 * the card from the slot. The driver handles these 2 cases
48 * differently for SD8688 combo chip.
49 * If the user is removing the module, the FUNC_SHUTDOWN
50 * command for SD8688 is sent to the firmware.
51 * If the card is removed, there is no need to send this command.
52 *
53 * The variable 'user_rmmod' is used to distinguish these two
54 * scenarios. This flag is initialized as FALSE in case the card
55 * is removed, and will be set to TRUE for module removal when
56 * module_exit function is called.
57 */
58static u8 user_rmmod;
59
44static char *lbs_helper_name = NULL; 60static char *lbs_helper_name = NULL;
45module_param_named(helper_name, lbs_helper_name, charp, 0644); 61module_param_named(helper_name, lbs_helper_name, charp, 0644);
46 62
@@ -61,7 +77,6 @@ struct if_sdio_model {
61 int model; 77 int model;
62 const char *helper; 78 const char *helper;
63 const char *firmware; 79 const char *firmware;
64 struct if_sdio_card *card;
65}; 80};
66 81
67static struct if_sdio_model if_sdio_models[] = { 82static struct if_sdio_model if_sdio_models[] = {
@@ -70,21 +85,18 @@ static struct if_sdio_model if_sdio_models[] = {
70 .model = IF_SDIO_MODEL_8385, 85 .model = IF_SDIO_MODEL_8385,
71 .helper = "sd8385_helper.bin", 86 .helper = "sd8385_helper.bin",
72 .firmware = "sd8385.bin", 87 .firmware = "sd8385.bin",
73 .card = NULL,
74 }, 88 },
75 { 89 {
76 /* 8686 */ 90 /* 8686 */
77 .model = IF_SDIO_MODEL_8686, 91 .model = IF_SDIO_MODEL_8686,
78 .helper = "sd8686_helper.bin", 92 .helper = "sd8686_helper.bin",
79 .firmware = "sd8686.bin", 93 .firmware = "sd8686.bin",
80 .card = NULL,
81 }, 94 },
82 { 95 {
83 /* 8688 */ 96 /* 8688 */
84 .model = IF_SDIO_MODEL_8688, 97 .model = IF_SDIO_MODEL_8688,
85 .helper = "sd8688_helper.bin", 98 .helper = "sd8688_helper.bin",
86 .firmware = "sd8688.bin", 99 .firmware = "sd8688.bin",
87 .card = NULL,
88 }, 100 },
89}; 101};
90 102
@@ -927,8 +939,6 @@ static int if_sdio_probe(struct sdio_func *func,
927 goto free; 939 goto free;
928 } 940 }
929 941
930 if_sdio_models[i].card = card;
931
932 card->helper = if_sdio_models[i].helper; 942 card->helper = if_sdio_models[i].helper;
933 card->firmware = if_sdio_models[i].firmware; 943 card->firmware = if_sdio_models[i].firmware;
934 944
@@ -1014,8 +1024,16 @@ static int if_sdio_probe(struct sdio_func *func,
1014 /* 1024 /*
1015 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions 1025 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
1016 */ 1026 */
1017 priv->fn_init_required = 1027 if (card->model == IF_SDIO_MODEL_8688) {
1018 (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; 1028 struct cmd_header cmd;
1029
1030 memset(&cmd, 0, sizeof(cmd));
1031
1032 lbs_deb_sdio("send function INIT command\n");
1033 if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
1034 lbs_cmd_copyback, (unsigned long) &cmd))
1035 lbs_pr_alert("CMD_FUNC_INIT cmd failed\n");
1036 }
1019 1037
1020 ret = lbs_start_card(priv); 1038 ret = lbs_start_card(priv);
1021 if (ret) 1039 if (ret)
@@ -1057,30 +1075,39 @@ static void if_sdio_remove(struct sdio_func *func)
1057{ 1075{
1058 struct if_sdio_card *card; 1076 struct if_sdio_card *card;
1059 struct if_sdio_packet *packet; 1077 struct if_sdio_packet *packet;
1060 int ret;
1061 1078
1062 lbs_deb_enter(LBS_DEB_SDIO); 1079 lbs_deb_enter(LBS_DEB_SDIO);
1063 1080
1064 card = sdio_get_drvdata(func); 1081 card = sdio_get_drvdata(func);
1065 1082
1066 lbs_stop_card(card->priv); 1083 if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) {
1084 /*
1085 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
1086 * multiple functions
1087 */
1088 struct cmd_header cmd;
1089
1090 memset(&cmd, 0, sizeof(cmd));
1091
1092 lbs_deb_sdio("send function SHUTDOWN command\n");
1093 if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
1094 &cmd, sizeof(cmd), lbs_cmd_copyback,
1095 (unsigned long) &cmd))
1096 lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
1097 }
1067 1098
1068 card->priv->surpriseremoved = 1; 1099 card->priv->surpriseremoved = 1;
1069 1100
1070 lbs_deb_sdio("call remove card\n"); 1101 lbs_deb_sdio("call remove card\n");
1102 lbs_stop_card(card->priv);
1071 lbs_remove_card(card->priv); 1103 lbs_remove_card(card->priv);
1072 1104
1073 flush_workqueue(card->workqueue); 1105 flush_workqueue(card->workqueue);
1074 destroy_workqueue(card->workqueue); 1106 destroy_workqueue(card->workqueue);
1075 1107
1076 sdio_claim_host(func); 1108 sdio_claim_host(func);
1077
1078 /* Disable interrupts */
1079 sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret);
1080
1081 sdio_release_irq(func); 1109 sdio_release_irq(func);
1082 sdio_disable_func(func); 1110 sdio_disable_func(func);
1083
1084 sdio_release_host(func); 1111 sdio_release_host(func);
1085 1112
1086 while (card->packets) { 1113 while (card->packets) {
@@ -1116,6 +1143,9 @@ static int __init if_sdio_init_module(void)
1116 1143
1117 ret = sdio_register_driver(&if_sdio_driver); 1144 ret = sdio_register_driver(&if_sdio_driver);
1118 1145
1146 /* Clear the flag in case user removes the card. */
1147 user_rmmod = 0;
1148
1119 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); 1149 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
1120 1150
1121 return ret; 1151 return ret;
@@ -1123,22 +1153,10 @@ static int __init if_sdio_init_module(void)
1123 1153
1124static void __exit if_sdio_exit_module(void) 1154static void __exit if_sdio_exit_module(void)
1125{ 1155{
1126 int i;
1127 struct if_sdio_card *card;
1128
1129 lbs_deb_enter(LBS_DEB_SDIO); 1156 lbs_deb_enter(LBS_DEB_SDIO);
1130 1157
1131 for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) { 1158 /* Set the flag as user is removing this module. */
1132 card = if_sdio_models[i].card; 1159 user_rmmod = 1;
1133
1134 /*
1135 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
1136 * multiple functions
1137 */
1138 if (card && card->priv)
1139 card->priv->fn_shutdown_required =
1140 (card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
1141 }
1142 1160
1143 sdio_unregister_driver(&if_sdio_driver); 1161 sdio_unregister_driver(&if_sdio_driver);
1144 1162