Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 215659d1 authored by Ian Armstrong's avatar Ian Armstrong Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB: ivtv: Automatic firmware reload



If the firmware has failed, this patch will automatically reload &
restart the card. The previous card state will be restored on a
successful restart.  Firmware reload will only happen if neither the
encoder or decoder is active.  If the card is busy then behaviour is as
before, returning -EIO on device access until the reload can occur. On
cards that support video output, coloured bars will be displayed during
the reload.

Andy Walls (ivtv maintainer and patch committer) made minor tweaks to
comments and the logged messages, but nothing substantial otherwise.

Signed-off-by: default avatarIan Armstrong <ian@iarmst.demon.co.uk>
Signed-off-by: default avatarAndy Walls <awalls@md.metrocast.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 914610e8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1444,6 +1444,7 @@ EXPORT_SYMBOL(ivtv_udma_unmap);
EXPORT_SYMBOL(ivtv_udma_alloc);
EXPORT_SYMBOL(ivtv_udma_prepare);
EXPORT_SYMBOL(ivtv_init_on_first_open);
EXPORT_SYMBOL(ivtv_firmware_check);

module_init(module_start);
module_exit(module_cleanup);
+1 −0
Original line number Diff line number Diff line
@@ -737,6 +737,7 @@ struct ivtv {
	struct v4l2_rect osd_rect;      /* current OSD position and size */
	struct v4l2_rect main_rect;     /* current Main window position and size */
	struct osd_info *osd_info;      /* ivtvfb private OSD info */
	void (*ivtvfb_restore)(struct ivtv *itv); /* Used for a warm start */
};

static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
+15 −9
Original line number Diff line number Diff line
@@ -536,9 +536,13 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
			return -EBUSY;
		}
		rc = ivtv_start_v4l2_decode_stream(s, 0);
		if (rc < 0) {
			if (rc == -EAGAIN)
				rc = ivtv_start_v4l2_decode_stream(s, 0);
			if (rc < 0)
				return rc;
		}
	}
	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
		return ivtv_set_speed(itv, speed);
	return 0;
@@ -926,19 +930,21 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
	IVTV_DEBUG_FILE("open %s\n", s->name);

#ifdef CONFIG_VIDEO_ADV_DEBUG
	/* Unless ivtv_fw_debug is set, error out if firmware dead. */
	if (ivtv_fw_debug) {
		IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
			  video_device_node_name(vdev));
		IVTV_WARN("Selected firmware errors will be ignored\n");
	}

	/* Unless ivtv_fw_debug is set, error out if firmware dead. */
	if (ivtv_firmware_check(itv, "ivtv_serialized_open") && !ivtv_fw_debug)
		return -EIO;
	} else {
#else
	if (ivtv_firmware_check(itv, "ivtv_serialized_open"))
		return -EIO;
	if (1) {
#endif
		res = ivtv_firmware_check(itv, "ivtv_serialized_open");
		if (res == -EAGAIN)
			res = ivtv_firmware_check(itv, "ivtv_serialized_open");
		if (res < 0)
			return -EIO;
	}

	if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
+76 −0
Original line number Diff line number Diff line
@@ -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;
}
+8 −0
Original line number Diff line number Diff line
@@ -377,3 +377,11 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
	for (i = 0; i < argc; i++, p++)
		data[i] = readl(p);
}

/* Wipe api cache */
void ivtv_mailbox_cache_invalidate(struct ivtv *itv)
{
	int i;
	for (i = 0; i < 256; i++)
		itv->api_cache[i].last_jiffies = 0;
}
Loading