V4L/DVB: ivtv: Add firmare monitoring and debug mode to ignore firmware problems
>From Ian's e-mail: When a device is opened the firmware state will be checked. If it isn't responding then the open will fail with -EIO. Due to the nature of the hardware, a single failed check will block everything since we don't know exactly what has failed. A side effect of this is the blocking of debug access, so an additional debug level has been created which allows the block to be bypassed. Andy Walls' modifications: I modified Ian's patch to add a separate fw_debug module parameter to change the driver's behavior, as opposed to using the normal debug module parameter. The fw_debug module parameter is only available when CONFIG_VIDEO_ADV_DEBUG is set. I also made some minor whitespace adjustments and changed some warning messages to be a bit more specific. s/happy/glad/g Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk> Signed-off-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
a5ba334cda
commit
914610e8c5
@@ -130,6 +130,9 @@ static int ivtv_yuv_threshold = -1;
|
|||||||
static int ivtv_pci_latency = 1;
|
static int ivtv_pci_latency = 1;
|
||||||
|
|
||||||
int ivtv_debug;
|
int ivtv_debug;
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
int ivtv_fw_debug;
|
||||||
|
#endif
|
||||||
|
|
||||||
static int tunertype = -1;
|
static int tunertype = -1;
|
||||||
static int newi2c = -1;
|
static int newi2c = -1;
|
||||||
@@ -141,6 +144,9 @@ module_param_string(pal, pal, sizeof(pal), 0644);
|
|||||||
module_param_string(secam, secam, sizeof(secam), 0644);
|
module_param_string(secam, secam, sizeof(secam), 0644);
|
||||||
module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
|
module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
|
||||||
module_param_named(debug,ivtv_debug, int, 0644);
|
module_param_named(debug,ivtv_debug, int, 0644);
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
module_param_named(fw_debug, ivtv_fw_debug, int, 0644);
|
||||||
|
#endif
|
||||||
module_param(ivtv_pci_latency, int, 0644);
|
module_param(ivtv_pci_latency, int, 0644);
|
||||||
module_param(ivtv_yuv_mode, int, 0644);
|
module_param(ivtv_yuv_mode, int, 0644);
|
||||||
module_param(ivtv_yuv_threshold, int, 0644);
|
module_param(ivtv_yuv_threshold, int, 0644);
|
||||||
@@ -217,6 +223,10 @@ MODULE_PARM_DESC(debug,
|
|||||||
"\t\t\t 256/0x0100: yuv\n"
|
"\t\t\t 256/0x0100: yuv\n"
|
||||||
"\t\t\t 512/0x0200: i2c\n"
|
"\t\t\t 512/0x0200: i2c\n"
|
||||||
"\t\t\t1024/0x0400: high volume\n");
|
"\t\t\t1024/0x0400: high volume\n");
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
MODULE_PARM_DESC(fw_debug,
|
||||||
|
"Enable code for debugging firmware problems. Default: 0\n");
|
||||||
|
#endif
|
||||||
MODULE_PARM_DESC(ivtv_pci_latency,
|
MODULE_PARM_DESC(ivtv_pci_latency,
|
||||||
"Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
|
"Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
|
||||||
"\t\t\tDefault: Yes");
|
"\t\t\tDefault: Yes");
|
||||||
@@ -1425,6 +1435,9 @@ EXPORT_SYMBOL(ivtv_vapi);
|
|||||||
EXPORT_SYMBOL(ivtv_vapi_result);
|
EXPORT_SYMBOL(ivtv_vapi_result);
|
||||||
EXPORT_SYMBOL(ivtv_clear_irq_mask);
|
EXPORT_SYMBOL(ivtv_clear_irq_mask);
|
||||||
EXPORT_SYMBOL(ivtv_debug);
|
EXPORT_SYMBOL(ivtv_debug);
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
EXPORT_SYMBOL(ivtv_fw_debug);
|
||||||
|
#endif
|
||||||
EXPORT_SYMBOL(ivtv_reset_ir_gpio);
|
EXPORT_SYMBOL(ivtv_reset_ir_gpio);
|
||||||
EXPORT_SYMBOL(ivtv_udma_setup);
|
EXPORT_SYMBOL(ivtv_udma_setup);
|
||||||
EXPORT_SYMBOL(ivtv_udma_unmap);
|
EXPORT_SYMBOL(ivtv_udma_unmap);
|
||||||
|
@@ -122,6 +122,9 @@
|
|||||||
|
|
||||||
/* debugging */
|
/* debugging */
|
||||||
extern int ivtv_debug;
|
extern int ivtv_debug;
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
extern int ivtv_fw_debug;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define IVTV_DBGFLG_WARN (1 << 0)
|
#define IVTV_DBGFLG_WARN (1 << 0)
|
||||||
#define IVTV_DBGFLG_INFO (1 << 1)
|
#define IVTV_DBGFLG_INFO (1 << 1)
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include "ivtv-yuv.h"
|
#include "ivtv-yuv.h"
|
||||||
#include "ivtv-ioctl.h"
|
#include "ivtv-ioctl.h"
|
||||||
#include "ivtv-cards.h"
|
#include "ivtv-cards.h"
|
||||||
|
#include "ivtv-firmware.h"
|
||||||
#include <media/v4l2-event.h>
|
#include <media/v4l2-event.h>
|
||||||
#include <media/saa7115.h>
|
#include <media/saa7115.h>
|
||||||
|
|
||||||
@@ -526,6 +527,7 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
|
|||||||
{
|
{
|
||||||
struct ivtv *itv = id->itv;
|
struct ivtv *itv = id->itv;
|
||||||
struct ivtv_stream *s = &itv->streams[id->type];
|
struct ivtv_stream *s = &itv->streams[id->type];
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (atomic_read(&itv->decoding) == 0) {
|
if (atomic_read(&itv->decoding) == 0) {
|
||||||
if (ivtv_claim_stream(id, s->type)) {
|
if (ivtv_claim_stream(id, s->type)) {
|
||||||
@@ -533,7 +535,9 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
|
|||||||
IVTV_DEBUG_WARN("start decode, stream already claimed\n");
|
IVTV_DEBUG_WARN("start decode, stream already claimed\n");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
ivtv_start_v4l2_decode_stream(s, 0);
|
rc = ivtv_start_v4l2_decode_stream(s, 0);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
|
if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
|
||||||
return ivtv_set_speed(itv, speed);
|
return ivtv_set_speed(itv, speed);
|
||||||
@@ -912,12 +916,30 @@ int ivtv_v4l2_close(struct file *filp)
|
|||||||
|
|
||||||
static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
|
static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
struct video_device *vdev = video_devdata(filp);
|
||||||
|
#endif
|
||||||
struct ivtv *itv = s->itv;
|
struct ivtv *itv = s->itv;
|
||||||
struct ivtv_open_id *item;
|
struct ivtv_open_id *item;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
IVTV_DEBUG_FILE("open %s\n", s->name);
|
IVTV_DEBUG_FILE("open %s\n", s->name);
|
||||||
|
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
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
|
||||||
|
if (ivtv_firmware_check(itv, "ivtv_serialized_open"))
|
||||||
|
return -EIO;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
|
if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
|
||||||
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
|
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@@ -271,3 +271,49 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
|
|||||||
}
|
}
|
||||||
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
|
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check firmware running state. The checks fall through
|
||||||
|
allowing multiple failures to be logged. */
|
||||||
|
int ivtv_firmware_check(struct ivtv *itv, char *where)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
/* Check encoder is still running */
|
||||||
|
if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) {
|
||||||
|
IVTV_WARN("Encoder has died : %s\n", where);
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also check audio. Only check if not in use & encoder is okay */
|
||||||
|
if (!res && !atomic_read(&itv->capturing) &&
|
||||||
|
(!atomic_read(&itv->decoding) ||
|
||||||
|
(atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV,
|
||||||
|
&itv->i_flags)))) {
|
||||||
|
|
||||||
|
if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) {
|
||||||
|
IVTV_WARN("Audio has died (Encoder OK) : %s\n", where);
|
||||||
|
res = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
|
||||||
|
/* Second audio check. Skip if audio already failed */
|
||||||
|
if (res != -2 && read_dec(0x100) != read_dec(0x104)) {
|
||||||
|
/* Wait & try again to be certain. */
|
||||||
|
ivtv_msleep_timeout(14, 0);
|
||||||
|
if (read_dec(0x100) != read_dec(0x104)) {
|
||||||
|
IVTV_WARN("Audio has died (Decoder) : %s\n",
|
||||||
|
where);
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check decoder is still running */
|
||||||
|
if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) {
|
||||||
|
IVTV_WARN("Decoder has died : %s\n", where);
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@@ -26,5 +26,6 @@ int ivtv_firmware_init(struct ivtv *itv);
|
|||||||
void ivtv_firmware_versions(struct ivtv *itv);
|
void ivtv_firmware_versions(struct ivtv *itv);
|
||||||
void ivtv_halt_firmware(struct ivtv *itv);
|
void ivtv_halt_firmware(struct ivtv *itv);
|
||||||
void ivtv_init_mpeg_decoder(struct ivtv *itv);
|
void ivtv_init_mpeg_decoder(struct ivtv *itv);
|
||||||
|
int ivtv_firmware_check(struct ivtv *itv, char *where);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
#include "ivtv-yuv.h"
|
#include "ivtv-yuv.h"
|
||||||
#include "ivtv-cards.h"
|
#include "ivtv-cards.h"
|
||||||
#include "ivtv-streams.h"
|
#include "ivtv-streams.h"
|
||||||
|
#include "ivtv-firmware.h"
|
||||||
#include <media/v4l2-event.h>
|
#include <media/v4l2-event.h>
|
||||||
|
|
||||||
static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
|
static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
|
||||||
@@ -674,12 +675,17 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
|
|||||||
/* Decoder sometimes dies here, so wait a moment */
|
/* Decoder sometimes dies here, so wait a moment */
|
||||||
ivtv_msleep_timeout(10, 0);
|
ivtv_msleep_timeout(10, 0);
|
||||||
|
|
||||||
|
/* Known failure point for firmware, so check */
|
||||||
|
if (ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream") < 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
|
int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
|
||||||
{
|
{
|
||||||
struct ivtv *itv = s->itv;
|
struct ivtv *itv = s->itv;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (s->vdev == NULL)
|
if (s->vdev == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -689,7 +695,11 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
|
|||||||
|
|
||||||
IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
|
IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
|
||||||
|
|
||||||
ivtv_setup_v4l2_decode_stream(s);
|
rc = ivtv_setup_v4l2_decode_stream(s);
|
||||||
|
if (rc < 0) {
|
||||||
|
clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* set dma size to 65536 bytes */
|
/* set dma size to 65536 bytes */
|
||||||
ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
|
ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
|
||||||
|
Reference in New Issue
Block a user