diff options
Diffstat (limited to 'drivers/net/wireless/libertas/fw.c')
-rw-r--r-- | drivers/net/wireless/libertas/fw.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c new file mode 100644 index 000000000000..b194a4570791 --- /dev/null +++ b/drivers/net/wireless/libertas/fw.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /** | ||
2 | * This file contains the initialization for FW and HW | ||
3 | */ | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/moduleparam.h> | ||
6 | |||
7 | #include <linux/vmalloc.h> | ||
8 | #include <linux/firmware.h> | ||
9 | #include <linux/version.h> | ||
10 | |||
11 | #include "host.h" | ||
12 | #include "sbi.h" | ||
13 | #include "defs.h" | ||
14 | #include "decl.h" | ||
15 | #include "dev.h" | ||
16 | #include "fw.h" | ||
17 | #include "wext.h" | ||
18 | #include "if_usb.h" | ||
19 | |||
20 | char *libertas_fw_name = NULL; | ||
21 | module_param_named(fw_name, libertas_fw_name, charp, 0644); | ||
22 | |||
23 | unsigned int libertas_debug = 0; | ||
24 | module_param(libertas_debug, int, 0); | ||
25 | |||
26 | /** | ||
27 | * @brief This function checks the validity of Boot2/FW image. | ||
28 | * | ||
29 | * @param data pointer to image | ||
30 | * len image length | ||
31 | * @return 0 or -1 | ||
32 | */ | ||
33 | static int check_fwfile_format(u8 *data, u32 totlen) | ||
34 | { | ||
35 | u8 bincmd, exit; | ||
36 | u32 blksize, offset, len; | ||
37 | int ret; | ||
38 | |||
39 | ret = 1; | ||
40 | exit = len = 0; | ||
41 | |||
42 | do { | ||
43 | bincmd = *data; | ||
44 | blksize = *(u32*)(data + offsetof(struct fwheader, datalength)); | ||
45 | switch (bincmd) { | ||
46 | case FW_HAS_DATA_TO_RECV: | ||
47 | offset = sizeof(struct fwheader) + blksize; | ||
48 | data += offset; | ||
49 | len += offset; | ||
50 | if (len >= totlen) | ||
51 | exit = 1; | ||
52 | break; | ||
53 | case FW_HAS_LAST_BLOCK: | ||
54 | exit = 1; | ||
55 | ret = 0; | ||
56 | break; | ||
57 | default: | ||
58 | exit = 1; | ||
59 | break; | ||
60 | } | ||
61 | } while (!exit); | ||
62 | |||
63 | if (ret) | ||
64 | lbs_pr_err("bin file format check FAIL...\n"); | ||
65 | else | ||
66 | lbs_pr_debug(1, "bin file format check PASS...\n"); | ||
67 | |||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * @brief This function downloads firmware image, gets | ||
73 | * HW spec from firmware and set basic parameters to | ||
74 | * firmware. | ||
75 | * | ||
76 | * @param priv A pointer to wlan_private structure | ||
77 | * @return 0 or -1 | ||
78 | */ | ||
79 | static int wlan_setup_station_hw(wlan_private * priv) | ||
80 | { | ||
81 | int ret = -1; | ||
82 | wlan_adapter *adapter = priv->adapter; | ||
83 | |||
84 | ENTER(); | ||
85 | |||
86 | if ((ret = request_firmware(&priv->firmware, libertas_fw_name, | ||
87 | priv->hotplug_device)) < 0) { | ||
88 | lbs_pr_err("request_firmware() failed, error code = %#x\n", | ||
89 | ret); | ||
90 | lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name); | ||
91 | goto done; | ||
92 | } | ||
93 | |||
94 | if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) { | ||
95 | release_firmware(priv->firmware); | ||
96 | goto done; | ||
97 | } | ||
98 | |||
99 | ret = libertas_sbi_prog_firmware(priv); | ||
100 | |||
101 | release_firmware(priv->firmware); | ||
102 | |||
103 | if (ret) { | ||
104 | lbs_pr_debug(1, "Bootloader in invalid state!\n"); | ||
105 | ret = -1; | ||
106 | goto done; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * Read MAC address from HW | ||
111 | */ | ||
112 | memset(adapter->current_addr, 0xff, ETH_ALEN); | ||
113 | |||
114 | ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec, | ||
115 | 0, cmd_option_waitforrsp, 0, NULL); | ||
116 | |||
117 | if (ret) { | ||
118 | ret = -1; | ||
119 | goto done; | ||
120 | } | ||
121 | |||
122 | libertas_set_mac_packet_filter(priv); | ||
123 | |||
124 | /* Get the supported Data rates */ | ||
125 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, | ||
126 | cmd_act_get_tx_rate, | ||
127 | cmd_option_waitforrsp, 0, NULL); | ||
128 | |||
129 | if (ret) { | ||
130 | ret = -1; | ||
131 | goto done; | ||
132 | } | ||
133 | |||
134 | ret = 0; | ||
135 | done: | ||
136 | LEAVE(); | ||
137 | |||
138 | return (ret); | ||
139 | } | ||
140 | |||
141 | static int wlan_allocate_adapter(wlan_private * priv) | ||
142 | { | ||
143 | u32 ulbufsize; | ||
144 | wlan_adapter *adapter = priv->adapter; | ||
145 | |||
146 | struct bss_descriptor *ptempscantable; | ||
147 | |||
148 | /* Allocate buffer to store the BSSID list */ | ||
149 | ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST; | ||
150 | if (!(ptempscantable = kmalloc(ulbufsize, GFP_KERNEL))) { | ||
151 | libertas_free_adapter(priv); | ||
152 | return -1; | ||
153 | } | ||
154 | |||
155 | adapter->scantable = ptempscantable; | ||
156 | memset(adapter->scantable, 0, ulbufsize); | ||
157 | |||
158 | /* Allocate the command buffers */ | ||
159 | libertas_allocate_cmd_buffer(priv); | ||
160 | |||
161 | memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); | ||
162 | adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); | ||
163 | adapter->libertas_ps_confirm_sleep.command = | ||
164 | cpu_to_le16(cmd_802_11_ps_mode); | ||
165 | adapter->libertas_ps_confirm_sleep.size = | ||
166 | cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); | ||
167 | adapter->libertas_ps_confirm_sleep.result = 0; | ||
168 | adapter->libertas_ps_confirm_sleep.action = | ||
169 | cpu_to_le16(cmd_subcmd_sleep_confirmed); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static void wlan_init_adapter(wlan_private * priv) | ||
175 | { | ||
176 | wlan_adapter *adapter = priv->adapter; | ||
177 | int i; | ||
178 | |||
179 | adapter->scanprobes = 0; | ||
180 | |||
181 | adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; | ||
182 | adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; | ||
183 | |||
184 | /* ATIM params */ | ||
185 | adapter->atimwindow = 0; | ||
186 | |||
187 | adapter->connect_status = libertas_disconnected; | ||
188 | memset(adapter->current_addr, 0xff, ETH_ALEN); | ||
189 | |||
190 | /* scan type */ | ||
191 | adapter->scantype = cmd_scan_type_active; | ||
192 | |||
193 | /* scan mode */ | ||
194 | adapter->scanmode = cmd_bss_type_any; | ||
195 | |||
196 | /* 802.11 specific */ | ||
197 | adapter->secinfo.WEPstatus = wlan802_11WEPdisabled; | ||
198 | for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); | ||
199 | i++) | ||
200 | memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY)); | ||
201 | adapter->wep_tx_keyidx = 0; | ||
202 | adapter->secinfo.WEPstatus = wlan802_11WEPdisabled; | ||
203 | adapter->secinfo.authmode = wlan802_11authmodeopen; | ||
204 | adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE; | ||
205 | adapter->secinfo.Encryptionmode = CIPHER_NONE; | ||
206 | adapter->inframode = wlan802_11infrastructure; | ||
207 | |||
208 | adapter->assoc_req = NULL; | ||
209 | |||
210 | adapter->numinscantable = 0; | ||
211 | adapter->pattemptedbssdesc = NULL; | ||
212 | mutex_init(&adapter->lock); | ||
213 | |||
214 | adapter->prescan = 1; | ||
215 | |||
216 | memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); | ||
217 | |||
218 | /* PnP and power profile */ | ||
219 | adapter->surpriseremoved = 0; | ||
220 | |||
221 | adapter->currentpacketfilter = | ||
222 | cmd_act_mac_rx_on | cmd_act_mac_tx_on; | ||
223 | |||
224 | adapter->radioon = RADIO_ON; | ||
225 | adapter->txantenna = RF_ANTENNA_2; | ||
226 | adapter->rxantenna = RF_ANTENNA_AUTO; | ||
227 | |||
228 | adapter->is_datarate_auto = 1; | ||
229 | adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; | ||
230 | |||
231 | // set default value of capinfo. | ||
232 | #define SHORT_PREAMBLE_ALLOWED 1 | ||
233 | memset(&adapter->capinfo, 0, sizeof(adapter->capinfo)); | ||
234 | adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED; | ||
235 | |||
236 | adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL; | ||
237 | |||
238 | adapter->psmode = wlan802_11powermodecam; | ||
239 | adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; | ||
240 | |||
241 | adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; | ||
242 | |||
243 | adapter->psstate = PS_STATE_FULL_POWER; | ||
244 | adapter->needtowakeup = 0; | ||
245 | adapter->locallisteninterval = 0; /* default value in firmware will be used */ | ||
246 | |||
247 | adapter->datarate = 0; // Initially indicate the rate as auto | ||
248 | |||
249 | adapter->adhoc_grate_enabled = 0; | ||
250 | |||
251 | adapter->intcounter = 0; | ||
252 | |||
253 | adapter->currenttxskb = NULL; | ||
254 | adapter->pkttxctrl = 0; | ||
255 | |||
256 | memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); | ||
257 | adapter->tx_queue_idx = 0; | ||
258 | spin_lock_init(&adapter->txqueue_lock); | ||
259 | |||
260 | return; | ||
261 | } | ||
262 | |||
263 | static void command_timer_fn(unsigned long data); | ||
264 | |||
265 | int libertas_init_fw(wlan_private * priv) | ||
266 | { | ||
267 | int ret = -1; | ||
268 | wlan_adapter *adapter = priv->adapter; | ||
269 | |||
270 | ENTER(); | ||
271 | |||
272 | /* Allocate adapter structure */ | ||
273 | if ((ret = wlan_allocate_adapter(priv)) != 0) | ||
274 | goto done; | ||
275 | |||
276 | /* init adapter structure */ | ||
277 | wlan_init_adapter(priv); | ||
278 | |||
279 | /* init timer etc. */ | ||
280 | setup_timer(&adapter->command_timer, command_timer_fn, | ||
281 | (unsigned long)priv); | ||
282 | |||
283 | /* download fimrware etc. */ | ||
284 | if ((ret = wlan_setup_station_hw(priv)) != 0) { | ||
285 | del_timer_sync(&adapter->command_timer); | ||
286 | goto done; | ||
287 | } | ||
288 | |||
289 | /* init 802.11d */ | ||
290 | libertas_init_11d(priv); | ||
291 | |||
292 | ret = 0; | ||
293 | done: | ||
294 | LEAVE(); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | void libertas_free_adapter(wlan_private * priv) | ||
299 | { | ||
300 | wlan_adapter *adapter = priv->adapter; | ||
301 | |||
302 | if (!adapter) { | ||
303 | lbs_pr_debug(1, "Why double free adapter?:)\n"); | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | lbs_pr_debug(1, "Free command buffer\n"); | ||
308 | libertas_free_cmd_buffer(priv); | ||
309 | |||
310 | lbs_pr_debug(1, "Free commandTimer\n"); | ||
311 | del_timer(&adapter->command_timer); | ||
312 | |||
313 | lbs_pr_debug(1, "Free scantable\n"); | ||
314 | if (adapter->scantable) { | ||
315 | kfree(adapter->scantable); | ||
316 | adapter->scantable = NULL; | ||
317 | } | ||
318 | |||
319 | lbs_pr_debug(1, "Free adapter\n"); | ||
320 | |||
321 | /* Free the adapter object itself */ | ||
322 | kfree(adapter); | ||
323 | priv->adapter = NULL; | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * This function handles the timeout of command sending. | ||
328 | * It will re-send the same command again. | ||
329 | */ | ||
330 | static void command_timer_fn(unsigned long data) | ||
331 | { | ||
332 | wlan_private *priv = (wlan_private *)data; | ||
333 | wlan_adapter *adapter = priv->adapter; | ||
334 | struct cmd_ctrl_node *ptempnode; | ||
335 | struct cmd_ds_command *cmd; | ||
336 | unsigned long flags; | ||
337 | |||
338 | ptempnode = adapter->cur_cmd; | ||
339 | cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr; | ||
340 | |||
341 | lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command); | ||
342 | |||
343 | if (!adapter->fw_ready) | ||
344 | return; | ||
345 | |||
346 | if (ptempnode == NULL) { | ||
347 | lbs_pr_debug(1, "PTempnode Empty\n"); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
352 | adapter->cur_cmd = NULL; | ||
353 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
354 | |||
355 | lbs_pr_debug(1, "Re-sending same command as it timeout...!\n"); | ||
356 | libertas_queue_cmd(adapter, ptempnode, 0); | ||
357 | |||
358 | wake_up_interruptible(&priv->mainthread.waitq); | ||
359 | |||
360 | return; | ||
361 | } | ||