aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv/ivtv-firmware.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-firmware.c')
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index efb288d..d8bf2b0 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -23,7 +23,10 @@
#include "ivtv-mailbox.h"
#include "ivtv-firmware.h"
#include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
#include <linux/firmware.h>
+#include <media/saa7127.h>
#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE
#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6
@@ -272,6 +275,58 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
}
+/* Try to restart the card & restore previous settings */
+int ivtv_firmware_restart(struct ivtv *itv)
+{
+ int rc = 0;
+ v4l2_std_id std;
+ struct ivtv_open_id fh;
+ fh.itv = itv;
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+ /* Display test image during restart */
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+ SAA7127_INPUT_TYPE_TEST_IMAGE,
+ itv->card->video_outputs[itv->active_output].video_output,
+ 0);
+
+ mutex_lock(&itv->udma.lock);
+
+ rc = ivtv_firmware_init(itv);
+ if (rc) {
+ mutex_unlock(&itv->udma.lock);
+ return rc;
+ }
+
+ /* Allow settings to reload */
+ ivtv_mailbox_cache_invalidate(itv);
+
+ /* Restore video standard */
+ std = itv->std;
+ itv->std = 0;
+ ivtv_s_std(NULL, &fh, &std);
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_init_mpeg_decoder(itv);
+
+ /* Restore framebuffer if active */
+ if (itv->ivtvfb_restore)
+ itv->ivtvfb_restore(itv);
+
+ /* Restore alpha settings */
+ ivtv_set_osd_alpha(itv);
+
+ /* Restore normal output */
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+ SAA7127_INPUT_TYPE_NORMAL,
+ itv->card->video_outputs[itv->active_output].video_output,
+ 0);
+ }
+
+ mutex_unlock(&itv->udma.lock);
+ return rc;
+}
+
/* Check firmware running state. The checks fall through
allowing multiple failures to be logged. */
int ivtv_firmware_check(struct ivtv *itv, char *where)
@@ -315,5 +370,26 @@ int ivtv_firmware_check(struct ivtv *itv, char *where)
}
}
+ /* If something failed & currently idle, try to reload */
+ if (res && !atomic_read(&itv->capturing) &&
+ !atomic_read(&itv->decoding)) {
+ IVTV_INFO("Detected in %s that firmware had failed - "
+ "Reloading\n", where);
+ res = ivtv_firmware_restart(itv);
+ /*
+ * Even if restarted ok, still signal a problem had occured.
+ * The caller can come through this function again to check
+ * if things are really ok after the restart.
+ */
+ if (!res) {
+ IVTV_INFO("Firmware restart okay\n");
+ res = -EAGAIN;
+ } else {
+ IVTV_INFO("Firmware restart failed\n");
+ }
+ } else if (res) {
+ res = -EIO;
+ }
+
return res;
}