V4L/DVB (10211): vivi: Implements 4 inputs on vivi

This patch adds the capability of selecting between 4 different inputs
on vivi driver. Input 0 is the normal color bar, while inputs 1-3 are
modified color bars.

This allows testing input selection on userspace applications and
serves as an implementation model for other drivers.

The current approach allows a maximum of 10 different inputs, since the
input name generator assumes that we need just one digit to present the
input. It shouldn't be hard to modify it to present a bigger name of
inputs, but, in fact, it doesn't make much sense of doing it for this
test driver.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 81d5aa5..13e7bd0 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -223,6 +223,9 @@
 	char                       timestr[13];
 
 	int			   mv_count;	/* Controls bars movement */
+
+	/* Input Number */
+	int			   input;
 };
 
 struct vivi_fh {
@@ -235,6 +238,7 @@
 
 	enum v4l2_buf_type         type;
 	unsigned char              bars[8][3];
+	int			   input; 	/* Input Number on bars */
 };
 
 /* ------------------------------------------------------------------
@@ -254,18 +258,72 @@
 	BLACK,
 };
 
-static u8 bars[8][3] = {
 	/* R   G   B */
-	{204, 204, 204},  /* white */
-	{208, 208,   0},  /* ambar */
-	{  0, 206, 206},  /* cyan */
-	{  0, 239,   0},  /* green */
-	{239,   0, 239},  /* magenta */
-	{205,   0,   0},  /* red */
-	{  0,   0, 255},  /* blue */
-	{  0,   0,   0},  /* black */
+#define COLOR_WHITE	{204, 204, 204}
+#define COLOR_AMBAR	{208, 208,   0}
+#define COLOR_CIAN	{  0, 206, 206}
+#define	COLOR_GREEN	{  0, 239,   0}
+#define COLOR_MAGENTA	{239,   0, 239}
+#define COLOR_RED	{205,   0,   0}
+#define COLOR_BLUE	{  0,   0, 255}
+#define COLOR_BLACK	{  0,   0,   0}
+
+struct bar_std {
+	u8 bar[8][3];
 };
 
+/* Maximum number of bars are 10 - otherwise, the input print code
+   should be modified */
+static struct bar_std bars[] = {
+	{	/* Standard ITU-R color bar sequence */
+		{
+			COLOR_WHITE,
+			COLOR_AMBAR,
+			COLOR_CIAN,
+			COLOR_GREEN,
+			COLOR_MAGENTA,
+			COLOR_RED,
+			COLOR_BLUE,
+			COLOR_BLACK,
+		}
+	}, {
+		{
+			COLOR_WHITE,
+			COLOR_AMBAR,
+			COLOR_BLACK,
+			COLOR_WHITE,
+			COLOR_AMBAR,
+			COLOR_BLACK,
+			COLOR_WHITE,
+			COLOR_AMBAR,
+		}
+	}, {
+		{
+			COLOR_WHITE,
+			COLOR_CIAN,
+			COLOR_BLACK,
+			COLOR_WHITE,
+			COLOR_CIAN,
+			COLOR_BLACK,
+			COLOR_WHITE,
+			COLOR_CIAN,
+		}
+	}, {
+		{
+			COLOR_WHITE,
+			COLOR_GREEN,
+			COLOR_BLACK,
+			COLOR_WHITE,
+			COLOR_GREEN,
+			COLOR_BLACK,
+			COLOR_WHITE,
+			COLOR_GREEN,
+		}
+	},
+};
+
+#define NUM_INPUTS ARRAY_SIZE(bars)
+
 #define TO_Y(r, g, b) \
 	(((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
 /* RGB to  V(Cr) Color transform */
@@ -275,9 +333,10 @@
 #define TO_U(r, g, b) \
 	(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
 
-#define TSTAMP_MIN_Y 24
-#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
-#define TSTAMP_MIN_X 64
+#define TSTAMP_MIN_Y	24
+#define TSTAMP_MAX_Y	(TSTAMP_MIN_Y + 15)
+#define TSTAMP_INPUT_X	10
+#define TSTAMP_MIN_X	(54 + TSTAMP_INPUT_X)
 
 static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
 {
@@ -392,9 +451,29 @@
 		pos += 4; /* only 16 bpp supported for now */
 	}
 
-	/* Checks if it is possible to show timestamp */
+	/* Prints input entry number */
+
+	/* Checks if it is possible to input number */
 	if (TSTAMP_MAX_Y >= hmax)
 		goto end;
+
+	if (TSTAMP_INPUT_X + strlen(timestr) >= wmax)
+		goto end;
+
+	if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
+		chr = rom8x16_bits[fh->input * 16 + line - TSTAMP_MIN_Y];
+		pos = TSTAMP_INPUT_X;
+		for (i = 0; i < 7; i++) {
+			/* Draw white font on black background */
+			if (chr & 1 << (7 - i))
+				gen_twopix(fh, basep + pos, WHITE);
+			else
+				gen_twopix(fh, basep + pos, BLACK);
+			pos += 2;
+		}
+	}
+
+	/* Checks if it is possible to show timestamp */
 	if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
 		goto end;
 
@@ -807,38 +886,19 @@
 	return 0;
 }
 
-/*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-					struct v4l2_format *f)
+/* precalculate color bar values to speed up rendering */
+static void precalculate_bars(struct vivi_fh *fh)
 {
-	struct vivi_fh  *fh = priv;
-	struct videobuf_queue *q = &fh->vb_vidq;
+	struct vivi_dev *dev = fh->dev;
 	unsigned char r, g, b;
 	int k, is_yuv;
 
-	int ret = vidioc_try_fmt_vid_cap(file, fh, f);
-	if (ret < 0)
-		return (ret);
+	fh->input = dev->input;
 
-	mutex_lock(&q->vb_lock);
-
-	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-		dprintk(fh->dev, 1, "%s queue busy\n", __func__);
-		ret = -EBUSY;
-		goto out;
-	}
-
-	fh->fmt           = get_format(f);
-	fh->width         = f->fmt.pix.width;
-	fh->height        = f->fmt.pix.height;
-	fh->vb_vidq.field = f->fmt.pix.field;
-	fh->type          = f->type;
-
-	/* precalculate color bar values to speed up rendering */
 	for (k = 0; k < 8; k++) {
-		r = bars[k][0];
-		g = bars[k][1];
-		b = bars[k][2];
+		r = bars[fh->input].bar[k][0];
+		g = bars[fh->input].bar[k][1];
+		b = bars[fh->input].bar[k][2];
 		is_yuv = 0;
 
 		switch (fh->fmt->fourcc) {
@@ -871,11 +931,40 @@
 		}
 	}
 
+}
+
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivi_fh *fh = priv;
+	struct videobuf_queue *q = &fh->vb_vidq;
+
+	int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&q->vb_lock);
+
+	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+		dprintk(fh->dev, 1, "%s queue busy\n", __func__);
+		ret = -EBUSY;
+		goto out;
+	}
+
+	fh->fmt           = get_format(f);
+	fh->width         = f->fmt.pix.width;
+	fh->height        = f->fmt.pix.height;
+	fh->vb_vidq.field = f->fmt.pix.field;
+	fh->type          = f->type;
+
+	precalculate_bars(fh);
+
 	ret = 0;
 out:
 	mutex_unlock(&q->vb_lock);
 
-	return (ret);
+	return ret;
 }
 
 static int vidioc_reqbufs(struct file *file, void *priv,
@@ -950,27 +1039,36 @@
 static int vidioc_enum_input(struct file *file, void *priv,
 				struct v4l2_input *inp)
 {
-	if (inp->index != 0)
+	if (inp->index >= NUM_INPUTS)
 		return -EINVAL;
 
 	inp->type = V4L2_INPUT_TYPE_CAMERA;
 	inp->std = V4L2_STD_525_60;
-	strcpy(inp->name, "Camera");
+	sprintf(inp->name, "Camera %u", inp->index);
 
 	return (0);
 }
 
 static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
-	*i = 0;
+	struct vivi_fh *fh = priv;
+	struct vivi_dev *dev = fh->dev;
+
+	*i = dev->input;
 
 	return (0);
 }
 static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
-	if (i > 0)
+	struct vivi_fh *fh = priv;
+	struct vivi_dev *dev = fh->dev;
+
+	if (i >= NUM_INPUTS)
 		return -EINVAL;
 
+	dev->input = i;
+	precalculate_bars(fh);
+
 	return (0);
 }