Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
firmware.c
Go to the documentation of this file.
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");
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
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, UMH_WAIT_EXEC);
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  */
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
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  */
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  release_firmware((const struct firmware *)to_free->fw_desc);
406  to_free->fw_desc = NULL;
407  to_free->dl_data = NULL;
408  to_free->dl_len = 0;
409  }
410  return 0;
411 }