return ret;
}
+static void do_release_fw(struct b43_firmware_file *fw)
+{
+ release_firmware(fw->data);
+ fw->data = NULL;
+ fw->filename = NULL;
+}
+
static void b43_release_firmware(struct b43_wldev *dev)
{
- release_firmware(dev->fw.ucode);
- dev->fw.ucode = NULL;
- release_firmware(dev->fw.pcm);
- dev->fw.pcm = NULL;
- release_firmware(dev->fw.initvals);
- dev->fw.initvals = NULL;
- release_firmware(dev->fw.initvals_band);
- dev->fw.initvals_band = NULL;
+ do_release_fw(&dev->fw.ucode);
+ do_release_fw(&dev->fw.pcm);
+ do_release_fw(&dev->fw.initvals);
+ do_release_fw(&dev->fw.initvals_band);
}
static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
static int do_request_fw(struct b43_wldev *dev,
const char *name,
- const struct firmware **fw)
+ struct b43_firmware_file *fw)
{
char path[sizeof(modparam_fwpostfix) + 32];
+ const struct firmware *blob;
struct b43_fw_header *hdr;
u32 size;
int err;
- if (!name)
+ if (!name) {
+ /* Don't fetch anything. Free possibly cached firmware. */
+ do_release_fw(fw);
return 0;
+ }
+ if (fw->filename) {
+ if (strcmp(fw->filename, name) == 0)
+ return 0; /* Already have this fw. */
+ /* Free the cached firmware first. */
+ do_release_fw(fw);
+ }
snprintf(path, ARRAY_SIZE(path),
"b43%s/%s.fw",
modparam_fwpostfix, name);
- err = request_firmware(fw, path, dev->dev->dev);
+ err = request_firmware(&blob, path, dev->dev->dev);
if (err) {
b43err(dev->wl, "Firmware file \"%s\" not found "
"or load failed.\n", path);
return err;
}
- if ((*fw)->size < sizeof(struct b43_fw_header))
+ if (blob->size < sizeof(struct b43_fw_header))
goto err_format;
- hdr = (struct b43_fw_header *)((*fw)->data);
+ hdr = (struct b43_fw_header *)(blob->data);
switch (hdr->type) {
case B43_FW_TYPE_UCODE:
case B43_FW_TYPE_PCM:
size = be32_to_cpu(hdr->size);
- if (size != (*fw)->size - sizeof(struct b43_fw_header))
+ if (size != blob->size - sizeof(struct b43_fw_header))
goto err_format;
/* fallthrough */
case B43_FW_TYPE_IV:
goto err_format;
}
- return err;
+ fw->data = blob;
+ fw->filename = name;
+
+ return 0;
err_format:
b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+ release_firmware(blob);
+
return -EPROTO;
}
u32 tmshigh;
int err;
+ /* Get microcode */
tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
- if (!fw->ucode) {
+ if ((rev >= 5) && (rev <= 10))
+ filename = "ucode5";
+ else if ((rev >= 11) && (rev <= 12))
+ filename = "ucode11";
+ else if (rev >= 13)
+ filename = "ucode13";
+ else
+ goto err_no_ucode;
+ err = do_request_fw(dev, filename, &fw->ucode);
+ if (err)
+ goto err_load;
+
+ /* Get PCM code */
+ if ((rev >= 5) && (rev <= 10))
+ filename = "pcm5";
+ else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_pcm;
+ err = do_request_fw(dev, filename, &fw->pcm);
+ if (err)
+ goto err_load;
+
+ /* Get initvals */
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ if ((rev >= 5) && (rev <= 10)) {
+ if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+ filename = "a0g1initvals5";
+ else
+ filename = "a0g0initvals5";
+ } else
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_G:
if ((rev >= 5) && (rev <= 10))
- filename = "ucode5";
- else if ((rev >= 11) && (rev <= 12))
- filename = "ucode11";
+ filename = "b0g0initvals5";
else if (rev >= 13)
- filename = "ucode13";
+ filename = "lp0initvals13";
else
- goto err_no_ucode;
- err = do_request_fw(dev, filename, &fw->ucode);
- if (err)
- goto err_load;
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_N:
+ if ((rev >= 11) && (rev <= 12))
+ filename = "n0initvals11";
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
}
- if (!fw->pcm) {
+ err = do_request_fw(dev, filename, &fw->initvals);
+ if (err)
+ goto err_load;
+
+ /* Get bandswitch initvals */
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ if ((rev >= 5) && (rev <= 10)) {
+ if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+ filename = "a0g1bsinitvals5";
+ else
+ filename = "a0g0bsinitvals5";
+ } else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_G:
if ((rev >= 5) && (rev <= 10))
- filename = "pcm5";
+ filename = "b0g0bsinitvals5";
else if (rev >= 11)
filename = NULL;
else
- goto err_no_pcm;
- err = do_request_fw(dev, filename, &fw->pcm);
- if (err)
- goto err_load;
- }
- if (!fw->initvals) {
- switch (dev->phy.type) {
- case B43_PHYTYPE_A:
- if ((rev >= 5) && (rev <= 10)) {
- if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
- filename = "a0g1initvals5";
- else
- filename = "a0g0initvals5";
- } else
- goto err_no_initvals;
- break;
- case B43_PHYTYPE_G:
- if ((rev >= 5) && (rev <= 10))
- filename = "b0g0initvals5";
- else if (rev >= 13)
- filename = "lp0initvals13";
- else
- goto err_no_initvals;
- break;
- case B43_PHYTYPE_N:
- if ((rev >= 11) && (rev <= 12))
- filename = "n0initvals11";
- else
- goto err_no_initvals;
- break;
- default:
goto err_no_initvals;
- }
- err = do_request_fw(dev, filename, &fw->initvals);
- if (err)
- goto err_load;
- }
- if (!fw->initvals_band) {
- switch (dev->phy.type) {
- case B43_PHYTYPE_A:
- if ((rev >= 5) && (rev <= 10)) {
- if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
- filename = "a0g1bsinitvals5";
- else
- filename = "a0g0bsinitvals5";
- } else if (rev >= 11)
- filename = NULL;
- else
- goto err_no_initvals;
- break;
- case B43_PHYTYPE_G:
- if ((rev >= 5) && (rev <= 10))
- filename = "b0g0bsinitvals5";
- else if (rev >= 11)
- filename = NULL;
- else
- goto err_no_initvals;
- break;
- case B43_PHYTYPE_N:
- if ((rev >= 11) && (rev <= 12))
- filename = "n0bsinitvals11";
- else
- goto err_no_initvals;
- break;
- default:
+ break;
+ case B43_PHYTYPE_N:
+ if ((rev >= 11) && (rev <= 12))
+ filename = "n0bsinitvals11";
+ else
goto err_no_initvals;
- }
- err = do_request_fw(dev, filename, &fw->initvals_band);
- if (err)
- goto err_load;
+ break;
+ default:
+ goto err_no_initvals;
}
+ err = do_request_fw(dev, filename, &fw->initvals_band);
+ if (err)
+ goto err_load;
return 0;
int err = 0;
/* Upload Microcode. */
- data = (__be32 *) (dev->fw.ucode->data + hdr_len);
- len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+ data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
+ len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
for (i = 0; i < len; i++) {
b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
udelay(10);
}
- if (dev->fw.pcm) {
+ if (dev->fw.pcm.data) {
/* Upload PCM data. */
- data = (__be32 *) (dev->fw.pcm->data + hdr_len);
- len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+ data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
+ len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
/* No need for autoinc bit in SHM_HW */
size_t count;
int err;
- hdr = (const struct b43_fw_header *)(fw->initvals->data);
- ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len);
+ hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
+ ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
count = be32_to_cpu(hdr->size);
err = b43_write_initvals(dev, ivals, count,
- fw->initvals->size - hdr_len);
+ fw->initvals.data->size - hdr_len);
if (err)
goto out;
- if (fw->initvals_band) {
- hdr = (const struct b43_fw_header *)(fw->initvals_band->data);
- ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len);
+ if (fw->initvals_band.data) {
+ hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
+ ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
count = be32_to_cpu(hdr->size);
err = b43_write_initvals(dev, ivals, count,
- fw->initvals_band->size - hdr_len);
+ fw->initvals_band.data->size - hdr_len);
if (err)
goto out;
}