diff options
author | Bing Zhao <bzhao@marvell.com> | 2009-06-01 21:04:36 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-06-03 14:05:16 -0400 |
commit | 6bc61f4d8e2fa3d54017c29b58603e8771158a25 (patch) | |
tree | a527be05a193d1ef4b223322b4af6d83c69f64cb /drivers/net/wireless/libertas/if_sdio.c | |
parent | 328d84fb3614d006254c990a6224ce437147a5ac (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.c | 76 |
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 | */ | ||
58 | static u8 user_rmmod; | ||
59 | |||
44 | static char *lbs_helper_name = NULL; | 60 | static char *lbs_helper_name = NULL; |
45 | module_param_named(helper_name, lbs_helper_name, charp, 0644); | 61 | module_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 | ||
67 | static struct if_sdio_model if_sdio_models[] = { | 82 | static 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 | ||
1124 | static void __exit if_sdio_exit_module(void) | 1154 | static 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 | ||