Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.6 413 lines 12 kB view raw
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* 60unifi_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 */ 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 * 143unifi_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 */ 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 */ 199s32 200unifi_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 */ 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 298#ifdef CSR_WIFI_SPLIT_PATCH 299static 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 */ 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); 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 */ 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}