|
@@ -1934,7 +1934,7 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void do_release_fw(struct b43_firmware_file *fw)
|
|
|
+void b43_do_release_fw(struct b43_firmware_file *fw)
|
|
|
{
|
|
|
release_firmware(fw->data);
|
|
|
fw->data = NULL;
|
|
@@ -1943,10 +1943,10 @@ static void do_release_fw(struct b43_firmware_file *fw)
|
|
|
|
|
|
static void b43_release_firmware(struct b43_wldev *dev)
|
|
|
{
|
|
|
- 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);
|
|
|
+ b43_do_release_fw(&dev->fw.ucode);
|
|
|
+ b43_do_release_fw(&dev->fw.pcm);
|
|
|
+ b43_do_release_fw(&dev->fw.initvals);
|
|
|
+ b43_do_release_fw(&dev->fw.initvals_band);
|
|
|
}
|
|
|
|
|
|
static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
|
|
@@ -1963,12 +1963,10 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
|
|
|
b43warn(wl, text);
|
|
|
}
|
|
|
|
|
|
-static int do_request_fw(struct b43_wldev *dev,
|
|
|
- const char *name,
|
|
|
- struct b43_firmware_file *fw,
|
|
|
- bool silent)
|
|
|
+int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
|
|
+ const char *name,
|
|
|
+ struct b43_firmware_file *fw)
|
|
|
{
|
|
|
- char path[sizeof(modparam_fwpostfix) + 32];
|
|
|
const struct firmware *blob;
|
|
|
struct b43_fw_header *hdr;
|
|
|
u32 size;
|
|
@@ -1976,29 +1974,49 @@ static int do_request_fw(struct b43_wldev *dev,
|
|
|
|
|
|
if (!name) {
|
|
|
/* Don't fetch anything. Free possibly cached firmware. */
|
|
|
- do_release_fw(fw);
|
|
|
+ /* FIXME: We should probably keep it anyway, to save some headache
|
|
|
+ * on suspend/resume with multiband devices. */
|
|
|
+ b43_do_release_fw(fw);
|
|
|
return 0;
|
|
|
}
|
|
|
if (fw->filename) {
|
|
|
- if (strcmp(fw->filename, name) == 0)
|
|
|
+ if ((fw->type == ctx->req_type) &&
|
|
|
+ (strcmp(fw->filename, name) == 0))
|
|
|
return 0; /* Already have this fw. */
|
|
|
/* Free the cached firmware first. */
|
|
|
- do_release_fw(fw);
|
|
|
+ /* FIXME: We should probably do this later after we successfully
|
|
|
+ * got the new fw. This could reduce headache with multiband devices.
|
|
|
+ * We could also redesign this to cache the firmware for all possible
|
|
|
+ * bands all the time. */
|
|
|
+ b43_do_release_fw(fw);
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (ctx->req_type) {
|
|
|
+ case B43_FWTYPE_PROPRIETARY:
|
|
|
+ snprintf(ctx->fwname, sizeof(ctx->fwname),
|
|
|
+ "b43%s/%s.fw",
|
|
|
+ modparam_fwpostfix, name);
|
|
|
+ break;
|
|
|
+ case B43_FWTYPE_OPENSOURCE:
|
|
|
+ snprintf(ctx->fwname, sizeof(ctx->fwname),
|
|
|
+ "b43-open%s/%s.fw",
|
|
|
+ modparam_fwpostfix, name);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ B43_WARN_ON(1);
|
|
|
+ return -ENOSYS;
|
|
|
}
|
|
|
-
|
|
|
- snprintf(path, ARRAY_SIZE(path),
|
|
|
- "b43%s/%s.fw",
|
|
|
- modparam_fwpostfix, name);
|
|
|
- err = request_firmware(&blob, path, dev->dev->dev);
|
|
|
+ err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
|
|
|
if (err == -ENOENT) {
|
|
|
- if (!silent) {
|
|
|
- b43err(dev->wl, "Firmware file \"%s\" not found\n",
|
|
|
- path);
|
|
|
- }
|
|
|
+ snprintf(ctx->errors[ctx->req_type],
|
|
|
+ sizeof(ctx->errors[ctx->req_type]),
|
|
|
+ "Firmware file \"%s\" not found\n", ctx->fwname);
|
|
|
return err;
|
|
|
} else if (err) {
|
|
|
- b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n",
|
|
|
- path, err);
|
|
|
+ snprintf(ctx->errors[ctx->req_type],
|
|
|
+ sizeof(ctx->errors[ctx->req_type]),
|
|
|
+ "Firmware file \"%s\" request failed (err=%d)\n",
|
|
|
+ ctx->fwname, err);
|
|
|
return err;
|
|
|
}
|
|
|
if (blob->size < sizeof(struct b43_fw_header))
|
|
@@ -2021,20 +2039,24 @@ static int do_request_fw(struct b43_wldev *dev,
|
|
|
|
|
|
fw->data = blob;
|
|
|
fw->filename = name;
|
|
|
+ fw->type = ctx->req_type;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
err_format:
|
|
|
- b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
|
|
|
+ snprintf(ctx->errors[ctx->req_type],
|
|
|
+ sizeof(ctx->errors[ctx->req_type]),
|
|
|
+ "Firmware file \"%s\" format error.\n", ctx->fwname);
|
|
|
release_firmware(blob);
|
|
|
|
|
|
return -EPROTO;
|
|
|
}
|
|
|
|
|
|
-static int b43_request_firmware(struct b43_wldev *dev)
|
|
|
+static int b43_try_request_fw(struct b43_request_fw_context *ctx)
|
|
|
{
|
|
|
- struct b43_firmware *fw = &dev->fw;
|
|
|
- const u8 rev = dev->dev->id.revision;
|
|
|
+ struct b43_wldev *dev = ctx->dev;
|
|
|
+ struct b43_firmware *fw = &ctx->dev->fw;
|
|
|
+ const u8 rev = ctx->dev->dev->id.revision;
|
|
|
const char *filename;
|
|
|
u32 tmshigh;
|
|
|
int err;
|
|
@@ -2049,7 +2071,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
|
|
|
filename = "ucode13";
|
|
|
else
|
|
|
goto err_no_ucode;
|
|
|
- err = do_request_fw(dev, filename, &fw->ucode, 0);
|
|
|
+ err = b43_do_request_fw(ctx, filename, &fw->ucode);
|
|
|
if (err)
|
|
|
goto err_load;
|
|
|
|
|
@@ -2061,7 +2083,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
|
|
|
else
|
|
|
goto err_no_pcm;
|
|
|
fw->pcm_request_failed = 0;
|
|
|
- err = do_request_fw(dev, filename, &fw->pcm, 1);
|
|
|
+ err = b43_do_request_fw(ctx, filename, &fw->pcm);
|
|
|
if (err == -ENOENT) {
|
|
|
/* We did not find a PCM file? Not fatal, but
|
|
|
* core rev <= 10 must do without hwcrypto then. */
|
|
@@ -2097,7 +2119,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
|
|
|
default:
|
|
|
goto err_no_initvals;
|
|
|
}
|
|
|
- err = do_request_fw(dev, filename, &fw->initvals, 0);
|
|
|
+ err = b43_do_request_fw(ctx, filename, &fw->initvals);
|
|
|
if (err)
|
|
|
goto err_load;
|
|
|
|
|
@@ -2131,30 +2153,34 @@ static int b43_request_firmware(struct b43_wldev *dev)
|
|
|
default:
|
|
|
goto err_no_initvals;
|
|
|
}
|
|
|
- err = do_request_fw(dev, filename, &fw->initvals_band, 0);
|
|
|
+ err = b43_do_request_fw(ctx, filename, &fw->initvals_band);
|
|
|
if (err)
|
|
|
goto err_load;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
-err_load:
|
|
|
- b43_print_fw_helptext(dev->wl, 1);
|
|
|
- goto error;
|
|
|
-
|
|
|
err_no_ucode:
|
|
|
- err = -ENODEV;
|
|
|
- b43err(dev->wl, "No microcode available for core rev %u\n", rev);
|
|
|
+ err = ctx->fatal_failure = -EOPNOTSUPP;
|
|
|
+ b43err(dev->wl, "The driver does not know which firmware (ucode) "
|
|
|
+ "is required for your device (wl-core rev %u)\n", rev);
|
|
|
goto error;
|
|
|
|
|
|
err_no_pcm:
|
|
|
- err = -ENODEV;
|
|
|
- b43err(dev->wl, "No PCM available for core rev %u\n", rev);
|
|
|
+ err = ctx->fatal_failure = -EOPNOTSUPP;
|
|
|
+ b43err(dev->wl, "The driver does not know which firmware (PCM) "
|
|
|
+ "is required for your device (wl-core rev %u)\n", rev);
|
|
|
goto error;
|
|
|
|
|
|
err_no_initvals:
|
|
|
- err = -ENODEV;
|
|
|
- b43err(dev->wl, "No Initial Values firmware file for PHY %u, "
|
|
|
- "core rev %u\n", dev->phy.type, rev);
|
|
|
+ err = ctx->fatal_failure = -EOPNOTSUPP;
|
|
|
+ b43err(dev->wl, "The driver does not know which firmware (initvals) "
|
|
|
+ "is required for your device (wl-core rev %u)\n", rev);
|
|
|
+ goto error;
|
|
|
+
|
|
|
+err_load:
|
|
|
+ /* We failed to load this firmware image. The error message
|
|
|
+ * already is in ctx->errors. Return and let our caller decide
|
|
|
+ * what to do. */
|
|
|
goto error;
|
|
|
|
|
|
error:
|
|
@@ -2162,6 +2188,48 @@ error:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int b43_request_firmware(struct b43_wldev *dev)
|
|
|
+{
|
|
|
+ struct b43_request_fw_context *ctx;
|
|
|
+ unsigned int i;
|
|
|
+ int err;
|
|
|
+ const char *errmsg;
|
|
|
+
|
|
|
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
|
|
+ if (!ctx)
|
|
|
+ return -ENOMEM;
|
|
|
+ ctx->dev = dev;
|
|
|
+
|
|
|
+ ctx->req_type = B43_FWTYPE_PROPRIETARY;
|
|
|
+ err = b43_try_request_fw(ctx);
|
|
|
+ if (!err)
|
|
|
+ goto out; /* Successfully loaded it. */
|
|
|
+ err = ctx->fatal_failure;
|
|
|
+ if (err)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ ctx->req_type = B43_FWTYPE_OPENSOURCE;
|
|
|
+ err = b43_try_request_fw(ctx);
|
|
|
+ if (!err)
|
|
|
+ goto out; /* Successfully loaded it. */
|
|
|
+ err = ctx->fatal_failure;
|
|
|
+ if (err)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* Could not find a usable firmware. Print the errors. */
|
|
|
+ for (i = 0; i < B43_NR_FWTYPES; i++) {
|
|
|
+ errmsg = ctx->errors[i];
|
|
|
+ if (strlen(errmsg))
|
|
|
+ b43err(dev->wl, errmsg);
|
|
|
+ }
|
|
|
+ b43_print_fw_helptext(dev->wl, 1);
|
|
|
+ err = -ENOENT;
|
|
|
+
|
|
|
+out:
|
|
|
+ kfree(ctx);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static int b43_upload_microcode(struct b43_wldev *dev)
|
|
|
{
|
|
|
const size_t hdr_len = sizeof(struct b43_fw_header);
|