[PATCH 156/510] staging/easycap: Add option to show conspicuous indication of signal loss

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Mike Thomas <rmthomas@xxxxxxxxxxx>

A new module parameter turns on the option of displaying a testcard when
the analogue input signal is lost (more precisely: when the hardware
detects no field/frame synchronization).  This feature has been requested
in the context of security cameras used at night.

Signed-off-by: Mike Thomas <rmthomas@xxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxx>
---
 drivers/staging/easycap/easycap.h          |    2 +
 drivers/staging/easycap/easycap_main.c     |   71 +++++++++++++++++++------
 drivers/staging/easycap/easycap_testcard.c |   80 +++++++++++++++++++---------
 3 files changed, 112 insertions(+), 41 deletions(-)

diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h
index 7c4cf7a..e9410b7 100644
--- a/drivers/staging/easycap/easycap.h
+++ b/drivers/staging/easycap/easycap.h
@@ -154,6 +154,7 @@
 #error video_isoc_buffer[.] will not be big enough
 #endif
 #define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY
+#define VIDEO_LOST_TOLERATE 50
 /*---------------------------------------------------------------------------*/
 /*
  *  VIDEO BUFFERS
@@ -344,6 +345,7 @@ int usec;
 int tolerate;
 int skip;
 int skipped;
+int lost[INPUT_MANY];
 int merit[180];
 
 struct timeval timeval0;
diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c
index 988feee..21450e8 100644
--- a/drivers/staging/easycap/easycap_main.c
+++ b/drivers/staging/easycap/easycap_main.c
@@ -33,7 +33,9 @@
 #include "easycap_ioctl.h"
 
 int debug;
+int bars;
 module_param(debug, int, S_IRUGO | S_IWUSR);
+module_param(bars, int, S_IRUGO | S_IWUSR);
 
 /*---------------------------------------------------------------------------*/
 /*
@@ -868,7 +870,7 @@ return 0;
 void
 easycap_delete(struct kref *pkref)
 {
-int k, m, lost;
+int k, m, gone;
 int allocation_video_urb, allocation_video_page, allocation_video_struct;
 int allocation_audio_urb, allocation_audio_page, allocation_audio_struct;
 int registered_video, registered_audio;
@@ -941,7 +943,7 @@ for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY;  k++) {
 JOM(4, "isoc video buffers freed: %i pages\n", m * (0x01 << VIDEO_ISOC_ORDER));
 /*---------------------------------------------------------------------------*/
 JOM(4, "freeing video field buffers.\n");
-lost = 0;
+gone = 0;
 for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
 	for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
 		if ((void *)NULL != peasycap->field_buffer[k][m].pgo) {
@@ -949,14 +951,14 @@ for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
 					(peasycap->field_buffer[k][m].pgo));
 			peasycap->field_buffer[k][m].pgo = (void *)NULL;
 			peasycap->allocation_video_page -= 1;
-			lost++;
+			gone++;
 		}
 	}
 }
-JOM(4, "video field buffers freed: %i pages\n", lost);
+JOM(4, "video field buffers freed: %i pages\n", gone);
 /*---------------------------------------------------------------------------*/
 JOM(4, "freeing video frame buffers.\n");
-lost = 0;
+gone = 0;
 for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
 	for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
 		if ((void *)NULL != peasycap->frame_buffer[k][m].pgo) {
@@ -964,11 +966,11 @@ for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
 					(peasycap->frame_buffer[k][m].pgo));
 			peasycap->frame_buffer[k][m].pgo = (void *)NULL;
 			peasycap->allocation_video_page -= 1;
-			lost++;
+			gone++;
 		}
 	}
 }
-JOM(4, "video frame buffers freed: %i pages\n", lost);
+JOM(4, "video frame buffers freed: %i pages\n", gone);
 /*---------------------------------------------------------------------------*/
 /*
  *  FREE AUDIO.
@@ -1027,16 +1029,16 @@ JOM(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \
 					m * (0x01 << AUDIO_ISOC_ORDER));
 /*---------------------------------------------------------------------------*/
 JOM(4, "freeing audio buffers.\n");
-lost = 0;
+gone = 0;
 for (k = 0;  k < peasycap->audio_buffer_page_many;  k++) {
 	if ((void *)NULL != peasycap->audio_buffer[k].pgo) {
 		free_page((unsigned long)(peasycap->audio_buffer[k].pgo));
 		peasycap->audio_buffer[k].pgo = (void *)NULL;
 		peasycap->allocation_audio_page -= 1;
-		lost++;
+		gone++;
 	}
 }
-JOM(4, "easysnd_delete(): audio buffers freed: %i pages\n", lost);
+JOM(4, "easysnd_delete(): audio buffers freed: %i pages\n", gone);
 /*---------------------------------------------------------------------------*/
 JOM(4, "freeing easycap structure.\n");
 allocation_video_urb    = peasycap->allocation_video_urb;
