staging: csr: remove CsrCharString typedef
[linux-block.git] / drivers / staging / csr / firmware.c
CommitLineData
635d2b00
GKH
1/*
2 * ---------------------------------------------------------------------------
3 * FILE: firmware.c
4 *
5 * PURPOSE:
6 * Implements the f/w related HIP core lib API.
7 * It is part of the porting exercise in Linux.
8 *
9 * Also, it contains example code for reading the loader and f/w files
10 * from the userspace and starting the SME in Linux.
11 *
12 * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
13 *
14 * Refer to LICENSE.txt included with this source code for details on
15 * the license terms.
16 *
17 * ---------------------------------------------------------------------------
18 */
19#include <linux/kmod.h>
20#include <linux/vmalloc.h>
21#include <linux/firmware.h>
22#include <asm/uaccess.h>
23#include "csr_wifi_hip_unifi.h"
24#include "csr_wifi_hip_unifi_udi.h"
25#include "unifiio.h"
26#include "unifi_priv.h"
27
28/*
29 * ---------------------------------------------------------------------------
30 *
31 * F/W download. Part of the HIP core API
32 *
33 * ---------------------------------------------------------------------------
34 */
35
36
37/*
38 * ---------------------------------------------------------------------------
39 * unifi_fw_read_start
40 *
41 * Returns a structure to be passed in unifi_fw_read().
42 * This structure is an OS specific description of the f/w file.
43 * In the linux implementation it is a buffer with the f/w and its' length.
44 * The HIP driver calls this functions to request for the loader or
45 * the firmware file.
46 * The structure pointer can be freed when unifi_fw_read_stop() is called.
47 *
48 * Arguments:
49 * ospriv Pointer to driver context.
50 * is_fw Type of firmware to retrieve
51 * info Versions information. Can be used to determine
52 * the appropriate f/w file to load.
53 *
54 * Returns:
55 * O on success, non-zero otherwise.
56 *
57 * ---------------------------------------------------------------------------
58 */
59void*
163eb0d8 60unifi_fw_read_start(void *ospriv, s8 is_fw, const card_info_t *info)
635d2b00
GKH
61{
62 unifi_priv_t *priv = (unifi_priv_t*)ospriv;
63 CSR_UNUSED(info);
64
65 func_enter();
66
67 if (is_fw == UNIFI_FW_STA) {
68 /* F/w may have been released after a previous successful download. */
69 if (priv->fw_sta.dl_data == NULL) {
70 unifi_trace(priv, UDBG2, "Attempt reload of sta f/w\n");
71 uf_request_firmware_files(priv, UNIFI_FW_STA);
72 }
73 /* Set up callback struct for readfunc() */
74 if (priv->fw_sta.dl_data != NULL) {
75 func_exit();
76 return &priv->fw_sta;
77 }
78
79 } else {
80 unifi_error(priv, "downloading firmware... unknown request: %d\n", is_fw);
81 }
82
83 func_exit();
84 return NULL;
85} /* unifi_fw_read_start() */
86
87
88
89/*
90 * ---------------------------------------------------------------------------
91 * unifi_fw_read_stop
92 *
93 * Called when the HIP driver has finished using the loader or
94 * the firmware file.
95 * The firmware buffer may be released now.
96 *
97 * Arguments:
98 * ospriv Pointer to driver context.
99 * dlpriv The pointer returned by unifi_fw_read_start()
100 *
101 * ---------------------------------------------------------------------------
102 */
103void
104unifi_fw_read_stop(void *ospriv, void *dlpriv)
105{
106 unifi_priv_t *priv = (unifi_priv_t*)ospriv;
107 struct dlpriv *dl_struct = (struct dlpriv *)dlpriv;
108 func_enter();
109
110 if (dl_struct != NULL) {
111 if (dl_struct->dl_data != NULL) {
112 unifi_trace(priv, UDBG2, "Release f/w buffer %p, %d bytes\n",
113 dl_struct->dl_data, dl_struct->dl_len);
114 }
115 uf_release_firmware(priv, dl_struct);
116 }
117
118 func_exit();
119} /* unifi_fw_read_stop() */
120
121
122/*
123 * ---------------------------------------------------------------------------
124 * unifi_fw_open_buffer
125 *
126 * Returns a handle for a buffer dynamically allocated by the driver,
127 * e.g. into which a firmware file may have been converted from another format
128 * which is the case with some production test images.
129 *
130 * The handle may then be used by unifi_fw_read() to access the contents of
131 * the buffer.
132 *
133 * Arguments:
134 * ospriv Pointer to driver context.
135 * fwbuf Buffer containing firmware image
136 * len Length of buffer in bytes
137 *
138 * Returns
139 * Handle for buffer, or NULL on error
140 * ---------------------------------------------------------------------------
141 */
142void *
26a6b2e1 143unifi_fw_open_buffer(void *ospriv, void *fwbuf, u32 len)
635d2b00
GKH
144{
145 unifi_priv_t *priv = (unifi_priv_t*)ospriv;
146 func_enter();
147
148 if (fwbuf == NULL) {
149 func_exit();
150 return NULL;
151 }
152 priv->fw_conv.dl_data = fwbuf;
153 priv->fw_conv.dl_len = len;
154 priv->fw_conv.fw_desc = NULL; /* No OS f/w resource is associated */
155
156 func_exit();
157 return &priv->fw_conv;
158}
159
160/*
161 * ---------------------------------------------------------------------------
162 * unifi_fw_close_buffer
163 *
164 * Releases any handle for a buffer dynamically allocated by the driver,
165 * e.g. into which a firmware file may have been converted from another format
166 * which is the case with some production test images.
167 *
168 *
169 * Arguments:
170 * ospriv Pointer to driver context.
171 * fwbuf Buffer containing firmware image
172 *
173 * Returns
174 * Handle for buffer, or NULL on error
175 * ---------------------------------------------------------------------------
176 */
177void unifi_fw_close_buffer(void *ospriv, void *fwbuf)
178{
179}
180
181/*
182 * ---------------------------------------------------------------------------
183 * unifi_fw_read
184 *
185 * The HIP driver calls this function to ask for a part of the loader or
186 * the firmware file.
187 *
188 * Arguments:
189 * ospriv Pointer to driver context.
190 * arg The pointer returned by unifi_fw_read_start().
191 * offset The offset in the file to return from.
192 * buf A buffer to store the requested data.
193 * len The size of the buf and the size of the requested data.
194 *
195 * Returns
196 * The number of bytes read from the firmware image, or -ve on error
197 * ---------------------------------------------------------------------------
198 */
95e326c2 199s32
26a6b2e1 200unifi_fw_read(void *ospriv, void *arg, u32 offset, void *buf, u32 len)
635d2b00
GKH
201{
202 const struct dlpriv *dlpriv = arg;
203
204 if (offset >= dlpriv->dl_len) {
205 /* at end of file */
206 return 0;
207 }
208
209 if ((offset + len) > dlpriv->dl_len) {
210 /* attempt to read past end of file */
211 return -1;
212 }
213
214 memcpy(buf, dlpriv->dl_data+offset, len);
215
216 return len;
217
218} /* unifi_fw_read() */
219
220
221
222
635d2b00
GKH
223#define UNIFIHELPER_INIT_MODE_SMEUSER 2
224#define UNIFIHELPER_INIT_MODE_NATIVE 1
225
226/*
227 * ---------------------------------------------------------------------------
228 * uf_run_unifihelper
229 *
230 * Ask userspace to send us firmware for download by running
231 * '/usr/sbin/unififw'.
232 * The same script starts the SME userspace application.
233 * Derived from net_run_sbin_hotplug().
234 *
235 * Arguments:
236 * priv Pointer to OS private struct.
237 *
238 * Returns:
239 * None.
240 * ---------------------------------------------------------------------------
241 */
242int
243uf_run_unifihelper(unifi_priv_t *priv)
244{
245#ifdef CONFIG_HOTPLUG
246
247#ifdef ANDROID_BUILD
248 char *prog = "/system/bin/unififw";
249#else
250 char *prog = "/usr/sbin/unififw";
251#endif /* ANDROID_BUILD */
252
253 char *argv[6], *envp[4];
254 char inst_str[8];
255 char init_mode[8];
256 int i, r;
257
258#if (defined CSR_SME_USERSPACE) && (!defined CSR_SUPPORT_WEXT)
259 unifi_trace(priv, UDBG1, "SME userspace build: run unifi_helper manually\n");
260 return 0;
261#endif
262
263 unifi_trace(priv, UDBG1, "starting %s\n", prog);
264
265 snprintf(inst_str, 8, "%d", priv->instance);
266#if (defined CSR_SME_USERSPACE)
267 snprintf(init_mode, 8, "%d", UNIFIHELPER_INIT_MODE_SMEUSER);
268#else
269 snprintf(init_mode, 8, "%d", UNIFIHELPER_INIT_MODE_NATIVE);
270#endif /* CSR_SME_USERSPACE */
271
272 i = 0;
273 argv[i++] = prog;
274 argv[i++] = inst_str;
275 argv[i++] = init_mode;
276 argv[i++] = 0;
277 argv[i] = 0;
278 /* Don't add more args without making argv bigger */
279
280 /* minimal command environment */
281 i = 0;
282 envp[i++] = "HOME=/";
283 envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
284 envp[i] = 0;
285 /* Don't add more without making envp bigger */
286
287 unifi_trace(priv, UDBG2, "running %s %s %s\n", argv[0], argv[1], argv[2]);
288
289 r = call_usermodehelper(argv[0], argv, envp, 0);
290
291 return r;
292#else
293 unifi_trace(priv, UDBG1, "Can't automatically download firmware because kernel does not have HOTPLUG\n");
294 return -1;
295#endif
296} /* uf_run_unifihelper() */
297
95edd09e
GKH
298#ifdef CSR_WIFI_SPLIT_PATCH
299static CsrBool is_ap_mode(unifi_priv_t *priv)
300{
301 if (priv == NULL || priv->interfacePriv[0] == NULL)
302 {
303 return FALSE;
304 }
635d2b00 305
95edd09e
GKH
306 /* Test for mode requiring AP patch */
307 return(CSR_WIFI_HIP_IS_AP_FW(priv->interfacePriv[0]->interfaceMode));
308}
309#endif
635d2b00
GKH
310
311/*
312 * ---------------------------------------------------------------------------
313 * uf_request_firmware_files
314 *
315 * Get the firmware files from userspace.
316 *
317 * Arguments:
318 * priv Pointer to OS private struct.
319 * is_fw type of firmware to load (UNIFI_FW_STA/LOADER)
320 *
321 * Returns:
322 * None.
323 * ---------------------------------------------------------------------------
324 */
325int uf_request_firmware_files(unifi_priv_t *priv, int is_fw)
326{
327 /* uses the default method to get the firmware */
328 const struct firmware *fw_entry;
329 int postfix;
330#define UNIFI_MAX_FW_PATH_LEN 32
331 char fw_name[UNIFI_MAX_FW_PATH_LEN];
332 int r;
333
334#if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
335 if (priv->mib_data.length) {
336 vfree(priv->mib_data.data);
337 priv->mib_data.data = NULL;
338 priv->mib_data.length = 0;
339 }
340#endif /* CSR_SUPPORT_SME && CSR_SUPPORT_WEXT*/
341
342 postfix = priv->instance;
343
344 if (is_fw == UNIFI_FW_STA) {
345 /* Free kernel buffer and reload */
346 uf_release_firmware(priv, &priv->fw_sta);
95edd09e 347#ifdef CSR_WIFI_SPLIT_PATCH
635d2b00 348 scnprintf(fw_name, UNIFI_MAX_FW_PATH_LEN, "unifi-sdio-%d/%s",
95edd09e
GKH
349 postfix, (is_ap_mode(priv) ? "ap.xbv" : "staonly.xbv") );
350#else
351 scnprintf(fw_name, UNIFI_MAX_FW_PATH_LEN, "unifi-sdio-%d/%s",
352 postfix, "sta.xbv" );
353#endif
635d2b00
GKH
354 r = request_firmware(&fw_entry, fw_name, priv->unifi_device);
355 if (r == 0) {
356 priv->fw_sta.dl_data = fw_entry->data;
357 priv->fw_sta.dl_len = fw_entry->size;
358 priv->fw_sta.fw_desc = (void *)fw_entry;
359 } else {
360 unifi_trace(priv, UDBG2, "Firmware file not available\n");
361 }
362 }
363
364 return 0;
365
366} /* uf_request_firmware_files() */
367
368/*
369 * ---------------------------------------------------------------------------
370 * uf_release_firmware_files
371 *
372 * Release all buffers used to store firmware files
373 *
374 * Arguments:
375 * priv Pointer to OS private struct.
376 *
377 * Returns:
378 * None.
379 * ---------------------------------------------------------------------------
380 */
381int uf_release_firmware_files(unifi_priv_t *priv)
382{
383 uf_release_firmware(priv, &priv->fw_sta);
384
385 return 0;
386}
387
388/*
389 * ---------------------------------------------------------------------------
390 * uf_release_firmware
391 *
392 * Release specific buffer used to store firmware
393 *
394 * Arguments:
395 * priv Pointer to OS private struct.
396 * to_free Pointer to specific buffer to release
397 *
398 * Returns:
399 * None.
400 * ---------------------------------------------------------------------------
401 */
402int uf_release_firmware(unifi_priv_t *priv, struct dlpriv *to_free)
403{
404 if (to_free != NULL) {
405 if (to_free->fw_desc != NULL) {
406 release_firmware((const struct firmware *)to_free->fw_desc);
407 }
408 to_free->fw_desc = NULL;
409 to_free->dl_data = NULL;
410 to_free->dl_len = 0;
411 }
412 return 0;
413}