diff --git a/drivers/media/tuners/xc2028.c b/drivers/media/tuners/xc2028.c index 8e6638e5f688..a9c1f9ea74e8 100644 --- a/drivers/media/tuners/xc2028.c +++ b/drivers/media/tuners/xc2028.c @@ -116,6 +116,7 @@ struct xc2028_data { struct xc2028_ctrl ctrl; struct firmware_properties cur_fw; + struct completion fw_completion; struct mutex lock; }; @@ -1329,6 +1330,9 @@ static void xc2028_dvb_release(struct dvb_frontend *fe) mutex_lock(&xc2028_list_mutex); + if (priv->state == XC2028_WAITING_FIRMWARE) + wait_for_completion(&priv->fw_completion); + /* only perform final cleanup if this is the last instance */ if (hybrid_tuner_report_instance_count(priv) == 1) free_firmware(priv); @@ -1361,30 +1365,21 @@ static void load_firmware_cb(const struct firmware *fw, void *context) { struct dvb_frontend *fe = context; - struct xc2028_data *priv; + struct xc2028_data *priv = fe->tuner_priv; int rc; - if (!fe) { - pr_warn("xc2028: No frontend in %s\n", __func__); - return; - } - - priv = fe->tuner_priv; - tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error"); if (!fw) { tuner_err("Could not load firmware %s.\n", priv->fname); priv->state = XC2028_NODEV; - return; + } else { + rc = load_all_firmwares(fe, fw); + release_firmware(fw); + if (rc == 0) + priv->state = XC2028_ACTIVE; } - rc = load_all_firmwares(fe, fw); - - release_firmware(fw); - - if (rc < 0) - return; - priv->state = XC2028_ACTIVE; + complete(&priv->fw_completion); } static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) @@ -1433,8 +1428,10 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) tuner_err("Failed to request firmware %s\n", priv->fname); priv->state = XC2028_NODEV; - } else + } else { + init_completion(&priv->fw_completion); priv->state = XC2028_WAITING_FIRMWARE; + } } unlock: mutex_unlock(&priv->lock);