tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.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     if (is_fw == UNIFI_FW_STA) {
66         /* F/w may have been released after a previous successful download. */
67         if (priv->fw_sta.dl_data == NULL) {
68             unifi_trace(priv, UDBG2, "Attempt reload of sta f/w\n");
69             uf_request_firmware_files(priv, UNIFI_FW_STA);
70         }
71         /* Set up callback struct for readfunc() */
72         if (priv->fw_sta.dl_data != NULL) {
73             return &priv->fw_sta;
74         }
75
76     } else {
77         unifi_error(priv, "downloading firmware... unknown request: %d\n", is_fw);
78     }
79
80     return NULL;
81 } /* unifi_fw_read_start() */
82
83
84
85 /*
86  * ---------------------------------------------------------------------------
87  *  unifi_fw_read_stop
88  *
89  *      Called when the HIP driver has finished using the loader or
90  *      the firmware file.
91  *      The firmware buffer may be released now.
92  *
93  *  Arguments:
94  *      ospriv          Pointer to driver context.
95  *      dlpriv          The pointer returned by unifi_fw_read_start()
96  *
97  * ---------------------------------------------------------------------------
98  */
99 void
100 unifi_fw_read_stop(void *ospriv, void *dlpriv)
101 {
102     unifi_priv_t *priv = (unifi_priv_t*)ospriv;
103     struct dlpriv *dl_struct = (struct dlpriv *)dlpriv;
104
105     if (dl_struct != NULL) {
106         if (dl_struct->dl_data != NULL) {
107             unifi_trace(priv, UDBG2, "Release f/w buffer %p, %d bytes\n",
108                         dl_struct->dl_data, dl_struct->dl_len);
109         }
110         uf_release_firmware(priv, dl_struct);
111     }
112
113 } /* unifi_fw_read_stop() */
114
115
116 /*
117  * ---------------------------------------------------------------------------
118  *  unifi_fw_open_buffer
119  *
120  *  Returns a handle for a buffer dynamically allocated by the driver,
121  *  e.g. into which a firmware file may have been converted from another format
122  *  which is the case with some production test images.
123  *
124  *  The handle may then be used by unifi_fw_read() to access the contents of
125  *  the buffer.
126  *
127  *  Arguments:
128  *      ospriv          Pointer to driver context.
129  *      fwbuf           Buffer containing firmware image
130  *      len             Length of buffer in bytes
131  *
132  *  Returns
133  *      Handle for buffer, or NULL on error
134  * ---------------------------------------------------------------------------
135  */
136 void *
137 unifi_fw_open_buffer(void *ospriv, void *fwbuf, u32 len)
138 {
139     unifi_priv_t *priv = (unifi_priv_t*)ospriv;
140
141     if (fwbuf == NULL) {
142         return NULL;
143     }
144     priv->fw_conv.dl_data = fwbuf;
145     priv->fw_conv.dl_len = len;
146     priv->fw_conv.fw_desc = NULL;   /* No OS f/w resource is associated */
147
148     return &priv->fw_conv;
149 }
150
151 /*
152  * ---------------------------------------------------------------------------
153  *  unifi_fw_close_buffer
154  *
155  *  Releases any handle for a buffer dynamically allocated by the driver,
156  *  e.g. into which a firmware file may have been converted from another format
157  *  which is the case with some production test images.
158  *
159  *
160  *  Arguments:
161  *      ospriv          Pointer to driver context.
162  *      fwbuf           Buffer containing firmware image
163  *
164  *  Returns
165  *      Handle for buffer, or NULL on error
166  * ---------------------------------------------------------------------------
167  */
168 void unifi_fw_close_buffer(void *ospriv, void *fwbuf)
169 {
170 }
171
172 /*
173  * ---------------------------------------------------------------------------
174  *  unifi_fw_read
175  *
176  *      The HIP driver calls this function to ask for a part of the loader or
177  *      the firmware file.
178  *
179  *  Arguments:
180  *      ospriv          Pointer to driver context.
181  *      arg             The pointer returned by unifi_fw_read_start().
182  *      offset          The offset in the file to return from.
183  *      buf             A buffer to store the requested data.
184  *      len             The size of the buf and the size of the requested data.
185  *
186  *  Returns
187  *      The number of bytes read from the firmware image, or -ve on error
188  * ---------------------------------------------------------------------------
189  */
190 s32
191 unifi_fw_read(void *ospriv, void *arg, u32 offset, void *buf, u32 len)
192 {
193     const struct dlpriv *dlpriv = arg;
194
195     if (offset >= dlpriv->dl_len) {
196         /* at end of file */
197         return 0;
198     }
199
200     if ((offset + len) > dlpriv->dl_len) {
201         /* attempt to read past end of file */
202         return -1;
203     }
204
205     memcpy(buf, dlpriv->dl_data+offset, len);
206
207     return len;
208
209 } /* unifi_fw_read() */
210
211
212
213
214 #define UNIFIHELPER_INIT_MODE_SMEUSER   2
215 #define UNIFIHELPER_INIT_MODE_NATIVE    1
216
217 /*
218  * ---------------------------------------------------------------------------
219  *  uf_run_unifihelper
220  *
221  *      Ask userspace to send us firmware for download by running
222  *      '/usr/sbin/unififw'.
223  *      The same script starts the SME userspace application.
224  *      Derived from net_run_sbin_hotplug().
225  *
226  *  Arguments:
227  *      priv            Pointer to OS private struct.
228  *
229  *  Returns:
230  *      None.
231  * ---------------------------------------------------------------------------
232  */
233 int
234 uf_run_unifihelper(unifi_priv_t *priv)
235 {
236 #ifdef ANDROID_BUILD
237     char *prog = "/system/bin/unififw";
238 #else
239     char *prog = "/usr/sbin/unififw";
240 #endif /* ANDROID_BUILD */
241
242     char *argv[6], *envp[4];
243     char inst_str[8];
244     char init_mode[8];
245     int i, r;
246
247 #if (defined CSR_SME_USERSPACE) && (!defined CSR_SUPPORT_WEXT)
248     unifi_trace(priv, UDBG1, "SME userspace build: run unifi_helper manually\n");
249     return 0;
250 #endif
251
252     unifi_trace(priv, UDBG1, "starting %s\n", prog);
253
254     snprintf(inst_str,   8, "%d", priv->instance);
255 #if (defined CSR_SME_USERSPACE)
256     snprintf(init_mode, 8, "%d", UNIFIHELPER_INIT_MODE_SMEUSER);
257 #else
258     snprintf(init_mode, 8, "%d", UNIFIHELPER_INIT_MODE_NATIVE);
259 #endif /* CSR_SME_USERSPACE */
260
261     i = 0;
262     argv[i++] = prog;
263     argv[i++] = inst_str;
264     argv[i++] = init_mode;
265     argv[i++] = 0;
266     argv[i] = 0;
267     /* Don't add more args without making argv bigger */
268
269     /* minimal command environment */
270     i = 0;
271     envp[i++] = "HOME=/";
272     envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
273     envp[i] = 0;
274     /* Don't add more without making envp bigger */
275
276     unifi_trace(priv, UDBG2, "running %s %s %s\n", argv[0], argv[1], argv[2]);
277
278     r = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
279
280     return r;
281 } /* uf_run_unifihelper() */
282
283 #ifdef CSR_WIFI_SPLIT_PATCH
284 static u8 is_ap_mode(unifi_priv_t *priv)
285 {
286     if (priv == NULL || priv->interfacePriv[0] == NULL)
287     {
288         return FALSE;
289     }
290
291     /* Test for mode requiring AP patch */
292     return(CSR_WIFI_HIP_IS_AP_FW(priv->interfacePriv[0]->interfaceMode));
293 }
294 #endif
295
296 /*
297  * ---------------------------------------------------------------------------
298  *  uf_request_firmware_files
299  *
300  *      Get the firmware files from userspace.
301  *
302  *  Arguments:
303  *      priv            Pointer to OS private struct.
304  *      is_fw           type of firmware to load (UNIFI_FW_STA/LOADER)
305  *
306  *  Returns:
307  *      None.
308  * ---------------------------------------------------------------------------
309  */
310 int uf_request_firmware_files(unifi_priv_t *priv, int is_fw)
311 {
312     /* uses the default method to get the firmware */
313     const struct firmware *fw_entry;
314     int postfix;
315 #define UNIFI_MAX_FW_PATH_LEN       32
316     char fw_name[UNIFI_MAX_FW_PATH_LEN];
317     int r;
318
319 #if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT)
320     if (priv->mib_data.length) {
321         vfree(priv->mib_data.data);
322         priv->mib_data.data = NULL;
323         priv->mib_data.length = 0;
324     }
325 #endif /* CSR_SUPPORT_SME && CSR_SUPPORT_WEXT*/
326
327     postfix = priv->instance;
328
329     if (is_fw == UNIFI_FW_STA) {
330         /* Free kernel buffer and reload */
331         uf_release_firmware(priv, &priv->fw_sta);
332 #ifdef CSR_WIFI_SPLIT_PATCH
333         scnprintf(fw_name, UNIFI_MAX_FW_PATH_LEN, "unifi-sdio-%d/%s",
334                   postfix, (is_ap_mode(priv) ? "ap.xbv" : "staonly.xbv") );
335 #else
336         scnprintf(fw_name, UNIFI_MAX_FW_PATH_LEN, "unifi-sdio-%d/%s",
337                   postfix, "sta.xbv" );
338 #endif
339         r = request_firmware(&fw_entry, fw_name, priv->unifi_device);
340         if (r == 0) {
341             priv->fw_sta.dl_data = fw_entry->data;
342             priv->fw_sta.dl_len = fw_entry->size;
343             priv->fw_sta.fw_desc = (void *)fw_entry;
344         } else {
345             unifi_trace(priv, UDBG2, "Firmware file not available\n");
346         }
347     }
348
349     return 0;
350
351 } /* uf_request_firmware_files() */
352
353 /*
354  * ---------------------------------------------------------------------------
355  *  uf_release_firmware_files
356  *
357  *      Release all buffers used to store firmware files
358  *
359  *  Arguments:
360  *      priv            Pointer to OS private struct.
361  *
362  *  Returns:
363  *      None.
364  * ---------------------------------------------------------------------------
365  */
366 int uf_release_firmware_files(unifi_priv_t *priv)
367 {
368     uf_release_firmware(priv, &priv->fw_sta);
369
370     return 0;
371 }
372
373 /*
374  * ---------------------------------------------------------------------------
375  *  uf_release_firmware
376  *
377  *      Release specific buffer used to store firmware
378  *
379  *  Arguments:
380  *      priv            Pointer to OS private struct.
381  *      to_free         Pointer to specific buffer to release
382  *
383  *  Returns:
384  *      None.
385  * ---------------------------------------------------------------------------
386  */
387 int uf_release_firmware(unifi_priv_t *priv, struct dlpriv *to_free)
388 {
389     if (to_free != NULL) {
390         release_firmware((const struct firmware *)to_free->fw_desc);
391         to_free->fw_desc = NULL;
392         to_free->dl_data = NULL;
393         to_free->dl_len = 0;
394     }
395     return 0;
396 }