root/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_nvram_char
  2. is_whitespace
  3. brcmf_nvram_handle_idle
  4. brcmf_nvram_handle_key
  5. brcmf_nvram_handle_value
  6. brcmf_nvram_handle_comment
  7. brcmf_nvram_handle_end
  8. brcmf_init_nvram_parser
  9. brcmf_fw_strip_multi_v1
  10. brcmf_fw_strip_multi_v2
  11. brcmf_fw_add_defaults
  12. brcmf_fw_nvram_strip
  13. brcmf_fw_nvram_free
  14. brcmf_fw_fix_efi_nvram_ccode
  15. brcmf_fw_nvram_from_efi
  16. brcmf_fw_nvram_from_efi
  17. brcmf_fw_free_request
  18. brcmf_fw_request_nvram_done
  19. brcmf_fw_complete_request
  20. brcmf_fw_request_firmware
  21. brcmf_fw_request_done
  22. brcmf_fw_request_is_valid
  23. brcmf_fw_get_firmwares
  24. brcmf_fw_alloc_request

   1 // SPDX-License-Identifier: ISC
   2 /*
   3  * Copyright (c) 2013 Broadcom Corporation
   4  */
   5 
   6 #include <linux/efi.h>
   7 #include <linux/kernel.h>
   8 #include <linux/slab.h>
   9 #include <linux/device.h>
  10 #include <linux/firmware.h>
  11 #include <linux/module.h>
  12 #include <linux/bcm47xx_nvram.h>
  13 
  14 #include "debug.h"
  15 #include "firmware.h"
  16 #include "core.h"
  17 #include "common.h"
  18 #include "chip.h"
  19 
  20 #define BRCMF_FW_MAX_NVRAM_SIZE                 64000
  21 #define BRCMF_FW_NVRAM_DEVPATH_LEN              19      /* devpath0=pcie/1/4/ */
  22 #define BRCMF_FW_NVRAM_PCIEDEV_LEN              10      /* pcie/1/4/ + \0 */
  23 #define BRCMF_FW_DEFAULT_BOARDREV               "boardrev=0xff"
  24 
  25 enum nvram_parser_state {
  26         IDLE,
  27         KEY,
  28         VALUE,
  29         COMMENT,
  30         END
  31 };
  32 
  33 /**
  34  * struct nvram_parser - internal info for parser.
  35  *
  36  * @state: current parser state.
  37  * @data: input buffer being parsed.
  38  * @nvram: output buffer with parse result.
  39  * @nvram_len: length of parse result.
  40  * @line: current line.
  41  * @column: current column in line.
  42  * @pos: byte offset in input buffer.
  43  * @entry: start position of key,value entry.
  44  * @multi_dev_v1: detect pcie multi device v1 (compressed).
  45  * @multi_dev_v2: detect pcie multi device v2.
  46  * @boardrev_found: nvram contains boardrev information.
  47  */
  48 struct nvram_parser {
  49         enum nvram_parser_state state;
  50         const u8 *data;
  51         u8 *nvram;
  52         u32 nvram_len;
  53         u32 line;
  54         u32 column;
  55         u32 pos;
  56         u32 entry;
  57         bool multi_dev_v1;
  58         bool multi_dev_v2;
  59         bool boardrev_found;
  60 };
  61 
  62 /**
  63  * is_nvram_char() - check if char is a valid one for NVRAM entry
  64  *
  65  * It accepts all printable ASCII chars except for '#' which opens a comment.
  66  * Please note that ' ' (space) while accepted is not a valid key name char.
  67  */
  68 static bool is_nvram_char(char c)
  69 {
  70         /* comment marker excluded */
  71         if (c == '#')
  72                 return false;
  73 
  74         /* key and value may have any other readable character */
  75         return (c >= 0x20 && c < 0x7f);
  76 }
  77 
  78 static bool is_whitespace(char c)
  79 {
  80         return (c == ' ' || c == '\r' || c == '\n' || c == '\t');
  81 }
  82 
  83 static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp)
  84 {
  85         char c;
  86 
  87         c = nvp->data[nvp->pos];
  88         if (c == '\n')
  89                 return COMMENT;
  90         if (is_whitespace(c) || c == '\0')
  91                 goto proceed;
  92         if (c == '#')
  93                 return COMMENT;
  94         if (is_nvram_char(c)) {
  95                 nvp->entry = nvp->pos;
  96                 return KEY;
  97         }
  98         brcmf_dbg(INFO, "warning: ln=%d:col=%d: ignoring invalid character\n",
  99                   nvp->line, nvp->column);
 100 proceed:
 101         nvp->column++;
 102         nvp->pos++;
 103         return IDLE;
 104 }
 105 
 106 static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
 107 {
 108         enum nvram_parser_state st = nvp->state;
 109         char c;
 110 
 111         c = nvp->data[nvp->pos];
 112         if (c == '=') {
 113                 /* ignore RAW1 by treating as comment */
 114                 if (strncmp(&nvp->data[nvp->entry], "RAW1", 4) == 0)
 115                         st = COMMENT;
 116                 else
 117                         st = VALUE;
 118                 if (strncmp(&nvp->data[nvp->entry], "devpath", 7) == 0)
 119                         nvp->multi_dev_v1 = true;
 120                 if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
 121                         nvp->multi_dev_v2 = true;
 122                 if (strncmp(&nvp->data[nvp->entry], "boardrev", 8) == 0)
 123                         nvp->boardrev_found = true;
 124         } else if (!is_nvram_char(c) || c == ' ') {
 125                 brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
 126                           nvp->line, nvp->column);
 127                 return COMMENT;
 128         }
 129 
 130         nvp->column++;
 131         nvp->pos++;
 132         return st;
 133 }
 134 
 135 static enum nvram_parser_state
 136 brcmf_nvram_handle_value(struct nvram_parser *nvp)
 137 {
 138         char c;
 139         char *skv;
 140         char *ekv;
 141         u32 cplen;
 142 
 143         c = nvp->data[nvp->pos];
 144         if (!is_nvram_char(c)) {
 145                 /* key,value pair complete */
 146                 ekv = (u8 *)&nvp->data[nvp->pos];
 147                 skv = (u8 *)&nvp->data[nvp->entry];
 148                 cplen = ekv - skv;
 149                 if (nvp->nvram_len + cplen + 1 >= BRCMF_FW_MAX_NVRAM_SIZE)
 150                         return END;
 151                 /* copy to output buffer */
 152                 memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen);
 153                 nvp->nvram_len += cplen;
 154                 nvp->nvram[nvp->nvram_len] = '\0';
 155                 nvp->nvram_len++;
 156                 return IDLE;
 157         }
 158         nvp->pos++;
 159         nvp->column++;
 160         return VALUE;
 161 }
 162 
 163 static enum nvram_parser_state
 164 brcmf_nvram_handle_comment(struct nvram_parser *nvp)
 165 {
 166         char *eoc, *sol;
 167 
 168         sol = (char *)&nvp->data[nvp->pos];
 169         eoc = strchr(sol, '\n');
 170         if (!eoc) {
 171                 eoc = strchr(sol, '\0');
 172                 if (!eoc)
 173                         return END;
 174         }
 175 
 176         /* eat all moving to next line */
 177         nvp->line++;
 178         nvp->column = 1;
 179         nvp->pos += (eoc - sol) + 1;
 180         return IDLE;
 181 }
 182 
 183 static enum nvram_parser_state brcmf_nvram_handle_end(struct nvram_parser *nvp)
 184 {
 185         /* final state */
 186         return END;
 187 }
 188 
 189 static enum nvram_parser_state
 190 (*nv_parser_states[])(struct nvram_parser *nvp) = {
 191         brcmf_nvram_handle_idle,
 192         brcmf_nvram_handle_key,
 193         brcmf_nvram_handle_value,
 194         brcmf_nvram_handle_comment,
 195         brcmf_nvram_handle_end
 196 };
 197 
 198 static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
 199                                    const u8 *data, size_t data_len)
 200 {
 201         size_t size;
 202 
 203         memset(nvp, 0, sizeof(*nvp));
 204         nvp->data = data;
 205         /* Limit size to MAX_NVRAM_SIZE, some files contain lot of comment */
 206         if (data_len > BRCMF_FW_MAX_NVRAM_SIZE)
 207                 size = BRCMF_FW_MAX_NVRAM_SIZE;
 208         else
 209                 size = data_len;
 210         /* Alloc for extra 0 byte + roundup by 4 + length field */
 211         size += 1 + 3 + sizeof(u32);
 212         nvp->nvram = kzalloc(size, GFP_KERNEL);
 213         if (!nvp->nvram)
 214                 return -ENOMEM;
 215 
 216         nvp->line = 1;
 217         nvp->column = 1;
 218         return 0;
 219 }
 220 
 221 /* brcmf_fw_strip_multi_v1 :Some nvram files contain settings for multiple
 222  * devices. Strip it down for one device, use domain_nr/bus_nr to determine
 223  * which data is to be returned. v1 is the version where nvram is stored
 224  * compressed and "devpath" maps to index for valid entries.
 225  */
 226 static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr,
 227                                     u16 bus_nr)
 228 {
 229         /* Device path with a leading '=' key-value separator */
 230         char pci_path[] = "=pci/?/?";
 231         size_t pci_len;
 232         char pcie_path[] = "=pcie/?/?";
 233         size_t pcie_len;
 234 
 235         u32 i, j;
 236         bool found;
 237         u8 *nvram;
 238         u8 id;
 239 
 240         nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
 241         if (!nvram)
 242                 goto fail;
 243 
 244         /* min length: devpath0=pcie/1/4/ + 0:x=y */
 245         if (nvp->nvram_len < BRCMF_FW_NVRAM_DEVPATH_LEN + 6)
 246                 goto fail;
 247 
 248         /* First search for the devpathX and see if it is the configuration
 249          * for domain_nr/bus_nr. Search complete nvp
 250          */
 251         snprintf(pci_path, sizeof(pci_path), "=pci/%d/%d", domain_nr,
 252                  bus_nr);
 253         pci_len = strlen(pci_path);
 254         snprintf(pcie_path, sizeof(pcie_path), "=pcie/%d/%d", domain_nr,
 255                  bus_nr);
 256         pcie_len = strlen(pcie_path);
 257         found = false;
 258         i = 0;
 259         while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) {
 260                 /* Format: devpathX=pcie/Y/Z/
 261                  * Y = domain_nr, Z = bus_nr, X = virtual ID
 262                  */
 263                 if (strncmp(&nvp->nvram[i], "devpath", 7) == 0 &&
 264                     (!strncmp(&nvp->nvram[i + 8], pci_path, pci_len) ||
 265                      !strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len))) {
 266                         id = nvp->nvram[i + 7] - '0';
 267                         found = true;
 268                         break;
 269                 }
 270                 while (nvp->nvram[i] != 0)
 271                         i++;
 272                 i++;
 273         }
 274         if (!found)
 275                 goto fail;
 276 
 277         /* Now copy all valid entries, release old nvram and assign new one */
 278         i = 0;
 279         j = 0;
 280         while (i < nvp->nvram_len) {
 281                 if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
 282                         i += 2;
 283                         if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
 284                                 nvp->boardrev_found = true;
 285                         while (nvp->nvram[i] != 0) {
 286                                 nvram[j] = nvp->nvram[i];
 287                                 i++;
 288                                 j++;
 289                         }
 290                         nvram[j] = 0;
 291                         j++;
 292                 }
 293                 while (nvp->nvram[i] != 0)
 294                         i++;
 295                 i++;
 296         }
 297         kfree(nvp->nvram);
 298         nvp->nvram = nvram;
 299         nvp->nvram_len = j;
 300         return;
 301 
 302 fail:
 303         kfree(nvram);
 304         nvp->nvram_len = 0;
 305 }
 306 
 307 /* brcmf_fw_strip_multi_v2 :Some nvram files contain settings for multiple
 308  * devices. Strip it down for one device, use domain_nr/bus_nr to determine
 309  * which data is to be returned. v2 is the version where nvram is stored
 310  * uncompressed, all relevant valid entries are identified by
 311  * pcie/domain_nr/bus_nr:
 312  */
 313 static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr,
 314                                     u16 bus_nr)
 315 {
 316         char prefix[BRCMF_FW_NVRAM_PCIEDEV_LEN];
 317         size_t len;
 318         u32 i, j;
 319         u8 *nvram;
 320 
 321         nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
 322         if (!nvram)
 323                 goto fail;
 324 
 325         /* Copy all valid entries, release old nvram and assign new one.
 326          * Valid entries are of type pcie/X/Y/ where X = domain_nr and
 327          * Y = bus_nr.
 328          */
 329         snprintf(prefix, sizeof(prefix), "pcie/%d/%d/", domain_nr, bus_nr);
 330         len = strlen(prefix);
 331         i = 0;
 332         j = 0;
 333         while (i < nvp->nvram_len - len) {
 334                 if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
 335                         i += len;
 336                         if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
 337                                 nvp->boardrev_found = true;
 338                         while (nvp->nvram[i] != 0) {
 339                                 nvram[j] = nvp->nvram[i];
 340                                 i++;
 341                                 j++;
 342                         }
 343                         nvram[j] = 0;
 344                         j++;
 345                 }
 346                 while (nvp->nvram[i] != 0)
 347                         i++;
 348                 i++;
 349         }
 350         kfree(nvp->nvram);
 351         nvp->nvram = nvram;
 352         nvp->nvram_len = j;
 353         return;
 354 fail:
 355         kfree(nvram);
 356         nvp->nvram_len = 0;
 357 }
 358 
 359 static void brcmf_fw_add_defaults(struct nvram_parser *nvp)
 360 {
 361         if (nvp->boardrev_found)
 362                 return;
 363 
 364         memcpy(&nvp->nvram[nvp->nvram_len], &BRCMF_FW_DEFAULT_BOARDREV,
 365                strlen(BRCMF_FW_DEFAULT_BOARDREV));
 366         nvp->nvram_len += strlen(BRCMF_FW_DEFAULT_BOARDREV);
 367         nvp->nvram[nvp->nvram_len] = '\0';
 368         nvp->nvram_len++;
 369 }
 370 
 371 /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
 372  * and ending in a NUL. Removes carriage returns, empty lines, comment lines,
 373  * and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
 374  * End of buffer is completed with token identifying length of buffer.
 375  */
 376 static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len,
 377                                   u32 *new_length, u16 domain_nr, u16 bus_nr)
 378 {
 379         struct nvram_parser nvp;
 380         u32 pad;
 381         u32 token;
 382         __le32 token_le;
 383 
 384         if (brcmf_init_nvram_parser(&nvp, data, data_len) < 0)
 385                 return NULL;
 386 
 387         while (nvp.pos < data_len) {
 388                 nvp.state = nv_parser_states[nvp.state](&nvp);
 389                 if (nvp.state == END)
 390                         break;
 391         }
 392         if (nvp.multi_dev_v1) {
 393                 nvp.boardrev_found = false;
 394                 brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
 395         } else if (nvp.multi_dev_v2) {
 396                 nvp.boardrev_found = false;
 397                 brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
 398         }
 399 
 400         if (nvp.nvram_len == 0) {
 401                 kfree(nvp.nvram);
 402                 return NULL;
 403         }
 404 
 405         brcmf_fw_add_defaults(&nvp);
 406 
 407         pad = nvp.nvram_len;
 408         *new_length = roundup(nvp.nvram_len + 1, 4);
 409         while (pad != *new_length) {
 410                 nvp.nvram[pad] = 0;
 411                 pad++;
 412         }
 413 
 414         token = *new_length / 4;
 415         token = (~token << 16) | (token & 0x0000FFFF);
 416         token_le = cpu_to_le32(token);
 417 
 418         memcpy(&nvp.nvram[*new_length], &token_le, sizeof(token_le));
 419         *new_length += sizeof(token_le);
 420 
 421         return nvp.nvram;
 422 }
 423 
 424 void brcmf_fw_nvram_free(void *nvram)
 425 {
 426         kfree(nvram);
 427 }
 428 
 429 struct brcmf_fw {
 430         struct device *dev;
 431         struct brcmf_fw_request *req;
 432         u32 curpos;
 433         void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
 434 };
 435 
 436 static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
 437 
 438 #ifdef CONFIG_EFI
 439 /* In some cases the EFI-var stored nvram contains "ccode=ALL" or "ccode=XV"
 440  * to specify "worldwide" compatible settings, but these 2 ccode-s do not work
 441  * properly. "ccode=ALL" causes channels 12 and 13 to not be available,
 442  * "ccode=XV" causes all 5GHz channels to not be available. So we replace both
 443  * with "ccode=X2" which allows channels 12+13 and 5Ghz channels in
 444  * no-Initiate-Radiation mode. This means that we will never send on these
 445  * channels without first having received valid wifi traffic on the channel.
 446  */
 447 static void brcmf_fw_fix_efi_nvram_ccode(char *data, unsigned long data_len)
 448 {
 449         char *ccode;
 450 
 451         ccode = strnstr((char *)data, "ccode=ALL", data_len);
 452         if (!ccode)
 453                 ccode = strnstr((char *)data, "ccode=XV\r", data_len);
 454         if (!ccode)
 455                 return;
 456 
 457         ccode[6] = 'X';
 458         ccode[7] = '2';
 459         ccode[8] = '\r';
 460 }
 461 
 462 static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret)
 463 {
 464         const u16 name[] = { 'n', 'v', 'r', 'a', 'm', 0 };
 465         struct efivar_entry *nvram_efivar;
 466         unsigned long data_len = 0;
 467         u8 *data = NULL;
 468         int err;
 469 
 470         nvram_efivar = kzalloc(sizeof(*nvram_efivar), GFP_KERNEL);
 471         if (!nvram_efivar)
 472                 return NULL;
 473 
 474         memcpy(&nvram_efivar->var.VariableName, name, sizeof(name));
 475         nvram_efivar->var.VendorGuid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61,
 476                                                 0xb5, 0x1f, 0x43, 0x26,
 477                                                 0x81, 0x23, 0xd1, 0x13);
 478 
 479         err = efivar_entry_size(nvram_efivar, &data_len);
 480         if (err)
 481                 goto fail;
 482 
 483         data = kmalloc(data_len, GFP_KERNEL);
 484         if (!data)
 485                 goto fail;
 486 
 487         err = efivar_entry_get(nvram_efivar, NULL, &data_len, data);
 488         if (err)
 489                 goto fail;
 490 
 491         brcmf_fw_fix_efi_nvram_ccode(data, data_len);
 492         brcmf_info("Using nvram EFI variable\n");
 493 
 494         kfree(nvram_efivar);
 495         *data_len_ret = data_len;
 496         return data;
 497 
 498 fail:
 499         kfree(data);
 500         kfree(nvram_efivar);
 501         return NULL;
 502 }
 503 #else
 504 static inline u8 *brcmf_fw_nvram_from_efi(size_t *data_len) { return NULL; }
 505 #endif
 506 
 507 static void brcmf_fw_free_request(struct brcmf_fw_request *req)
 508 {
 509         struct brcmf_fw_item *item;
 510         int i;
 511 
 512         for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
 513                 if (item->type == BRCMF_FW_TYPE_BINARY)
 514                         release_firmware(item->binary);
 515                 else if (item->type == BRCMF_FW_TYPE_NVRAM)
 516                         brcmf_fw_nvram_free(item->nv_data.data);
 517         }
 518         kfree(req);
 519 }
 520 
 521 static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
 522 {
 523         struct brcmf_fw *fwctx = ctx;
 524         struct brcmf_fw_item *cur;
 525         bool free_bcm47xx_nvram = false;
 526         bool kfree_nvram = false;
 527         u32 nvram_length = 0;
 528         void *nvram = NULL;
 529         u8 *data = NULL;
 530         size_t data_len;
 531 
 532         brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
 533 
 534         cur = &fwctx->req->items[fwctx->curpos];
 535 
 536         if (fw && fw->data) {
 537                 data = (u8 *)fw->data;
 538                 data_len = fw->size;
 539         } else {
 540                 if ((data = bcm47xx_nvram_get_contents(&data_len)))
 541                         free_bcm47xx_nvram = true;
 542                 else if ((data = brcmf_fw_nvram_from_efi(&data_len)))
 543                         kfree_nvram = true;
 544                 else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL))
 545                         goto fail;
 546         }
 547 
 548         if (data)
 549                 nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,
 550                                              fwctx->req->domain_nr,
 551                                              fwctx->req->bus_nr);
 552 
 553         if (free_bcm47xx_nvram)
 554                 bcm47xx_nvram_release_contents(data);
 555         if (kfree_nvram)
 556                 kfree(data);
 557 
 558         release_firmware(fw);
 559         if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
 560                 goto fail;
 561 
 562         brcmf_dbg(TRACE, "nvram %p len %d\n", nvram, nvram_length);
 563         cur->nv_data.data = nvram;
 564         cur->nv_data.len = nvram_length;
 565         return 0;
 566 
 567 fail:
 568         return -ENOENT;
 569 }
 570 
 571 static int brcmf_fw_complete_request(const struct firmware *fw,
 572                                      struct brcmf_fw *fwctx)
 573 {
 574         struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
 575         int ret = 0;
 576 
 577         brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path, fw ? "" : "not ");
 578 
 579         switch (cur->type) {
 580         case BRCMF_FW_TYPE_NVRAM:
 581                 ret = brcmf_fw_request_nvram_done(fw, fwctx);
 582                 break;
 583         case BRCMF_FW_TYPE_BINARY:
 584                 if (fw)
 585                         cur->binary = fw;
 586                 else
 587                         ret = -ENOENT;
 588                 break;
 589         default:
 590                 /* something fishy here so bail out early */
 591                 brcmf_err("unknown fw type: %d\n", cur->type);
 592                 release_firmware(fw);
 593                 ret = -EINVAL;
 594         }
 595 
 596         return (cur->flags & BRCMF_FW_REQF_OPTIONAL) ? 0 : ret;
 597 }
 598 
 599 static int brcmf_fw_request_firmware(const struct firmware **fw,
 600                                      struct brcmf_fw *fwctx)
 601 {
 602         struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
 603         int ret;
 604 
 605         /* nvram files are board-specific, first try a board-specific path */
 606         if (cur->type == BRCMF_FW_TYPE_NVRAM && fwctx->req->board_type) {
 607                 char alt_path[BRCMF_FW_NAME_LEN];
 608 
 609                 strlcpy(alt_path, cur->path, BRCMF_FW_NAME_LEN);
 610                 /* strip .txt at the end */
 611                 alt_path[strlen(alt_path) - 4] = 0;
 612                 strlcat(alt_path, ".", BRCMF_FW_NAME_LEN);
 613                 strlcat(alt_path, fwctx->req->board_type, BRCMF_FW_NAME_LEN);
 614                 strlcat(alt_path, ".txt", BRCMF_FW_NAME_LEN);
 615 
 616                 ret = request_firmware(fw, alt_path, fwctx->dev);
 617                 if (ret == 0)
 618                         return ret;
 619         }
 620 
 621         return request_firmware(fw, cur->path, fwctx->dev);
 622 }
 623 
 624 static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
 625 {
 626         struct brcmf_fw *fwctx = ctx;
 627         int ret;
 628 
 629         ret = brcmf_fw_complete_request(fw, fwctx);
 630 
 631         while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) {
 632                 brcmf_fw_request_firmware(&fw, fwctx);
 633                 ret = brcmf_fw_complete_request(fw, ctx);
 634         }
 635 
 636         if (ret) {
 637                 brcmf_fw_free_request(fwctx->req);
 638                 fwctx->req = NULL;
 639         }
 640         fwctx->done(fwctx->dev, ret, fwctx->req);
 641         kfree(fwctx);
 642 }
 643 
 644 static bool brcmf_fw_request_is_valid(struct brcmf_fw_request *req)
 645 {
 646         struct brcmf_fw_item *item;
 647         int i;
 648 
 649         if (!req->n_items)
 650                 return false;
 651 
 652         for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
 653                 if (!item->path)
 654                         return false;
 655         }
 656         return true;
 657 }
 658 
 659 int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
 660                            void (*fw_cb)(struct device *dev, int err,
 661                                          struct brcmf_fw_request *req))
 662 {
 663         struct brcmf_fw_item *first = &req->items[0];
 664         struct brcmf_fw *fwctx;
 665         int ret;
 666 
 667         brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
 668         if (!fw_cb)
 669                 return -EINVAL;
 670 
 671         if (!brcmf_fw_request_is_valid(req))
 672                 return -EINVAL;
 673 
 674         fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
 675         if (!fwctx)
 676                 return -ENOMEM;
 677 
 678         fwctx->dev = dev;
 679         fwctx->req = req;
 680         fwctx->done = fw_cb;
 681 
 682         ret = request_firmware_nowait(THIS_MODULE, true, first->path,
 683                                       fwctx->dev, GFP_KERNEL, fwctx,
 684                                       brcmf_fw_request_done);
 685         if (ret < 0)
 686                 brcmf_fw_request_done(NULL, fwctx);
 687 
 688         return 0;
 689 }
 690 
 691 struct brcmf_fw_request *
 692 brcmf_fw_alloc_request(u32 chip, u32 chiprev,
 693                        const struct brcmf_firmware_mapping mapping_table[],
 694                        u32 table_size, struct brcmf_fw_name *fwnames,
 695                        u32 n_fwnames)
 696 {
 697         struct brcmf_fw_request *fwreq;
 698         char chipname[12];
 699         const char *mp_path;
 700         size_t mp_path_len;
 701         u32 i, j;
 702         char end = '\0';
 703 
 704         for (i = 0; i < table_size; i++) {
 705                 if (mapping_table[i].chipid == chip &&
 706                     mapping_table[i].revmask & BIT(chiprev))
 707                         break;
 708         }
 709 
 710         brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname));
 711 
 712         if (i == table_size) {
 713                 brcmf_err("Unknown chip %s\n", chipname);
 714                 return NULL;
 715         }
 716 
 717         fwreq = kzalloc(struct_size(fwreq, items, n_fwnames), GFP_KERNEL);
 718         if (!fwreq)
 719                 return NULL;
 720 
 721         brcmf_info("using %s for chip %s\n",
 722                    mapping_table[i].fw_base, chipname);
 723 
 724         mp_path = brcmf_mp_global.firmware_path;
 725         mp_path_len = strnlen(mp_path, BRCMF_FW_ALTPATH_LEN);
 726         if (mp_path_len)
 727                 end = mp_path[mp_path_len - 1];
 728 
 729         fwreq->n_items = n_fwnames;
 730 
 731         for (j = 0; j < n_fwnames; j++) {
 732                 fwreq->items[j].path = fwnames[j].path;
 733                 fwnames[j].path[0] = '\0';
 734                 /* check if firmware path is provided by module parameter */
 735                 if (brcmf_mp_global.firmware_path[0] != '\0') {
 736                         strlcpy(fwnames[j].path, mp_path,
 737                                 BRCMF_FW_NAME_LEN);
 738 
 739                         if (end != '/') {
 740                                 strlcat(fwnames[j].path, "/",
 741                                         BRCMF_FW_NAME_LEN);
 742                         }
 743                 }
 744                 strlcat(fwnames[j].path, mapping_table[i].fw_base,
 745                         BRCMF_FW_NAME_LEN);
 746                 strlcat(fwnames[j].path, fwnames[j].extension,
 747                         BRCMF_FW_NAME_LEN);
 748                 fwreq->items[j].path = fwnames[j].path;
 749         }
 750 
 751         return fwreq;
 752 }

/* [<][>][^][v][top][bottom][index][help] */