Merge remote-tracking branch 'upstream' into next
[cascardo/linux.git] / drivers / staging / csr / firmware.c
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  */
59 void*
60 unifi_fw_read_start(void *ospriv, s8 is_fw, const card_info_t *info)
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  */
103 void
104 unifi_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  */
142 void *
143 unifi_fw_open_buffer(void *ospriv, void *fwbuf, u32 len)
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  */
177 void 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  */
199 s32
200 unifi_fw_read(void *ospriv, void *arg, u32 offset, void *buf, u32 len)
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
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  */
242 int
243 uf_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
298 #ifdef CSR_WIFI_SPLIT_PATCH
299 static u8 is_ap_mode(unifi_priv_t *priv)
300 {
301     if (priv == NULL || priv->interfacePriv[0] == NULL)
302     {
303         return FALSE;
304     }
305
306     /* Test for mode requiring AP patch */
307     return(CSR_WIFI_HIP_IS_AP_FW(priv->interfacePriv[0]->interfaceMode));
308 }
309 #endif
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  */
325 int 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);
347 #ifdef CSR_WIFI_SPLIT_PATCH
348         scnprintf(fw_name, UNIFI_MAX_FW_PATH_LEN, "unifi-sdio-%d/%s",
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
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  */
381 int 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  */
402 int 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 }