diff options
author | Ian Armstrong <ian@iarmst.demon.co.uk> | 2010-06-12 12:33:21 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-02 13:47:55 -0400 |
commit | 914610e8c508224a6fb9fb501ed4bda25b340ba6 (patch) | |
tree | 461d7bf99143ddda1847be4e9095a65268530ec3 | |
parent | a5ba334cda924eb0ae4754321ad7fc292c5a5288 (diff) |
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>
-rw-r--r-- | drivers/media/video/ivtv/ivtv-driver.c | 13 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-driver.h | 3 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-fileops.c | 24 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-firmware.c | 46 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-firmware.h | 1 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-streams.c | 12 |
6 files changed, 97 insertions, 2 deletions
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 1b79475ca134..3737797f20ea 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c | |||
@@ -130,6 +130,9 @@ static int ivtv_yuv_threshold = -1; | |||
130 | static int ivtv_pci_latency = 1; | 130 | static int ivtv_pci_latency = 1; |
131 | 131 | ||
132 | int ivtv_debug; | 132 | int ivtv_debug; |
133 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
134 | int ivtv_fw_debug; | ||
135 | #endif | ||
133 | 136 | ||
134 | static int tunertype = -1; | 137 | static int tunertype = -1; |
135 | static int newi2c = -1; | 138 | static int newi2c = -1; |
@@ -141,6 +144,9 @@ module_param_string(pal, pal, sizeof(pal), 0644); | |||
141 | module_param_string(secam, secam, sizeof(secam), 0644); | 144 | module_param_string(secam, secam, sizeof(secam), 0644); |
142 | module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); | 145 | module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); |
143 | module_param_named(debug,ivtv_debug, int, 0644); | 146 | module_param_named(debug,ivtv_debug, int, 0644); |
147 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
148 | module_param_named(fw_debug, ivtv_fw_debug, int, 0644); | ||
149 | #endif | ||
144 | module_param(ivtv_pci_latency, int, 0644); | 150 | module_param(ivtv_pci_latency, int, 0644); |
145 | module_param(ivtv_yuv_mode, int, 0644); | 151 | module_param(ivtv_yuv_mode, int, 0644); |
146 | module_param(ivtv_yuv_threshold, int, 0644); | 152 | module_param(ivtv_yuv_threshold, int, 0644); |
@@ -217,6 +223,10 @@ MODULE_PARM_DESC(debug, | |||
217 | "\t\t\t 256/0x0100: yuv\n" | 223 | "\t\t\t 256/0x0100: yuv\n" |
218 | "\t\t\t 512/0x0200: i2c\n" | 224 | "\t\t\t 512/0x0200: i2c\n" |
219 | "\t\t\t1024/0x0400: high volume\n"); | 225 | "\t\t\t1024/0x0400: high volume\n"); |
226 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
227 | MODULE_PARM_DESC(fw_debug, | ||
228 | "Enable code for debugging firmware problems. Default: 0\n"); | ||
229 | #endif | ||
220 | MODULE_PARM_DESC(ivtv_pci_latency, | 230 | MODULE_PARM_DESC(ivtv_pci_latency, |
221 | "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" | 231 | "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" |
222 | "\t\t\tDefault: Yes"); | 232 | "\t\t\tDefault: Yes"); |
@@ -1425,6 +1435,9 @@ EXPORT_SYMBOL(ivtv_vapi); | |||
1425 | EXPORT_SYMBOL(ivtv_vapi_result); | 1435 | EXPORT_SYMBOL(ivtv_vapi_result); |
1426 | EXPORT_SYMBOL(ivtv_clear_irq_mask); | 1436 | EXPORT_SYMBOL(ivtv_clear_irq_mask); |
1427 | EXPORT_SYMBOL(ivtv_debug); | 1437 | EXPORT_SYMBOL(ivtv_debug); |
1438 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1439 | EXPORT_SYMBOL(ivtv_fw_debug); | ||
1440 | #endif | ||
1428 | EXPORT_SYMBOL(ivtv_reset_ir_gpio); | 1441 | EXPORT_SYMBOL(ivtv_reset_ir_gpio); |
1429 | EXPORT_SYMBOL(ivtv_udma_setup); | 1442 | EXPORT_SYMBOL(ivtv_udma_setup); |
1430 | EXPORT_SYMBOL(ivtv_udma_unmap); | 1443 | EXPORT_SYMBOL(ivtv_udma_unmap); |
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 5b45fd2b2645..c038dc8beb3c 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h | |||
@@ -122,6 +122,9 @@ | |||
122 | 122 | ||
123 | /* debugging */ | 123 | /* debugging */ |
124 | extern int ivtv_debug; | 124 | extern int ivtv_debug; |
125 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
126 | extern int ivtv_fw_debug; | ||
127 | #endif | ||
125 | 128 | ||
126 | #define IVTV_DBGFLG_WARN (1 << 0) | 129 | #define IVTV_DBGFLG_WARN (1 << 0) |
127 | #define IVTV_DBGFLG_INFO (1 << 1) | 130 | #define IVTV_DBGFLG_INFO (1 << 1) |
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 3c2cc270ccd5..3fb21e1406a1 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "ivtv-yuv.h" | 32 | #include "ivtv-yuv.h" |
33 | #include "ivtv-ioctl.h" | 33 | #include "ivtv-ioctl.h" |
34 | #include "ivtv-cards.h" | 34 | #include "ivtv-cards.h" |
35 | #include "ivtv-firmware.h" | ||
35 | #include <media/v4l2-event.h> | 36 | #include <media/v4l2-event.h> |
36 | #include <media/saa7115.h> | 37 | #include <media/saa7115.h> |
37 | 38 | ||
@@ -526,6 +527,7 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed) | |||
526 | { | 527 | { |
527 | struct ivtv *itv = id->itv; | 528 | struct ivtv *itv = id->itv; |
528 | struct ivtv_stream *s = &itv->streams[id->type]; | 529 | struct ivtv_stream *s = &itv->streams[id->type]; |
530 | int rc; | ||
529 | 531 | ||
530 | if (atomic_read(&itv->decoding) == 0) { | 532 | if (atomic_read(&itv->decoding) == 0) { |
531 | if (ivtv_claim_stream(id, s->type)) { | 533 | if (ivtv_claim_stream(id, s->type)) { |
@@ -533,7 +535,9 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed) | |||
533 | IVTV_DEBUG_WARN("start decode, stream already claimed\n"); | 535 | IVTV_DEBUG_WARN("start decode, stream already claimed\n"); |
534 | return -EBUSY; | 536 | return -EBUSY; |
535 | } | 537 | } |
536 | ivtv_start_v4l2_decode_stream(s, 0); | 538 | rc = ivtv_start_v4l2_decode_stream(s, 0); |
539 | if (rc < 0) | ||
540 | return rc; | ||
537 | } | 541 | } |
538 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG) | 542 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG) |
539 | return ivtv_set_speed(itv, speed); | 543 | return ivtv_set_speed(itv, speed); |
@@ -912,12 +916,30 @@ int ivtv_v4l2_close(struct file *filp) | |||
912 | 916 | ||
913 | static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) | 917 | static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) |
914 | { | 918 | { |
919 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
920 | struct video_device *vdev = video_devdata(filp); | ||
921 | #endif | ||
915 | struct ivtv *itv = s->itv; | 922 | struct ivtv *itv = s->itv; |
916 | struct ivtv_open_id *item; | 923 | struct ivtv_open_id *item; |
917 | int res = 0; | 924 | int res = 0; |
918 | 925 | ||
919 | IVTV_DEBUG_FILE("open %s\n", s->name); | 926 | IVTV_DEBUG_FILE("open %s\n", s->name); |
920 | 927 | ||
928 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
929 | if (ivtv_fw_debug) { | ||
930 | IVTV_WARN("Opening %s with dead firmware lockout disabled\n", | ||
931 | video_device_node_name(vdev)); | ||
932 | IVTV_WARN("Selected firmware errors will be ignored\n"); | ||
933 | } | ||
934 | |||
935 | /* Unless ivtv_fw_debug is set, error out if firmware dead. */ | ||
936 | if (ivtv_firmware_check(itv, "ivtv_serialized_open") && !ivtv_fw_debug) | ||
937 | return -EIO; | ||
938 | #else | ||
939 | if (ivtv_firmware_check(itv, "ivtv_serialized_open")) | ||
940 | return -EIO; | ||
941 | #endif | ||
942 | |||
921 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG && | 943 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG && |
922 | test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) | 944 | test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) |
923 | return -EBUSY; | 945 | return -EBUSY; |
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c index a71e8ba306b0..efb288d34ca3 100644 --- a/drivers/media/video/ivtv/ivtv-firmware.c +++ b/drivers/media/video/ivtv/ivtv-firmware.c | |||
@@ -271,3 +271,49 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv) | |||
271 | } | 271 | } |
272 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); | 272 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); |
273 | } | 273 | } |
274 | |||
275 | /* Check firmware running state. The checks fall through | ||
276 | allowing multiple failures to be logged. */ | ||
277 | int ivtv_firmware_check(struct ivtv *itv, char *where) | ||
278 | { | ||
279 | int res = 0; | ||
280 | |||
281 | /* Check encoder is still running */ | ||
282 | if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) { | ||
283 | IVTV_WARN("Encoder has died : %s\n", where); | ||
284 | res = -1; | ||
285 | } | ||
286 | |||
287 | /* Also check audio. Only check if not in use & encoder is okay */ | ||
288 | if (!res && !atomic_read(&itv->capturing) && | ||
289 | (!atomic_read(&itv->decoding) || | ||
290 | (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV, | ||
291 | &itv->i_flags)))) { | ||
292 | |||
293 | if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) { | ||
294 | IVTV_WARN("Audio has died (Encoder OK) : %s\n", where); | ||
295 | res = -2; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { | ||
300 | /* Second audio check. Skip if audio already failed */ | ||
301 | if (res != -2 && read_dec(0x100) != read_dec(0x104)) { | ||
302 | /* Wait & try again to be certain. */ | ||
303 | ivtv_msleep_timeout(14, 0); | ||
304 | if (read_dec(0x100) != read_dec(0x104)) { | ||
305 | IVTV_WARN("Audio has died (Decoder) : %s\n", | ||
306 | where); | ||
307 | res = -1; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | /* Check decoder is still running */ | ||
312 | if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) { | ||
313 | IVTV_WARN("Decoder has died : %s\n", where); | ||
314 | res = -1; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | return res; | ||
319 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h index 041ba94e65bc..52bb4e5598fd 100644 --- a/drivers/media/video/ivtv/ivtv-firmware.h +++ b/drivers/media/video/ivtv/ivtv-firmware.h | |||
@@ -26,5 +26,6 @@ int ivtv_firmware_init(struct ivtv *itv); | |||
26 | void ivtv_firmware_versions(struct ivtv *itv); | 26 | void ivtv_firmware_versions(struct ivtv *itv); |
27 | void ivtv_halt_firmware(struct ivtv *itv); | 27 | void ivtv_halt_firmware(struct ivtv *itv); |
28 | void ivtv_init_mpeg_decoder(struct ivtv *itv); | 28 | void ivtv_init_mpeg_decoder(struct ivtv *itv); |
29 | int ivtv_firmware_check(struct ivtv *itv, char *where); | ||
29 | 30 | ||
30 | #endif | 31 | #endif |
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index a937e2ff9b6e..f0dd011a2ccc 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include "ivtv-yuv.h" | 42 | #include "ivtv-yuv.h" |
43 | #include "ivtv-cards.h" | 43 | #include "ivtv-cards.h" |
44 | #include "ivtv-streams.h" | 44 | #include "ivtv-streams.h" |
45 | #include "ivtv-firmware.h" | ||
45 | #include <media/v4l2-event.h> | 46 | #include <media/v4l2-event.h> |
46 | 47 | ||
47 | static const struct v4l2_file_operations ivtv_v4l2_enc_fops = { | 48 | 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) | |||
674 | /* Decoder sometimes dies here, so wait a moment */ | 675 | /* Decoder sometimes dies here, so wait a moment */ |
675 | ivtv_msleep_timeout(10, 0); | 676 | ivtv_msleep_timeout(10, 0); |
676 | 677 | ||
678 | /* Known failure point for firmware, so check */ | ||
679 | if (ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream") < 0) | ||
680 | return -EIO; | ||
681 | |||
677 | return 0; | 682 | return 0; |
678 | } | 683 | } |
679 | 684 | ||
680 | int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) | 685 | int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) |
681 | { | 686 | { |
682 | struct ivtv *itv = s->itv; | 687 | struct ivtv *itv = s->itv; |
688 | int rc; | ||
683 | 689 | ||
684 | if (s->vdev == NULL) | 690 | if (s->vdev == NULL) |
685 | return -EINVAL; | 691 | return -EINVAL; |
@@ -689,7 +695,11 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) | |||
689 | 695 | ||
690 | IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); | 696 | IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); |
691 | 697 | ||
692 | ivtv_setup_v4l2_decode_stream(s); | 698 | rc = ivtv_setup_v4l2_decode_stream(s); |
699 | if (rc < 0) { | ||
700 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
701 | return rc; | ||
702 | } | ||
693 | 703 | ||
694 | /* set dma size to 65536 bytes */ | 704 | /* set dma size to 65536 bytes */ |
695 | ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); | 705 | ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); |