@@ -1103,7 +1105,7 @@ else
 int
 easycap_dqbuf(struct easycap *peasycap, int mode)
 {
-int ifield, miss, rc;
+int input, ifield, miss, rc;
 
 JOT(8, "\n");
 
@@ -1115,6 +1117,36 @@ ifield = 0;
 JOM(8, "%i=ifield\n", ifield);
 /*---------------------------------------------------------------------------*/
 /*
+ *  CHECK FOR LOST INPUT SIGNAL.
+ *
+ *  FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
+ *  IF INPUT 0 IS PRESENT AND LOCKED, UNPLUGGING INPUT 4 DOES NOT RESULT IN
+ *  SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE IS FLYWHEELING
+ *  ON INPUT 0.  THE UPSHOT IS:
+ *
+ *    INPUT 0   PLUGGED, INPUT 4   PLUGGED => SCREEN 0 OK,   SCREEN 4 OK
+ *    INPUT 0   PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK,   SCREEN 4 BLACK
+ *    INPUT 0 UNPLUGGED, INPUT 4   PLUGGED => SCREEN 0 BARS, SCREEN 4 OK
+ *    INPUT 0 UNPLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 BARS, SCREEN 4 BARS
+*/
+/*---------------------------------------------------------------------------*/
+input = peasycap->input;
+if (0 <= input && INPUT_MANY > input) {
+	rc = read_saa(peasycap->pusb_device, 0x1F);
+	if (0 <= rc) {
+		if (rc & 0x40)
+			peasycap->lost[input] += 1;
+		else
+			peasycap->lost[input] -= 2;
+
+	if (0 > peasycap->lost[input])
+		peasycap->lost[input] = 0;
+	else if ((2 * VIDEO_LOST_TOLERATE) < peasycap->lost[input])
+		peasycap->lost[input] = (2 * VIDEO_LOST_TOLERATE);
+	}
+}
+/*---------------------------------------------------------------------------*/
+/*
  *  WAIT FOR FIELD ifield  (0 => TOP, 1 => BOTTOM)
  */
 /*---------------------------------------------------------------------------*/
@@ -1304,7 +1336,7 @@ struct signed_div_result sdr;
 void *pex, *pad;
 int kex, kad, mex, mad, rex, rad, rad2;
 int c2, c3, w2, w3, cz, wz;
-int rc, bytesperpixel, multiplier, much, more, over, rump, caches;
+int rc, bytesperpixel, multiplier, much, more, over, rump, caches, input;
 __u8 mask, margin;
 bool odd, isuy, decimatepixel, offerfields, badinput;
 
@@ -1314,6 +1346,7 @@ if ((struct easycap *)NULL == peasycap) {
 }
 
 badinput = false;
+input = 0x07 & peasycap->field_buffer[peasycap->field_read][0].input;
 
 JOM(8, "=====  parity %i, input 0x%02X, field buffer %i --> " \
 						"frame buffer %i\n", \
@@ -1337,8 +1370,10 @@ if (peasycap->field_read == peasycap->field_fill) {
 #if defined(EASYCAP_TESTCARD)
 easycap_testcard(peasycap, peasycap->field_read);
 #else
-if (0 != (0x0400 & peasycap->field_buffer[peasycap->field_read][0].kount))
-	easycap_testcard(peasycap, peasycap->field_read);
+if (0 <= input && INPUT_MANY > input) {
+	if (bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input])
+		easycap_testcard(peasycap, peasycap->field_read);
+}
 #endif /*EASYCAP_TESTCARD*/
 /*---------------------------------------------------------------------------*/
 
@@ -3491,6 +3526,8 @@ if (0 == bInterfaceNumber) {
 
 	peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
 
+	for (k = 0; k < INPUT_MANY; k++)
+		peasycap->lost[k] = 0;
 	peasycap->skip = 0;
 	peasycap->skipped = 0;
 	peasycap->offerfields = 0;
@@ -4733,7 +4770,7 @@ easycap_module_init(void)
 int result;
 
 SAY("========easycap=======\n");
-JOT(4, "begins.  %i=debug\n", debug);
+JOT(4, "begins.  %i=debug %i=bars\n", debug, bars);
 SAY("version: " EASYCAP_DRIVER_VERSION "\n");
 /*---------------------------------------------------------------------------*/
 /*
@@ -4774,6 +4811,8 @@ MODULE_AUTHOR("R.M. Thomas <rmthomas@xxxxxxxxxxx>");
 MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);
 MODULE_VERSION(EASYCAP_DRIVER_VERSION);
 #if defined(EASYCAP_DEBUG)
-MODULE_PARM_DESC(debug, "debug: 0 (default), 1, 2,...");
+MODULE_PARM_DESC(debug, "Debug level: 0 (default),1,2,...,9");
 #endif /*EASYCAP_DEBUG*/
+MODULE_PARM_DESC(bars, \
+	"Testcard bars on input signal failure: 0=>no, 1=>yes(default)");
 /*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/easycap/easycap_testcard.c
index dd98b47..e27dfe9 100644
--- a/drivers/staging/easycap/easycap_testcard.c
+++ b/drivers/staging/easycap/easycap_testcard.c
@@ -29,37 +29,69 @@
 #include "easycap_debug.h"
 
 /*****************************************************************************/
-#define TESTCARD_BYTESPERLINE (2 * 1440)
+#define TESTCARD_BYTESPERLINE (2 * 720)
 void
-easycap_testcard(struct easycap *peasycap, int field_fill)
+easycap_testcard(struct easycap *peasycap, int field)
 {
 int total;
 int y, u, v, r, g, b;
 unsigned char uyvy[4];
-
-int i1, line, k, m, n, more, much, barwidth;
+int i1, line, k, m, n, more, much, barwidth, barheight;
 unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
 struct data_buffer *pfield_buffer;
 
-JOT(8, "%i=field_fill\n", field_fill);
-
-if ((TESTCARD_BYTESPERLINE / 2) < peasycap->width) {
-	SAY("ERROR: image is too wide\n");
+if (NULL == peasycap) {
+	SAY("ERROR: peasycap is NULL\n");
+	return;
+}
+JOM(8, "%i=field\n", field);
+switch (peasycap->width) {
+case 720:
+case 360: {
+	barwidth = (2 * 720) / 8;
+	break;
+}
+case 704:
+case 352: {
+	barwidth = (2 * 704) / 8;
+	break;
+}
+case 640:
+case 320: {
+	barwidth = (2 * 640) / 8;
+	break;
+}
+default: {
+	SAM("ERROR:  cannot set barwidth\n");
 	return;
 }
-if (peasycap->width % 16) {
-	SAY("ERROR: indivisible image width\n");
+}
+if (TESTCARD_BYTESPERLINE < barwidth) {
+	SAM("ERROR: barwidth is too large\n");
 	return;
 }
-
+switch (peasycap->height) {
+case 576:
+case 288: {
+	barheight = 576;
+	break;
+}
+case 480:
+case 240: {
+	barheight = 480;
+	break;
+}
+default: {
+	SAM("ERROR: cannot set barheight\n");
+	return;
+}
+}
 total = 0;
-barwidth = (2 * peasycap->width) / 8;
-
-k = field_fill;
+k = field;
 m = 0;
 n = 0;
 
-for (line = 0;  line < (peasycap->height / 2);  line++) {
+for (line = 0;  line < (barheight / 2);  line++) {
 	for (i1 = 0;  i1 < 8;  i1++) {
 		r = (i1 * 256)/8;
 		g = (i1 * 256)/8;
@@ -88,15 +120,15 @@ for (line = 0;  line < (peasycap->height / 2);  line++) {
 
 		while (more) {
 			if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) {
-				SAY("ERROR:  bad m reached\n");
+				SAM("ERROR:  bad m reached\n");
 				return;
 			}
 		if (PAGE_SIZE < n) {
-			SAY("ERROR:  bad n reached\n"); return;
+			SAM("ERROR:  bad n reached\n"); return;
 		}
 
 		if (0 > more) {
-			SAY("ERROR:  internal fault\n");
+			SAM("ERROR:  internal fault\n");
 			return;
 		}
 
@@ -117,10 +149,6 @@ for (line = 0;  line < (peasycap->height / 2);  line++) {
 		}
 	}
 }
-
-JOT(8, "%i=total\n", total);
-if (total != peasycap->width * peasycap->height)
-	SAY("ERROR: wrong number of bytes written:  %i\n", total);
 return;
 }
 /*****************************************************************************/
@@ -375,10 +403,12 @@ int i1;
 unsigned char *p2;
 struct data_buffer *paudio_buffer;
 
-JOT(8, "%i=audio_fill\n", audio_fill);
-
+if (NULL == peasycap) {
+	SAY("ERROR: peasycap is NULL\n");
+	return;
+}
+JOM(8, "%i=audio_fill\n", audio_fill);
 paudio_buffer = &peasycap->audio_buffer[audio_fill];
-
 p2 = (unsigned char *)(paudio_buffer->pgo);
 for (i1 = 0;  i1 < PAGE_SIZE;  i1 += 4, p2 += 4) {
 	*p2       = (unsigned char) (0x00FF & tones[i1/2]);
-- 
1.7.3.2

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel


[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux