V4L/DVB: vivi: clean up and a major overhaul

- Clean up the code
- Use the kernel's built-in vga8x16 font instead of our own.
- Drop exclusive open: now multiple users can open the device as per the V4L2 spec.
- Move the format description to the vivi device instead of keeping it in the file
  handle. Again as per the spec.
- Streamline and simplify the drawing code. It is now easy to add text on top of
  the colorbar pattern.
- Upgrade the max resolution to 1920x1200.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 5a736b8..d5e30b8 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -13,29 +13,22 @@
  * License, or (at your option) any later version
  */
 #include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/errno.h>
-#include <linux/fs.h>
 #include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/random.h>
+#include <linux/font.h>
 #include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
 #include <linux/kthread.h>
-#include <linux/highmem.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
 #include <linux/freezer.h>
+#endif
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include "font.h"
+#include <media/v4l2-common.h>
 
 #define VIVI_MODULE_NAME "vivi"
 
@@ -44,8 +37,11 @@
 #define WAKE_DENOMINATOR 1001
 #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
+#define MAX_WIDTH 1920
+#define MAX_HEIGHT 1200
+
 #define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 6
+#define VIVI_MINOR_VERSION 7
 #define VIVI_RELEASE 0
 #define VIVI_VERSION \
 	KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
@@ -70,56 +66,8 @@
 module_param(vid_limit, uint, 0644);
 MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
 
-
-/* supported controls */
-static struct v4l2_queryctrl vivi_qctrl[] = {
-	{
-		.id            = V4L2_CID_AUDIO_VOLUME,
-		.name          = "Volume",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 65535,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-	}, {
-		.id            = V4L2_CID_BRIGHTNESS,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Brightness",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 1,
-		.default_value = 127,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-	}, {
-		.id            = V4L2_CID_CONTRAST,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Contrast",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 0x1,
-		.default_value = 0x10,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-	}, {
-		.id            = V4L2_CID_SATURATION,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Saturation",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 0x1,
-		.default_value = 127,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-	}, {
-		.id            = V4L2_CID_HUE,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Hue",
-		.minimum       = -128,
-		.maximum       = 127,
-		.step          = 0x1,
-		.default_value = 0,
-		.flags         = V4L2_CTRL_FLAG_SLIDER,
-	}
-};
+/* Global font descriptor */
+static const u8 *font8x16;
 
 #define dprintk(dev, level, fmt, arg...) \
 	v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
@@ -214,41 +162,38 @@
 	struct list_head           vivi_devlist;
 	struct v4l2_device 	   v4l2_dev;
 
+	/* controls */
+	int 			   brightness;
+	int 			   contrast;
+	int 			   saturation;
+	int 			   hue;
+	int 			   volume;
+
 	spinlock_t                 slock;
 	struct mutex		   mutex;
 
-	int                        users;
-
 	/* various device info */
 	struct video_device        *vfd;
 
 	struct vivi_dmaqueue       vidq;
 
 	/* Several counters */
-	int                        h, m, s, ms;
+	unsigned 		   ms;
 	unsigned long              jiffies;
-	char                       timestr[13];
 
 	int			   mv_count;	/* Controls bars movement */
 
 	/* Input Number */
 	int			   input;
 
-	/* Control 'registers' */
-	int 			   qctl_regs[ARRAY_SIZE(vivi_qctrl)];
-};
-
-struct vivi_fh {
-	struct vivi_dev            *dev;
-
 	/* video capture */
 	struct vivi_fmt            *fmt;
 	unsigned int               width, height;
 	struct videobuf_queue      vb_vidq;
 
-	enum v4l2_buf_type         type;
-	unsigned char              bars[8][3];
-	int			   input; 	/* Input Number on bars */
+	unsigned long 		   generating;
+	u8 			   bars[9][3];
+	u8 			   line[MAX_WIDTH * 4];
 };
 
 /* ------------------------------------------------------------------
@@ -259,19 +204,20 @@
 
 enum colors {
 	WHITE,
-	AMBAR,
+	AMBER,
 	CYAN,
 	GREEN,
 	MAGENTA,
 	RED,
 	BLUE,
 	BLACK,
+	TEXT_BLACK,
 };
 
-	/* R   G   B */
+/* R   G   B */
 #define COLOR_WHITE	{204, 204, 204}
-#define COLOR_AMBAR	{208, 208,   0}
-#define COLOR_CIAN	{  0, 206, 206}
+#define COLOR_AMBER	{208, 208,   0}
+#define COLOR_CYAN	{  0, 206, 206}
 #define	COLOR_GREEN	{  0, 239,   0}
 #define COLOR_MAGENTA	{239,   0, 239}
 #define COLOR_RED	{205,   0,   0}
@@ -279,56 +225,24 @@
 #define COLOR_BLACK	{  0,   0,   0}
 
 struct bar_std {
-	u8 bar[8][3];
+	u8 bar[9][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_AMBER, COLOR_CYAN, COLOR_GREEN,
+		  COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
 	}, {
-		{
-			COLOR_WHITE,
-			COLOR_AMBAR,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_AMBAR,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_AMBAR,
-		}
+		{ COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
+		  COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
 	}, {
-		{
-			COLOR_WHITE,
-			COLOR_CIAN,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_CIAN,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_CIAN,
-		}
+		{ COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
+		  COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
 	}, {
-		{
-			COLOR_WHITE,
-			COLOR_GREEN,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_GREEN,
-			COLOR_BLACK,
-			COLOR_WHITE,
-			COLOR_GREEN,
-		}
+		{ COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
+		  COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
 	},
 };
 
@@ -344,21 +258,18 @@
 	(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
 
 /* precalculate color bar values to speed up rendering */
-static void precalculate_bars(struct vivi_fh *fh)
+static void precalculate_bars(struct vivi_dev *dev)
 {
-	struct vivi_dev *dev = fh->dev;
-	unsigned char r, g, b;
+	u8 r, g, b;
 	int k, is_yuv;
 
-	fh->input = dev->input;
-
-	for (k = 0; k < 8; k++) {
-		r = bars[fh->input].bar[k][0];
-		g = bars[fh->input].bar[k][1];
-		b = bars[fh->input].bar[k][2];
+	for (k = 0; k < 9; k++) {
+		r = bars[dev->input].bar[k][0];
+		g = bars[dev->input].bar[k][1];
+		b = bars[dev->input].bar[k][2];
 		is_yuv = 0;
 
-		switch (fh->fmt->fourcc) {
+		switch (dev->fmt->fourcc) {
 		case V4L2_PIX_FMT_YUYV:
 		case V4L2_PIX_FMT_UYVY:
 			is_yuv = 1;
@@ -378,16 +289,15 @@
 		}
 
 		if (is_yuv) {
-			fh->bars[k][0] = TO_Y(r, g, b);	/* Luma */
-			fh->bars[k][1] = TO_U(r, g, b);	/* Cb */
-			fh->bars[k][2] = TO_V(r, g, b);	/* Cr */
+			dev->bars[k][0] = TO_Y(r, g, b);	/* Luma */
+			dev->bars[k][1] = TO_U(r, g, b);	/* Cb */
+			dev->bars[k][2] = TO_V(r, g, b);	/* Cr */
 		} else {
-			fh->bars[k][0] = r;
-			fh->bars[k][1] = g;
-			fh->bars[k][2] = b;
+			dev->bars[k][0] = r;
+			dev->bars[k][1] = g;
+			dev->bars[k][2] = b;
 		}
 	}
-
 }
 
 #define TSTAMP_MIN_Y	24
@@ -395,20 +305,20 @@
 #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)
+static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos)
 {
-	unsigned char r_y, g_u, b_v;
-	unsigned char *p;
+	u8 r_y, g_u, b_v;
 	int color;
+	u8 *p;
 
-	r_y = fh->bars[colorpos][0]; /* R or precalculated Y */
-	g_u = fh->bars[colorpos][1]; /* G or precalculated U */
-	b_v = fh->bars[colorpos][2]; /* B or precalculated V */
+	r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
+	g_u = dev->bars[colorpos][1]; /* G or precalculated U */
+	b_v = dev->bars[colorpos][2]; /* B or precalculated V */
 
 	for (color = 0; color < 4; color++) {
 		p = buf + color;
 
-		switch (fh->fmt->fourcc) {
+		switch (dev->fmt->fourcc) {
 		case V4L2_PIX_FMT_YUYV:
 			switch (color) {
 			case 0:
@@ -489,123 +399,88 @@
 	}
 }
 
-static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
-		int hmax, int line, int count, char *timestr)
+static void precalculate_line(struct vivi_dev *dev)
 {
-	int  w, i, j;
-	int pos = inipos;
-	char *s;
-	u8 chr;
+	int w;
 
-	/* We will just duplicate the second pixel at the packet */
-	wmax /= 2;
+	for (w = 0; w < dev->width * 2; w += 2) {
+		int colorpos = (w / (dev->width / 8) % 8);
 
-	/* Generate a standard color bar pattern */
-	for (w = 0; w < wmax; w++) {
-		int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
-
-		gen_twopix(fh, basep + pos, colorpos);
-		pos += 4; /* only 16 bpp supported for now */
+		gen_twopix(dev, dev->line + w * 2, colorpos);
 	}
+}
 
-	/* Prints input entry number */
+static void gen_text(struct vivi_dev *dev, char *basep,
+					int y, int x, char *text)
+{
+	int line;
 
-	/* 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;
+	/* Checks if it is possible to show string */
+	if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width)
+		return;
 
 	/* Print stream time */
-	if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
-		j = TSTAMP_MIN_X;
-		for (s = timestr; *s; s++) {
-			chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
-			for (i = 0; i < 7; i++) {
-				pos = inipos + j * 2;
+	for (line = y; line < y + 16; line++) {
+		int j = 0;
+		char *pos = basep + line * dev->width * 2 + x * 2;
+		char *s;
+
+		for (s = text; *s; s++) {
+			u8 chr = font8x16[*s * 16 + line - y];
+			int i;
+
+			for (i = 0; i < 7; i++, j++) {
 				/* Draw white font on black background */
-				if (chr & 1 << (7 - i))
-					gen_twopix(fh, basep + pos, WHITE);
+				if (chr & (1 << (7 - i)))
+					gen_twopix(dev, pos + j * 2, WHITE);
 				else
-					gen_twopix(fh, basep + pos, BLACK);
-				j++;
+					gen_twopix(dev, pos + j * 2, TEXT_BLACK);
 			}
 		}
 	}
-
-end:
-	return;
 }
 
-static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
+static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 {
-	struct vivi_dev *dev = fh->dev;
-	int h , pos = 0;
-	int hmax  = buf->vb.height;
-	int wmax  = buf->vb.width;
+	int hmax = buf->vb.height;
+	int wmax = buf->vb.width;
 	struct timeval ts;
-	char *tmpbuf;
 	void *vbuf = videobuf_to_vmalloc(&buf->vb);
+	unsigned ms;
+	char str[100];
+	int h, line = 1;
 
 	if (!vbuf)
 		return;
 
-	tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
-	if (!tmpbuf)
-		return;
-
-	for (h = 0; h < hmax; h++) {
-		gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
-			 dev->timestr);
-		memcpy(vbuf + pos, tmpbuf, wmax * 2);
-		pos += wmax*2;
-	}
-
-	dev->mv_count++;
-
-	kfree(tmpbuf);
+	for (h = 0; h < hmax; h++)
+		memcpy(vbuf + h * wmax * 2, dev->line + (dev->mv_count % wmax) * 2, wmax * 2);
 
 	/* Updates stream time */
 
-	dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
+	dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
 	dev->jiffies = jiffies;
-	if (dev->ms >= 1000) {
-		dev->ms -= 1000;
-		dev->s++;
-		if (dev->s >= 60) {
-			dev->s -= 60;
-			dev->m++;
-			if (dev->m > 60) {
-				dev->m -= 60;
-				dev->h++;
-				if (dev->h > 24)
-					dev->h -= 24;
-			}
-		}
-	}
-	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
-			dev->h, dev->m, dev->s, dev->ms);
+	ms = dev->ms;
+	snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
+			(ms / (60 * 60 * 1000)) % 24,
+			(ms / (60 * 1000)) % 60,
+			(ms / 1000) % 60,
+			ms % 1000);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " %dx%d, input %d ",
+			dev->width, dev->height, dev->input);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
 
-	dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
-			dev->timestr, (unsigned long)tmpbuf, pos);
+	snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
+			dev->brightness,
+			dev->contrast,
+			dev->saturation,
+			dev->hue);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " volume %3d ", dev->volume);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+
+	dev->mv_count += 2;
 
 	/* Advice that buffer was filled */
 	buf->vb.field_count++;
@@ -614,12 +489,10 @@
 	buf->vb.state = VIDEOBUF_DONE;
 }
 
-static void vivi_thread_tick(struct vivi_fh *fh)
+static void vivi_thread_tick(struct vivi_dev *dev)
 {
-	struct vivi_buffer *buf;
-	struct vivi_dev *dev = fh->dev;
 	struct vivi_dmaqueue *dma_q = &dev->vidq;
-
+	struct vivi_buffer *buf;
 	unsigned long flags = 0;
 
 	dprintk(dev, 1, "Thread tick\n");
@@ -642,22 +515,20 @@
 	do_gettimeofday(&buf->vb.ts);
 
 	/* Fill buffer */
-	vivi_fillbuff(fh, buf);
+	vivi_fillbuff(dev, buf);
 	dprintk(dev, 1, "filled buffer %p\n", buf);
 
 	wake_up(&buf->vb.done);
 	dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
 unlock:
 	spin_unlock_irqrestore(&dev->slock, flags);
-	return;
 }
 
 #define frames_to_ms(frames)					\
 	((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
 
-static void vivi_sleep(struct vivi_fh *fh)
+static void vivi_sleep(struct vivi_dev *dev)
 {
-	struct vivi_dev *dev = fh->dev;
 	struct vivi_dmaqueue *dma_q = &dev->vidq;
 	int timeout;
 	DECLARE_WAITQUEUE(wait, current);
@@ -672,7 +543,7 @@
 	/* Calculate time to wake up */
 	timeout = msecs_to_jiffies(frames_to_ms(1));
 
-	vivi_thread_tick(fh);
+	vivi_thread_tick(dev);
 
 	schedule_timeout_interruptible(timeout);
 
@@ -683,15 +554,14 @@
 
 static int vivi_thread(void *data)
 {
-	struct vivi_fh  *fh = data;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = data;
 
 	dprintk(dev, 1, "thread started\n");
 
 	set_freezable();
 
 	for (;;) {
-		vivi_sleep(fh);
+		vivi_sleep(dev);
 
 		if (kthread_should_stop())
 			break;
@@ -700,39 +570,61 @@
 	return 0;
 }
 
-static int vivi_start_thread(struct vivi_fh *fh)
+static void vivi_start_generating(struct file *file)
 {
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 	struct vivi_dmaqueue *dma_q = &dev->vidq;
 
-	dma_q->frame = 0;
-	dma_q->ini_jiffies = jiffies;
-
 	dprintk(dev, 1, "%s\n", __func__);
 
-	dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
+	if (test_and_set_bit(0, &dev->generating))
+		return;
+	file->private_data = dev;
+
+	/* Resets frame counters */
+	dev->ms = 0;
+	dev->mv_count = 0;
+	dev->jiffies = jiffies;
+
+	dma_q->frame = 0;
+	dma_q->ini_jiffies = jiffies;
+	dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name);
 
 	if (IS_ERR(dma_q->kthread)) {
 		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-		return PTR_ERR(dma_q->kthread);
+		clear_bit(0, &dev->generating);
+		return;
 	}
 	/* Wakes thread */
 	wake_up_interruptible(&dma_q->wq);
 
 	dprintk(dev, 1, "returning from %s\n", __func__);
-	return 0;
 }
 
-static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
+static void vivi_stop_generating(struct file *file)
 {
-	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+	struct vivi_dev *dev = video_drvdata(file);
+	struct vivi_dmaqueue *dma_q = &dev->vidq;
 
 	dprintk(dev, 1, "%s\n", __func__);
+
+	if (!file->private_data)
+		return;
+	if (!test_and_clear_bit(0, &dev->generating))
+		return;
+
 	/* shutdown control thread */
 	if (dma_q->kthread) {
 		kthread_stop(dma_q->kthread);
 		dma_q->kthread = NULL;
 	}
+	videobuf_stop(&dev->vb_vidq);
+	videobuf_mmap_free(&dev->vb_vidq);
+}
+
+static int vivi_is_generating(struct vivi_dev *dev)
+{
+	return test_bit(0, &dev->generating);
 }
 
 /* ------------------------------------------------------------------
@@ -741,16 +633,15 @@
 static int
 buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
 {
-	struct vivi_fh  *fh = vq->priv_data;
-	struct vivi_dev *dev  = fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
 
-	*size = fh->width*fh->height*2;
+	*size = dev->width * dev->height * 2;
 
 	if (0 == *count)
 		*count = 32;
 
-	if (*size * *count > vid_limit * 1024 * 1024)
-		*count = (vid_limit * 1024 * 1024) / *size;
+	while (*size * *count > vid_limit * 1024 * 1024)
+		(*count)--;
 
 	dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
 		*count, *size);
@@ -760,49 +651,43 @@
 
 static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
 {
-	struct vivi_fh  *fh = vq->priv_data;
-	struct vivi_dev *dev  = fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
 
 	dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
 
-	if (in_interrupt())
-		BUG();
-
 	videobuf_vmalloc_free(&buf->vb);
 	dprintk(dev, 1, "free_buffer: freed\n");
 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
-#define norm_maxw() 1024
-#define norm_maxh() 768
 static int
 buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 						enum v4l2_field field)
 {
-	struct vivi_fh     *fh  = vq->priv_data;
-	struct vivi_dev    *dev = fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
 	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
 	int rc;
 
 	dprintk(dev, 1, "%s, field=%d\n", __func__, field);
 
-	BUG_ON(NULL == fh->fmt);
+	BUG_ON(NULL == dev->fmt);
 
-	if (fh->width  < 48 || fh->width  > norm_maxw() ||
-	    fh->height < 32 || fh->height > norm_maxh())
+	if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
+	    dev->height < 32 || dev->height > MAX_HEIGHT)
 		return -EINVAL;
 
-	buf->vb.size = fh->width*fh->height*2;
-	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+	buf->vb.size = dev->width * dev->height * 2;
+	if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
 		return -EINVAL;
 
 	/* These properties only change when queue is idle, see s_fmt */
-	buf->fmt       = fh->fmt;
-	buf->vb.width  = fh->width;
-	buf->vb.height = fh->height;
+	buf->fmt       = dev->fmt;
+	buf->vb.width  = dev->width;
+	buf->vb.height = dev->height;
 	buf->vb.field  = field;
 
-	precalculate_bars(fh);
+	precalculate_bars(dev);
+	precalculate_line(dev);
 
 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		rc = videobuf_iolock(vq, &buf->vb, NULL);
@@ -811,7 +696,6 @@
 	}
 
 	buf->vb.state = VIDEOBUF_PREPARED;
-
 	return 0;
 
 fail:
@@ -822,9 +706,8 @@
 static void
 buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
-	struct vivi_buffer    *buf  = container_of(vb, struct vivi_buffer, vb);
-	struct vivi_fh        *fh   = vq->priv_data;
-	struct vivi_dev       *dev  = fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
+	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
 	struct vivi_dmaqueue *vidq = &dev->vidq;
 
 	dprintk(dev, 1, "%s\n", __func__);
@@ -836,9 +719,8 @@
 static void buffer_release(struct videobuf_queue *vq,
 			   struct videobuf_buffer *vb)
 {
-	struct vivi_buffer   *buf  = container_of(vb, struct vivi_buffer, vb);
-	struct vivi_fh       *fh   = vq->priv_data;
-	struct vivi_dev      *dev  = (struct vivi_dev *)fh->dev;
+	struct vivi_dev *dev = vq->priv_data;
+	struct vivi_buffer *buf  = container_of(vb, struct vivi_buffer, vb);
 
 	dprintk(dev, 1, "%s\n", __func__);
 
@@ -858,16 +740,14 @@
 static int vidioc_querycap(struct file *file, void  *priv,
 					struct v4l2_capability *cap)
 {
-	struct vivi_fh  *fh  = priv;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 
 	strcpy(cap->driver, "vivi");
 	strcpy(cap->card, "vivi");
 	strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
 	cap->version = VIVI_VERSION;
-	cap->capabilities =	V4L2_CAP_VIDEO_CAPTURE |
-				V4L2_CAP_STREAMING     |
-				V4L2_CAP_READWRITE;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
+			    V4L2_CAP_READWRITE;
 	return 0;
 }
 
@@ -889,28 +769,25 @@
 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
-	struct vivi_fh *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	f->fmt.pix.width        = fh->width;
-	f->fmt.pix.height       = fh->height;
-	f->fmt.pix.field        = fh->vb_vidq.field;
-	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+	f->fmt.pix.width        = dev->width;
+	f->fmt.pix.height       = dev->height;
+	f->fmt.pix.field        = dev->vb_vidq.field;
+	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
 	f->fmt.pix.bytesperline =
-		(f->fmt.pix.width * fh->fmt->depth) >> 3;
+		(f->fmt.pix.width * dev->fmt->depth) >> 3;
 	f->fmt.pix.sizeimage =
 		f->fmt.pix.height * f->fmt.pix.bytesperline;
-
-	return (0);
+	return 0;
 }
 
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 			struct v4l2_format *f)
 {
-	struct vivi_fh  *fh  = priv;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 	struct vivi_fmt *fmt;
 	enum v4l2_field field;
-	unsigned int maxw, maxh;
 
 	fmt = get_format(f);
 	if (!fmt) {
@@ -928,113 +805,109 @@
 		return -EINVAL;
 	}
 
-	maxw  = norm_maxw();
-	maxh  = norm_maxh();
-
 	f->fmt.pix.field = field;
-	v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
-			      &f->fmt.pix.height, 32, maxh, 0, 0);
+	v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
+			      &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
 	f->fmt.pix.bytesperline =
 		(f->fmt.pix.width * fmt->depth) >> 3;
 	f->fmt.pix.sizeimage =
 		f->fmt.pix.height * f->fmt.pix.bytesperline;
-
 	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)
 {
-	struct vivi_fh *fh = priv;
-	struct videobuf_queue *q = &fh->vb_vidq;
+	struct vivi_dev *dev = video_drvdata(file);
+	struct videobuf_queue *q = &dev->vb_vidq;
 
-	int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+	int ret = vidioc_try_fmt_vid_cap(file, priv, 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__);
+	if (vivi_is_generating(dev)) {
+		dprintk(dev, 1, "%s device 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;
-
+	dev->fmt = get_format(f);
+	dev->width = f->fmt.pix.width;
+	dev->height = f->fmt.pix.height;
+	dev->vb_vidq.field = f->fmt.pix.field;
 	ret = 0;
 out:
 	mutex_unlock(&q->vb_lock);
-
 	return ret;
 }
 
 static int vidioc_reqbufs(struct file *file, void *priv,
 			  struct v4l2_requestbuffers *p)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return (videobuf_reqbufs(&fh->vb_vidq, p));
+	return videobuf_reqbufs(&dev->vb_vidq, p);
 }
 
 static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return (videobuf_querybuf(&fh->vb_vidq, p));
+	return videobuf_querybuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return (videobuf_qbuf(&fh->vb_vidq, p));
+	return videobuf_qbuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return (videobuf_dqbuf(&fh->vb_vidq, p,
-				file->f_flags & O_NONBLOCK));
+	return videobuf_dqbuf(&dev->vb_vidq, p,
+				file->f_flags & O_NONBLOCK);
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+	return videobuf_cgmbuf(&dev->vb_vidq, mbuf, 8);
 }
 #endif
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
+	int ret;
 
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
+	ret = videobuf_streamon(&dev->vb_vidq);
+	if (ret)
+		return ret;
 
-	return videobuf_streamon(&fh->vb_vidq);
+	vivi_start_generating(file);
+	return 0;
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-	struct vivi_fh  *fh = priv;
+	struct vivi_dev *dev = video_drvdata(file);
+	int ret;
 
-	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	return videobuf_streamoff(&fh->vb_vidq);
+	ret = videobuf_streamoff(&dev->vb_vidq);
+	if (!ret)
+		vivi_stop_generating(file);
+	return ret;
 }
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
@@ -1052,80 +925,104 @@
 	inp->type = V4L2_INPUT_TYPE_CAMERA;
 	inp->std = V4L2_STD_525_60;
 	sprintf(inp->name, "Camera %u", inp->index);
-
-	return (0);
+	return 0;
 }
 
 static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
-	struct vivi_fh *fh = priv;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 
 	*i = dev->input;
-
-	return (0);
+	return 0;
 }
+
 static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
-	struct vivi_fh *fh = priv;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 
 	if (i >= NUM_INPUTS)
 		return -EINVAL;
 
 	dev->input = i;
-	precalculate_bars(fh);
-
-	return (0);
+	precalculate_bars(dev);
+	precalculate_line(dev);
+	return 0;
 }
 
-	/* --- controls ---------------------------------------------- */
+/* --- controls ---------------------------------------------- */
 static int vidioc_queryctrl(struct file *file, void *priv,
 			    struct v4l2_queryctrl *qc)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-		if (qc->id && qc->id == vivi_qctrl[i].id) {
-			memcpy(qc, &(vivi_qctrl[i]),
-				sizeof(*qc));
-			return (0);
-		}
-
+	switch (qc->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 200);
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
+	case V4L2_CID_CONTRAST:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 16);
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
+	}
 	return -EINVAL;
 }
 
 static int vidioc_g_ctrl(struct file *file, void *priv,
 			 struct v4l2_control *ctrl)
 {
-	struct vivi_fh *fh = priv;
-	struct vivi_dev *dev = fh->dev;
-	int i;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-		if (ctrl->id == vivi_qctrl[i].id) {
-			ctrl->value = dev->qctl_regs[i];
-			return 0;
-		}
-
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		ctrl->value = dev->volume;
+		return 0;
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = dev->brightness;
+		return 0;
+	case V4L2_CID_CONTRAST:
+		ctrl->value = dev->contrast;
+		return 0;
+	case V4L2_CID_SATURATION:
+		ctrl->value = dev->saturation;
+		return 0;
+	case V4L2_CID_HUE:
+		ctrl->value = dev->hue;
+		return 0;
+	}
 	return -EINVAL;
 }
+
 static int vidioc_s_ctrl(struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
-	struct vivi_fh *fh = priv;
-	struct vivi_dev *dev = fh->dev;
-	int i;
+	struct vivi_dev *dev = video_drvdata(file);
+	struct v4l2_queryctrl qc;
+	int err;
 
-	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-		if (ctrl->id == vivi_qctrl[i].id) {
-			if (ctrl->value < vivi_qctrl[i].minimum ||
-			    ctrl->value > vivi_qctrl[i].maximum) {
-				return -ERANGE;
-			}
-			dev->qctl_regs[i] = ctrl->value;
-			return 0;
-		}
+	qc.id = ctrl->id;
+	err = vidioc_queryctrl(file, priv, &qc);
+	if (err < 0)
+		return err;
+	if (ctrl->value < qc.minimum || ctrl->value > qc.maximum)
+		return -ERANGE;
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		dev->volume = ctrl->value;
+		return 0;
+	case V4L2_CID_BRIGHTNESS:
+		dev->brightness = ctrl->value;
+		return 0;
+	case V4L2_CID_CONTRAST:
+		dev->contrast = ctrl->value;
+		return 0;
+	case V4L2_CID_SATURATION:
+		dev->saturation = ctrl->value;
+		return 0;
+	case V4L2_CID_HUE:
+		dev->hue = ctrl->value;
+		return 0;
+	}
 	return -EINVAL;
 }
 
@@ -1133,134 +1030,58 @@
 	File operations for the device
    ------------------------------------------------------------------*/
 
-static int vivi_open(struct file *file)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-	struct vivi_fh *fh = NULL;
-	int retval = 0;
-
-	mutex_lock(&dev->mutex);
-	dev->users++;
-
-	if (dev->users > 1) {
-		dev->users--;
-		mutex_unlock(&dev->mutex);
-		return -EBUSY;
-	}
-
-	dprintk(dev, 1, "open %s type=%s users=%d\n",
-		video_device_node_name(dev->vfd),
-		v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh) {
-		dev->users--;
-		retval = -ENOMEM;
-	}
-	mutex_unlock(&dev->mutex);
-
-	if (retval)
-		return retval;
-
-	file->private_data = fh;
-	fh->dev      = dev;
-
-	fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	fh->fmt      = &formats[0];
-	fh->width    = 640;
-	fh->height   = 480;
-
-	/* Resets frame counters */
-	dev->h = 0;
-	dev->m = 0;
-	dev->s = 0;
-	dev->ms = 0;
-	dev->mv_count = 0;
-	dev->jiffies = jiffies;
-	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
-			dev->h, dev->m, dev->s, dev->ms);
-
-	videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
-			NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
-			sizeof(struct vivi_buffer), fh);
-
-	vivi_start_thread(fh);
-
-	return 0;
-}
-
 static ssize_t
 vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
-	struct vivi_fh *fh = file->private_data;
+	struct vivi_dev *dev = video_drvdata(file);
 
-	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
+	vivi_start_generating(file);
+	return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0,
 					file->f_flags & O_NONBLOCK);
-	}
-	return 0;
 }
 
 static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
-	struct vivi_fh        *fh = file->private_data;
-	struct vivi_dev       *dev = fh->dev;
-	struct videobuf_queue *q = &fh->vb_vidq;
+	struct vivi_dev *dev = video_drvdata(file);
+	struct videobuf_queue *q = &dev->vb_vidq;
 
 	dprintk(dev, 1, "%s\n", __func__);
 
-	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
-		return POLLERR;
-
+	vivi_start_generating(file);
 	return videobuf_poll_stream(file, q, wait);
 }
 
 static int vivi_close(struct file *file)
 {
-	struct vivi_fh         *fh = file->private_data;
-	struct vivi_dev *dev       = fh->dev;
-	struct vivi_dmaqueue *vidq = &dev->vidq;
 	struct video_device  *vdev = video_devdata(file);
+	struct vivi_dev *dev = video_drvdata(file);
 
-	vivi_stop_thread(vidq);
-	videobuf_stop(&fh->vb_vidq);
-	videobuf_mmap_free(&fh->vb_vidq);
+	vivi_stop_generating(file);
 
-	kfree(fh);
-
-	mutex_lock(&dev->mutex);
-	dev->users--;
-	mutex_unlock(&dev->mutex);
-
-	dprintk(dev, 1, "close called (dev=%s, users=%d)\n",
-		video_device_node_name(vdev), dev->users);
-
+	dprintk(dev, 1, "close called (dev=%s)\n",
+		video_device_node_name(vdev));
 	return 0;
 }
 
 static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct vivi_fh  *fh = file->private_data;
-	struct vivi_dev *dev = fh->dev;
+	struct vivi_dev *dev = video_drvdata(file);
 	int ret;
 
 	dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
-	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+	ret = videobuf_mmap_mapper(&dev->vb_vidq, vma);
 
 	dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
 		(unsigned long)vma->vm_start,
-		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+		(unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
 		ret);
-
 	return ret;
 }
 
 static const struct v4l2_file_operations vivi_fops = {
 	.owner		= THIS_MODULE,
-	.open           = vivi_open,
 	.release        = vivi_close,
 	.read           = vivi_read,
 	.poll		= vivi_poll,
@@ -1282,11 +1103,11 @@
 	.vidioc_enum_input    = vidioc_enum_input,
 	.vidioc_g_input       = vidioc_g_input,
 	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
 	.vidioc_queryctrl     = vidioc_queryctrl,
 	.vidioc_g_ctrl        = vidioc_g_ctrl,
 	.vidioc_s_ctrl        = vidioc_s_ctrl,
-	.vidioc_streamon      = vidioc_streamon,
-	.vidioc_streamoff     = vidioc_streamoff,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	.vidiocgmbuf          = vidiocgmbuf,
 #endif
@@ -1330,7 +1151,7 @@
 {
 	struct vivi_dev *dev;
 	struct video_device *vfd;
-	int ret, i;
+	int ret;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
@@ -1342,6 +1163,20 @@
 	if (ret)
 		goto free_dev;
 
+	dev->fmt = &formats[0];
+	dev->width = 640;
+	dev->height = 480;
+	dev->volume = 200;
+	dev->brightness = 127;
+	dev->contrast = 16;
+	dev->saturation = 127;
+	dev->hue = 0;
+
+	videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops,
+			NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			V4L2_FIELD_INTERLACED,
+			sizeof(struct vivi_buffer), dev);
+
 	/* init video dma queues */
 	INIT_LIST_HEAD(&dev->vidq.active);
 	init_waitqueue_head(&dev->vidq.wq);
@@ -1357,6 +1192,7 @@
 
 	*vfd = vivi_template;
 	vfd->debug = debug;
+	vfd->v4l2_dev = &dev->v4l2_dev;
 
 	ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
 	if (ret < 0)
@@ -1364,10 +1200,6 @@
 
 	video_set_drvdata(vfd, dev);
 
-	/* Set all controls to their default value. */
-	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-		dev->qctl_regs[i] = vivi_qctrl[i].default_value;
-
 	/* Now that everything is fine, let's add it to device list */
 	list_add_tail(&dev->vivi_devlist, &vivi_devlist);
 
@@ -1396,8 +1228,15 @@
  */
 static int __init vivi_init(void)
 {
+	const struct font_desc *font = find_font("VGA8x16");
 	int ret = 0, i;
 
+	if (font == NULL) {
+		printk(KERN_ERR "vivi: could not find font\n");
+		return -ENODEV;
+	}
+	font8x16 = font->data;
+
 	if (n_devs <= 0)
 		n_devs = 1;
 
@@ -1412,7 +1251,7 @@
 	}
 
 	if (ret < 0) {
-		printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
+		printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
 		return ret;
 	}