remove svc.c and add svvd.c (copy from vivi.c)
authoryuyeon.oh <yuyeon.oh@samsung.com>
Tue, 24 May 2011 06:45:10 +0000 (15:45 +0900)
committeryuyeon.oh <yuyeon.oh@samsung.com>
Tue, 24 May 2011 06:45:10 +0000 (15:45 +0900)
Change-Id: I3e380b10475694eb4328ac935d408d2fdfd31914

.config
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/svc.c [deleted file]
drivers/media/video/svvd.c [new file with mode: 0755]

diff --git a/.config b/.config
index d6f028d5d1d5976f34f50479733b4896be952812..e93c164a9cc6cd0430a1ea68592e46e605a86683 100644 (file)
--- a/.config
+++ b/.config
@@ -851,7 +851,7 @@ CONFIG_VIDEO_CAPTURE_DRIVERS=y
 # CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 # CONFIG_VIDEO_VIVI is not set
-CONFIG_VIDEO_SVC=y
+CONFIG_VIDEO_SVVD=y
 # CONFIG_VIDEO_CPIA is not set
 # CONFIG_VIDEO_CPIA2 is not set
 # CONFIG_VIDEO_STRADIS is not set
index b201c8528a9fb00869d509beaf6f613114ecebb0..2db67fabec76fc554e2529619e75421ee9b99031 100755 (executable)
@@ -547,13 +547,13 @@ config VIDEO_VIVI
          Say Y here if you want to test video apps or debug V4L devices.
          In doubt, say N.
 
-config VIDEO_SVC
-       tristate "Samsung Virtual Video Driver"
+config VIDEO_SVVD
+       tristate "S-core Virtual Video Driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
        select VIDEOBUF_VMALLOC
        default n
        ---help---
-         Enables a Samsung Virtual Camera driver. This device shows a test 
+         Enables a S-core Virtual Video driver. This device shows a test 
          video(YUV420), as a real device would generate by using V4L2 api.
          And it supports overlay driver.
          Say Y here if you want to test video apps or debug V4L devices.
index bad4a11eb6f61b1ec094576fea644544c9a6857d..1ae3fa77829773df6c3f76851a4b46280bedf67f 100755 (executable)
@@ -144,7 +144,7 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_CX18) += cx18/
 
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
-obj-$(CONFIG_VIDEO_SVC)  += svc.o
+obj-$(CONFIG_VIDEO_SVVD)  += svvd.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 obj-$(CONFIG_VIDEO_OMAP2)              += omap2cam.o
diff --git a/drivers/media/video/svc.c b/drivers/media/video/svc.c
deleted file mode 100644 (file)
index 7705fc6..0000000
+++ /dev/null
@@ -1,1440 +0,0 @@
-/*
- * Virtual Video driver - This code emulates a real video device with v4l2 api
- *
- * Copyright (c) 2006 by:
- *      Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
- *      Ted Walther <ted--a.t--enumera.com>
- *      John Sokol <sokol--a.t--videotechnology.com>
- *      http://v4l.videotechnology.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD Licence, GNU General Public License
- * as published by the Free Software Foundation; either version 2 of the
- * 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/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>
-#include <linux/freezer.h>
-#include <media/videobuf-vmalloc.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include "font.h"
-
-#define VIVI_MODULE_NAME "vivi"
-
-/* Wake up at about 30 fps */
-#define WAKE_NUMERATOR 30
-#define WAKE_DENOMINATOR 1001
-#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
-
-#define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 6
-#define VIVI_RELEASE 0
-#define VIVI_VERSION \
-       KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-
-static unsigned video_nr = -1;
-module_param(video_nr, uint, 0644);
-MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
-
-static unsigned n_devs = 1;
-module_param(n_devs, uint, 0644);
-MODULE_PARM_DESC(n_devs, "number of video devices to create");
-
-static unsigned debug;
-module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-static unsigned int vid_limit = 16;
-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,
-       }
-};
-
-#define dprintk(dev, level, fmt, arg...) \
-       v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
-
-/* ------------------------------------------------------------------
-       Basic structures
-   ------------------------------------------------------------------*/
-
-struct vivi_fmt {
-       char  *name;
-       u32   fourcc;          /* v4l2 format id */
-       int   depth;
-};
-
-static struct vivi_fmt formats[] = {
-       {
-               .name     = "4:2:2, packed, YUYV",
-               .fourcc   = V4L2_PIX_FMT_YUYV,
-               .depth    = 16,
-       },
-       {
-               .name     = "4:2:2, packed, UYVY",
-               .fourcc   = V4L2_PIX_FMT_UYVY,
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB565 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB565 (BE)",
-               .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB555 (LE)",
-               .fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
-               .depth    = 16,
-       },
-       {
-               .name     = "RGB555 (BE)",
-               .fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
-               .depth    = 16,
-       },
-};
-
-static struct vivi_fmt *get_format(struct v4l2_format *f)
-{
-       struct vivi_fmt *fmt;
-       unsigned int k;
-
-       for (k = 0; k < ARRAY_SIZE(formats); k++) {
-               fmt = &formats[k];
-               if (fmt->fourcc == f->fmt.pix.pixelformat)
-                       break;
-       }
-
-       if (k == ARRAY_SIZE(formats))
-               return NULL;
-
-       return &formats[k];
-}
-
-struct sg_to_addr {
-       int pos;
-       struct scatterlist *sg;
-};
-
-/* buffer for one video frame */
-struct vivi_buffer {
-       /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer vb;
-
-       struct vivi_fmt        *fmt;
-};
-
-struct vivi_dmaqueue {
-       struct list_head       active;
-
-       /* thread for generating video stream*/
-       struct task_struct         *kthread;
-       wait_queue_head_t          wq;
-       /* Counters to control fps rate */
-       int                        frame;
-       int                        ini_jiffies;
-};
-
-static LIST_HEAD(vivi_devlist);
-
-struct vivi_dev {
-       struct list_head           vivi_devlist;
-       struct v4l2_device         v4l2_dev;
-
-       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 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 */
-};
-
-/* ------------------------------------------------------------------
-       DMA and thread functions
-   ------------------------------------------------------------------*/
-
-/* Bars and Colors should match positions */
-
-enum colors {
-       WHITE,
-       AMBAR,
-       CYAN,
-       GREEN,
-       MAGENTA,
-       RED,
-       BLUE,
-       BLACK,
-};
-
-       /* R   G   B */
-#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 */
-#define TO_V(r, g, b) \
-       (((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
-/* RGB to  U(Cb) Color transform */
-#define TO_U(r, g, b) \
-       (((-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)
-{
-       struct vivi_dev *dev = fh->dev;
-       unsigned char 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];
-               is_yuv = 0;
-
-               switch (fh->fmt->fourcc) {
-               case V4L2_PIX_FMT_YUYV:
-               case V4L2_PIX_FMT_UYVY:
-                       is_yuv = 1;
-                       break;
-               case V4L2_PIX_FMT_RGB565:
-               case V4L2_PIX_FMT_RGB565X:
-                       r >>= 3;
-                       g >>= 2;
-                       b >>= 3;
-                       break;
-               case V4L2_PIX_FMT_RGB555:
-               case V4L2_PIX_FMT_RGB555X:
-                       r >>= 3;
-                       g >>= 3;
-                       b >>= 3;
-                       break;
-               }
-
-               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 */
-               } else {
-                       fh->bars[k][0] = r;
-                       fh->bars[k][1] = g;
-                       fh->bars[k][2] = b;
-               }
-       }
-
-}
-
-#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)
-{
-       unsigned char r_y, g_u, b_v;
-       unsigned char *p;
-       int color;
-
-       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 */
-
-       for (color = 0; color < 4; color++) {
-               p = buf + color;
-
-               switch (fh->fmt->fourcc) {
-               case V4L2_PIX_FMT_YUYV:
-                       switch (color) {
-                       case 0:
-                       case 2:
-                               *p = r_y;
-                               break;
-                       case 1:
-                               *p = g_u;
-                               break;
-                       case 3:
-                               *p = b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_UYVY:
-                       switch (color) {
-                       case 1:
-                       case 3:
-                               *p = r_y;
-                               break;
-                       case 0:
-                               *p = g_u;
-                               break;
-                       case 2:
-                               *p = b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB565:
-                       switch (color) {
-                       case 0:
-                       case 2:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       case 1:
-                       case 3:
-                               *p = (r_y << 3) | (g_u >> 3);
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB565X:
-                       switch (color) {
-                       case 0:
-                       case 2:
-                               *p = (r_y << 3) | (g_u >> 3);
-                               break;
-                       case 1:
-                       case 3:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB555:
-                       switch (color) {
-                       case 0:
-                       case 2:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       case 1:
-                       case 3:
-                               *p = (r_y << 2) | (g_u >> 3);
-                               break;
-                       }
-                       break;
-               case V4L2_PIX_FMT_RGB555X:
-                       switch (color) {
-                       case 0:
-                       case 2:
-                               *p = (r_y << 2) | (g_u >> 3);
-                               break;
-                       case 1:
-                       case 3:
-                               *p = (g_u << 5) | b_v;
-                               break;
-                       }
-                       break;
-               }
-       }
-}
-
-static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
-               int hmax, int line, int count, char *timestr)
-{
-       int  w, i, j;
-       int pos = inipos;
-       char *s;
-       u8 chr;
-
-       /* We will just duplicate the second pixel at the packet */
-       wmax /= 2;
-
-       /* 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 */
-       }
-
-       /* 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;
-
-       /* 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;
-                               /* Draw white font on black background */
-                               if (chr & 1 << (7 - i))
-                                       gen_twopix(fh, basep + pos, WHITE);
-                               else
-                                       gen_twopix(fh, basep + pos, BLACK);
-                               j++;
-                       }
-               }
-       }
-
-end:
-       return;
-}
-
-static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
-{
-       struct vivi_dev *dev = fh->dev;
-       int h , pos = 0;
-       int hmax  = buf->vb.height;
-       int wmax  = buf->vb.width;
-       struct timeval ts;
-       char *tmpbuf;
-       void *vbuf = videobuf_to_vmalloc(&buf->vb);
-
-       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);
-
-       /* Updates stream time */
-
-       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);
-
-       dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
-                       dev->timestr, (unsigned long)tmpbuf, pos);
-
-       /* Advice that buffer was filled */
-       buf->vb.field_count++;
-       do_gettimeofday(&ts);
-       buf->vb.ts = ts;
-       buf->vb.state = VIDEOBUF_DONE;
-}
-
-static void vivi_thread_tick(struct vivi_fh *fh)
-{
-       struct vivi_buffer *buf;
-       struct vivi_dev *dev = fh->dev;
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-
-       unsigned long flags = 0;
-
-       dprintk(dev, 1, "Thread tick\n");
-
-       spin_lock_irqsave(&dev->slock, flags);
-       if (list_empty(&dma_q->active)) {
-               dprintk(dev, 1, "No active queue to serve\n");
-               goto unlock;
-       }
-
-       buf = list_entry(dma_q->active.next,
-                        struct vivi_buffer, vb.queue);
-
-       /* Nobody is waiting on this buffer, return */
-       if (!waitqueue_active(&buf->vb.done))
-               goto unlock;
-
-       list_del(&buf->vb.queue);
-
-       do_gettimeofday(&buf->vb.ts);
-
-       /* Fill buffer */
-       vivi_fillbuff(fh, 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)
-{
-       struct vivi_dev *dev = fh->dev;
-       struct vivi_dmaqueue *dma_q = &dev->vidq;
-       int timeout;
-       DECLARE_WAITQUEUE(wait, current);
-
-       dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
-               (unsigned long)dma_q);
-
-       add_wait_queue(&dma_q->wq, &wait);
-       if (kthread_should_stop())
-               goto stop_task;
-
-       /* Calculate time to wake up */
-       timeout = msecs_to_jiffies(frames_to_ms(1));
-
-       vivi_thread_tick(fh);
-
-       schedule_timeout_interruptible(timeout);
-
-stop_task:
-       remove_wait_queue(&dma_q->wq, &wait);
-       try_to_freeze();
-}
-
-static int vivi_thread(void *data)
-{
-       struct vivi_fh  *fh = data;
-       struct vivi_dev *dev = fh->dev;
-
-       dprintk(dev, 1, "thread started\n");
-
-       set_freezable();
-
-       for (;;) {
-               vivi_sleep(fh);
-
-               if (kthread_should_stop())
-                       break;
-       }
-       dprintk(dev, 1, "thread: exit\n");
-       return 0;
-}
-
-static int vivi_start_thread(struct vivi_fh *fh)
-{
-       struct vivi_dev *dev = fh->dev;
-       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 (IS_ERR(dma_q->kthread)) {
-               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-               return PTR_ERR(dma_q->kthread);
-       }
-       /* 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)
-{
-       struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
-
-       dprintk(dev, 1, "%s\n", __func__);
-       /* shutdown control thread */
-       if (dma_q->kthread) {
-               kthread_stop(dma_q->kthread);
-               dma_q->kthread = NULL;
-       }
-}
-
-/* ------------------------------------------------------------------
-       Videobuf operations
-   ------------------------------------------------------------------*/
-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;
-
-       *size = fh->width*fh->height*2;
-
-       if (0 == *count)
-               *count = 32;
-
-       while (*size * *count > vid_limit * 1024 * 1024)
-               (*count)--;
-
-       dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
-               *count, *size);
-
-       return 0;
-}
-
-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;
-
-       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_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);
-
-       if (fh->width  < 48 || fh->width  > norm_maxw() ||
-           fh->height < 32 || fh->height > norm_maxh())
-               return -EINVAL;
-
-       buf->vb.size = fh->width*fh->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->vb.field  = field;
-
-       precalculate_bars(fh);
-
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               rc = videobuf_iolock(vq, &buf->vb, NULL);
-               if (rc < 0)
-                       goto fail;
-       }
-
-       buf->vb.state = VIDEOBUF_PREPARED;
-
-       return 0;
-
-fail:
-       free_buffer(vq, buf);
-       return rc;
-}
-
-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_dmaqueue *vidq = &dev->vidq;
-
-       dprintk(dev, 1, "%s\n", __func__);
-
-       buf->vb.state = VIDEOBUF_QUEUED;
-       list_add_tail(&buf->vb.queue, &vidq->active);
-}
-
-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;
-
-       dprintk(dev, 1, "%s\n", __func__);
-
-       free_buffer(vq, buf);
-}
-
-static struct videobuf_queue_ops vivi_video_qops = {
-       .buf_setup      = buffer_setup,
-       .buf_prepare    = buffer_prepare,
-       .buf_queue      = buffer_queue,
-       .buf_release    = buffer_release,
-};
-
-/* ------------------------------------------------------------------
-       IOCTL vidioc handling
-   ------------------------------------------------------------------*/
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *cap)
-{
-       struct vivi_fh  *fh  = priv;
-       struct vivi_dev *dev = fh->dev;
-
-       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;
-       return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
-                                       struct v4l2_fmtdesc *f)
-{
-       struct vivi_fmt *fmt;
-
-       if (f->index >= ARRAY_SIZE(formats))
-               return -EINVAL;
-
-       fmt = &formats[f->index];
-
-       strlcpy(f->description, fmt->name, sizeof(f->description));
-       f->pixelformat = fmt->fourcc;
-       return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_format *f)
-{
-       struct vivi_fh *fh = priv;
-
-       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.bytesperline =
-               (f->fmt.pix.width * fh->fmt->depth) >> 3;
-       f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
-
-       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_fmt *fmt;
-       enum v4l2_field field;
-       unsigned int maxw, maxh;
-
-       fmt = get_format(f);
-       if (!fmt) {
-               dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
-                       f->fmt.pix.pixelformat);
-               return -EINVAL;
-       }
-
-       field = f->fmt.pix.field;
-
-       if (field == V4L2_FIELD_ANY) {
-               field = V4L2_FIELD_INTERLACED;
-       } else if (V4L2_FIELD_INTERLACED != field) {
-               dprintk(dev, 1, "Field type invalid.\n");
-               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);
-       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;
-
-       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;
-
-       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;
-
-       return (videobuf_reqbufs(&fh->vb_vidq, p));
-}
-
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct vivi_fh  *fh = priv;
-
-       return (videobuf_querybuf(&fh->vb_vidq, p));
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct vivi_fh *fh = priv;
-
-       return (videobuf_qbuf(&fh->vb_vidq, p));
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct vivi_fh  *fh = priv;
-
-       return (videobuf_dqbuf(&fh->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;
-
-       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
-}
-#endif
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct vivi_fh  *fh = priv;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       return videobuf_streamon(&fh->vb_vidq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct vivi_fh  *fh = priv;
-
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (i != fh->type)
-               return -EINVAL;
-
-       return videobuf_streamoff(&fh->vb_vidq);
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
-{
-       return 0;
-}
-
-/* only one input in this sample driver */
-static int vidioc_enum_input(struct file *file, void *priv,
-                               struct v4l2_input *inp)
-{
-       if (inp->index >= NUM_INPUTS)
-               return -EINVAL;
-
-       inp->type = V4L2_INPUT_TYPE_CAMERA;
-       inp->std = V4L2_STD_525_60;
-       sprintf(inp->name, "Camera %u", inp->index);
-
-       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;
-
-       *i = dev->input;
-
-       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;
-
-       if (i >= NUM_INPUTS)
-               return -EINVAL;
-
-       dev->input = i;
-       precalculate_bars(fh);
-
-       return (0);
-}
-
-       /* --- 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);
-               }
-
-       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;
-
-       for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-               if (ctrl->id == vivi_qctrl[i].id) {
-                       ctrl->value = dev->qctl_regs[i];
-                       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;
-
-       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;
-               }
-       return -EINVAL;
-}
-
-/* ------------------------------------------------------------------
-       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 /dev/video%d type=%s users=%d\n", dev->vfd->num,
-               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;
-
-       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               return videobuf_read_stream(&fh->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;
-
-       dprintk(dev, 1, "%s\n", __func__);
-
-       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
-               return POLLERR;
-
-       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;
-
-       int minor = video_devdata(file)->minor;
-
-       vivi_stop_thread(vidq);
-       videobuf_stop(&fh->vb_vidq);
-       videobuf_mmap_free(&fh->vb_vidq);
-
-       kfree(fh);
-
-       mutex_lock(&dev->mutex);
-       dev->users--;
-       mutex_unlock(&dev->mutex);
-
-       dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
-               minor, dev->users);
-
-       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;
-       int ret;
-
-       dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
-
-       ret = videobuf_mmap_mapper(&fh->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,
-               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,
-       .ioctl          = video_ioctl2, /* V4L2 ioctl handler */
-       .mmap           = vivi_mmap,
-};
-
-static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
-       .vidioc_querycap      = vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs       = vidioc_reqbufs,
-       .vidioc_querybuf      = vidioc_querybuf,
-       .vidioc_qbuf          = vidioc_qbuf,
-       .vidioc_dqbuf         = vidioc_dqbuf,
-       .vidioc_s_std         = vidioc_s_std,
-       .vidioc_enum_input    = vidioc_enum_input,
-       .vidioc_g_input       = vidioc_g_input,
-       .vidioc_s_input       = vidioc_s_input,
-       .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
-};
-
-static struct video_device vivi_template = {
-       .name           = "vivi",
-       .fops           = &vivi_fops,
-       .ioctl_ops      = &vivi_ioctl_ops,
-       .minor          = -1,
-       .release        = video_device_release,
-
-       .tvnorms              = V4L2_STD_525_60,
-       .current_norm         = V4L2_STD_NTSC_M,
-};
-
-/* -----------------------------------------------------------------
-       Initialization and module stuff
-   ------------------------------------------------------------------*/
-
-static int vivi_release(void)
-{
-       struct vivi_dev *dev;
-       struct list_head *list;
-
-       while (!list_empty(&vivi_devlist)) {
-               list = vivi_devlist.next;
-               list_del(list);
-               dev = list_entry(list, struct vivi_dev, vivi_devlist);
-
-               v4l2_info(&dev->v4l2_dev, "unregistering /dev/video%d\n",
-                       dev->vfd->num);
-               video_unregister_device(dev->vfd);
-               v4l2_device_unregister(&dev->v4l2_dev);
-               kfree(dev);
-       }
-
-       return 0;
-}
-
-static int __init vivi_create_instance(int inst)
-{
-       struct vivi_dev *dev;
-       struct video_device *vfd;
-       int ret, i;
-
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-
-       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
-                       "%s-%03d", VIVI_MODULE_NAME, inst);
-       ret = v4l2_device_register(NULL, &dev->v4l2_dev);
-       if (ret)
-               goto free_dev;
-
-       /* init video dma queues */
-       INIT_LIST_HEAD(&dev->vidq.active);
-       init_waitqueue_head(&dev->vidq.wq);
-
-       /* initialize locks */
-       spin_lock_init(&dev->slock);
-       mutex_init(&dev->mutex);
-
-       ret = -ENOMEM;
-       vfd = video_device_alloc();
-       if (!vfd)
-               goto unreg_dev;
-
-       *vfd = vivi_template;
-       vfd->debug = debug;
-
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-       if (ret < 0)
-               goto rel_vdev;
-
-       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);
-
-       snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
-                       vivi_template.name, vfd->num);
-
-       if (video_nr >= 0)
-               video_nr++;
-
-       dev->vfd = vfd;
-       v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n",
-                       vfd->num);
-       return 0;
-
-rel_vdev:
-       video_device_release(vfd);
-unreg_dev:
-       v4l2_device_unregister(&dev->v4l2_dev);
-free_dev:
-       kfree(dev);
-       return ret;
-}
-
-/* This routine allocates from 1 to n_devs virtual drivers.
-
-   The real maximum number of virtual drivers will depend on how many drivers
-   will succeed. This is limited to the maximum number of devices that
-   videodev supports, which is equal to VIDEO_NUM_DEVICES.
- */
-static int __init vivi_init(void)
-{
-       int ret = 0, i;
-
-       if (n_devs <= 0)
-               n_devs = 1;
-
-       for (i = 0; i < n_devs; i++) {
-               ret = vivi_create_instance(i);
-               if (ret) {
-                       /* If some instantiations succeeded, keep driver */
-                       if (i)
-                               ret = 0;
-                       break;
-               }
-       }
-
-       if (ret < 0) {
-               printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
-               return ret;
-       }
-
-       printk(KERN_INFO "Video Technology Magazine Virtual Video "
-                       "Capture Board ver %u.%u.%u successfully loaded.\n",
-                       (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
-                       VIVI_VERSION & 0xFF);
-
-       /* n_devs will reflect the actual number of allocated devices */
-       n_devs = i;
-
-       return ret;
-}
-
-static void __exit vivi_exit(void)
-{
-       vivi_release();
-}
-
-module_init(vivi_init);
-module_exit(vivi_exit);
diff --git a/drivers/media/video/svvd.c b/drivers/media/video/svvd.c
new file mode 100755 (executable)
index 0000000..1834e47
--- /dev/null
@@ -0,0 +1,1441 @@
+/*
+ * Virtual Video driver - This code emulates a real video device with v4l2 api
+ *
+ * Copyright (C) 2011 S-core
+ * Copyright (c) 2006 by:
+ *      Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ *      Ted Walther <ted--a.t--enumera.com>
+ *      John Sokol <sokol--a.t--videotechnology.com>
+ *      http://v4l.videotechnology.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the BSD Licence, GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * 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/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>
+#include <linux/freezer.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include "font.h"
+
+#define VIVI_MODULE_NAME "vivi"
+
+/* Wake up at about 30 fps */
+#define WAKE_NUMERATOR 30
+#define WAKE_DENOMINATOR 1001
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
+
+#define VIVI_MAJOR_VERSION 0
+#define VIVI_MINOR_VERSION 6
+#define VIVI_RELEASE 0
+#define VIVI_VERSION \
+       KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
+
+static unsigned n_devs = 1;
+module_param(n_devs, uint, 0644);
+MODULE_PARM_DESC(n_devs, "number of video devices to create");
+
+static unsigned debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+static unsigned int vid_limit = 16;
+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,
+       }
+};
+
+#define dprintk(dev, level, fmt, arg...) \
+       v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
+
+/* ------------------------------------------------------------------
+       Basic structures
+   ------------------------------------------------------------------*/
+
+struct vivi_fmt {
+       char  *name;
+       u32   fourcc;          /* v4l2 format id */
+       int   depth;
+};
+
+static struct vivi_fmt formats[] = {
+       {
+               .name     = "4:2:2, packed, YUYV",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+       },
+       {
+               .name     = "4:2:2, packed, UYVY",
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB565 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB565 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB555 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+               .depth    = 16,
+       },
+};
+
+static struct vivi_fmt *get_format(struct v4l2_format *f)
+{
+       struct vivi_fmt *fmt;
+       unsigned int k;
+
+       for (k = 0; k < ARRAY_SIZE(formats); k++) {
+               fmt = &formats[k];
+               if (fmt->fourcc == f->fmt.pix.pixelformat)
+                       break;
+       }
+
+       if (k == ARRAY_SIZE(formats))
+               return NULL;
+
+       return &formats[k];
+}
+
+struct sg_to_addr {
+       int pos;
+       struct scatterlist *sg;
+};
+
+/* buffer for one video frame */
+struct vivi_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer vb;
+
+       struct vivi_fmt        *fmt;
+};
+
+struct vivi_dmaqueue {
+       struct list_head       active;
+
+       /* thread for generating video stream*/
+       struct task_struct         *kthread;
+       wait_queue_head_t          wq;
+       /* Counters to control fps rate */
+       int                        frame;
+       int                        ini_jiffies;
+};
+
+static LIST_HEAD(vivi_devlist);
+
+struct vivi_dev {
+       struct list_head           vivi_devlist;
+       struct v4l2_device         v4l2_dev;
+
+       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 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 */
+};
+
+/* ------------------------------------------------------------------
+       DMA and thread functions
+   ------------------------------------------------------------------*/
+
+/* Bars and Colors should match positions */
+
+enum colors {
+       WHITE,
+       AMBAR,
+       CYAN,
+       GREEN,
+       MAGENTA,
+       RED,
+       BLUE,
+       BLACK,
+};
+
+       /* R   G   B */
+#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 */
+#define TO_V(r, g, b) \
+       (((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
+/* RGB to  U(Cb) Color transform */
+#define TO_U(r, g, b) \
+       (((-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)
+{
+       struct vivi_dev *dev = fh->dev;
+       unsigned char 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];
+               is_yuv = 0;
+
+               switch (fh->fmt->fourcc) {
+               case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_UYVY:
+                       is_yuv = 1;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+                       r >>= 3;
+                       g >>= 2;
+                       b >>= 3;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       r >>= 3;
+                       g >>= 3;
+                       b >>= 3;
+                       break;
+               }
+
+               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 */
+               } else {
+                       fh->bars[k][0] = r;
+                       fh->bars[k][1] = g;
+                       fh->bars[k][2] = b;
+               }
+       }
+
+}
+
+#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)
+{
+       unsigned char r_y, g_u, b_v;
+       unsigned char *p;
+       int color;
+
+       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 */
+
+       for (color = 0; color < 4; color++) {
+               p = buf + color;
+
+               switch (fh->fmt->fourcc) {
+               case V4L2_PIX_FMT_YUYV:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = r_y;
+                               break;
+                       case 1:
+                               *p = g_u;
+                               break;
+                       case 3:
+                               *p = b_v;
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_UYVY:
+                       switch (color) {
+                       case 1:
+                       case 3:
+                               *p = r_y;
+                               break;
+                       case 0:
+                               *p = g_u;
+                               break;
+                       case 2:
+                               *p = b_v;
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (r_y << 3) | (g_u >> 3);
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB565X:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (r_y << 3) | (g_u >> 3);
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (r_y << 2) | (g_u >> 3);
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB555X:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (r_y << 2) | (g_u >> 3);
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       }
+                       break;
+               }
+       }
+}
+
+static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
+               int hmax, int line, int count, char *timestr)
+{
+       int  w, i, j;
+       int pos = inipos;
+       char *s;
+       u8 chr;
+
+       /* We will just duplicate the second pixel at the packet */
+       wmax /= 2;
+
+       /* 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 */
+       }
+
+       /* 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;
+
+       /* 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;
+                               /* Draw white font on black background */
+                               if (chr & 1 << (7 - i))
+                                       gen_twopix(fh, basep + pos, WHITE);
+                               else
+                                       gen_twopix(fh, basep + pos, BLACK);
+                               j++;
+                       }
+               }
+       }
+
+end:
+       return;
+}
+
+static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
+{
+       struct vivi_dev *dev = fh->dev;
+       int h , pos = 0;
+       int hmax  = buf->vb.height;
+       int wmax  = buf->vb.width;
+       struct timeval ts;
+       char *tmpbuf;
+       void *vbuf = videobuf_to_vmalloc(&buf->vb);
+
+       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);
+
+       /* Updates stream time */
+
+       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);
+
+       dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
+                       dev->timestr, (unsigned long)tmpbuf, pos);
+
+       /* Advice that buffer was filled */
+       buf->vb.field_count++;
+       do_gettimeofday(&ts);
+       buf->vb.ts = ts;
+       buf->vb.state = VIDEOBUF_DONE;
+}
+
+static void vivi_thread_tick(struct vivi_fh *fh)
+{
+       struct vivi_buffer *buf;
+       struct vivi_dev *dev = fh->dev;
+       struct vivi_dmaqueue *dma_q = &dev->vidq;
+
+       unsigned long flags = 0;
+
+       dprintk(dev, 1, "Thread tick\n");
+
+       spin_lock_irqsave(&dev->slock, flags);
+       if (list_empty(&dma_q->active)) {
+               dprintk(dev, 1, "No active queue to serve\n");
+               goto unlock;
+       }
+
+       buf = list_entry(dma_q->active.next,
+                        struct vivi_buffer, vb.queue);
+
+       /* Nobody is waiting on this buffer, return */
+       if (!waitqueue_active(&buf->vb.done))
+               goto unlock;
+
+       list_del(&buf->vb.queue);
+
+       do_gettimeofday(&buf->vb.ts);
+
+       /* Fill buffer */
+       vivi_fillbuff(fh, 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)
+{
+       struct vivi_dev *dev = fh->dev;
+       struct vivi_dmaqueue *dma_q = &dev->vidq;
+       int timeout;
+       DECLARE_WAITQUEUE(wait, current);
+
+       dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
+               (unsigned long)dma_q);
+
+       add_wait_queue(&dma_q->wq, &wait);
+       if (kthread_should_stop())
+               goto stop_task;
+
+       /* Calculate time to wake up */
+       timeout = msecs_to_jiffies(frames_to_ms(1));
+
+       vivi_thread_tick(fh);
+
+       schedule_timeout_interruptible(timeout);
+
+stop_task:
+       remove_wait_queue(&dma_q->wq, &wait);
+       try_to_freeze();
+}
+
+static int vivi_thread(void *data)
+{
+       struct vivi_fh  *fh = data;
+       struct vivi_dev *dev = fh->dev;
+
+       dprintk(dev, 1, "thread started\n");
+
+       set_freezable();
+
+       for (;;) {
+               vivi_sleep(fh);
+
+               if (kthread_should_stop())
+                       break;
+       }
+       dprintk(dev, 1, "thread: exit\n");
+       return 0;
+}
+
+static int vivi_start_thread(struct vivi_fh *fh)
+{
+       struct vivi_dev *dev = fh->dev;
+       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 (IS_ERR(dma_q->kthread)) {
+               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+               return PTR_ERR(dma_q->kthread);
+       }
+       /* 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)
+{
+       struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       /* shutdown control thread */
+       if (dma_q->kthread) {
+               kthread_stop(dma_q->kthread);
+               dma_q->kthread = NULL;
+       }
+}
+
+/* ------------------------------------------------------------------
+       Videobuf operations
+   ------------------------------------------------------------------*/
+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;
+
+       *size = fh->width*fh->height*2;
+
+       if (0 == *count)
+               *count = 32;
+
+       while (*size * *count > vid_limit * 1024 * 1024)
+               (*count)--;
+
+       dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
+               *count, *size);
+
+       return 0;
+}
+
+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;
+
+       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_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);
+
+       if (fh->width  < 48 || fh->width  > norm_maxw() ||
+           fh->height < 32 || fh->height > norm_maxh())
+               return -EINVAL;
+
+       buf->vb.size = fh->width*fh->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->vb.field  = field;
+
+       precalculate_bars(fh);
+
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               rc = videobuf_iolock(vq, &buf->vb, NULL);
+               if (rc < 0)
+                       goto fail;
+       }
+
+       buf->vb.state = VIDEOBUF_PREPARED;
+
+       return 0;
+
+fail:
+       free_buffer(vq, buf);
+       return rc;
+}
+
+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_dmaqueue *vidq = &dev->vidq;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       buf->vb.state = VIDEOBUF_QUEUED;
+       list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+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;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops vivi_video_qops = {
+       .buf_setup      = buffer_setup,
+       .buf_prepare    = buffer_prepare,
+       .buf_queue      = buffer_queue,
+       .buf_release    = buffer_release,
+};
+
+/* ------------------------------------------------------------------
+       IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+static int vidioc_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct vivi_fh  *fh  = priv;
+       struct vivi_dev *dev = fh->dev;
+
+       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;
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       struct vivi_fmt *fmt;
+
+       if (f->index >= ARRAY_SIZE(formats))
+               return -EINVAL;
+
+       fmt = &formats[f->index];
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivi_fh *fh = priv;
+
+       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.bytesperline =
+               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       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_fmt *fmt;
+       enum v4l2_field field;
+       unsigned int maxw, maxh;
+
+       fmt = get_format(f);
+       if (!fmt) {
+               dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
+                       f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
+
+       field = f->fmt.pix.field;
+
+       if (field == V4L2_FIELD_ANY) {
+               field = V4L2_FIELD_INTERLACED;
+       } else if (V4L2_FIELD_INTERLACED != field) {
+               dprintk(dev, 1, "Field type invalid.\n");
+               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);
+       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;
+
+       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;
+
+       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;
+
+       return (videobuf_reqbufs(&fh->vb_vidq, p));
+}
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct vivi_fh  *fh = priv;
+
+       return (videobuf_querybuf(&fh->vb_vidq, p));
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct vivi_fh *fh = priv;
+
+       return (videobuf_qbuf(&fh->vb_vidq, p));
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct vivi_fh  *fh = priv;
+
+       return (videobuf_dqbuf(&fh->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;
+
+       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct vivi_fh  *fh = priv;
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
+
+       return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct vivi_fh  *fh = priv;
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
+
+       return videobuf_streamoff(&fh->vb_vidq);
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+       return 0;
+}
+
+/* only one input in this sample driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *inp)
+{
+       if (inp->index >= NUM_INPUTS)
+               return -EINVAL;
+
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->std = V4L2_STD_525_60;
+       sprintf(inp->name, "Camera %u", inp->index);
+
+       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;
+
+       *i = dev->input;
+
+       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;
+
+       if (i >= NUM_INPUTS)
+               return -EINVAL;
+
+       dev->input = i;
+       precalculate_bars(fh);
+
+       return (0);
+}
+
+       /* --- 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);
+               }
+
+       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;
+
+       for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+               if (ctrl->id == vivi_qctrl[i].id) {
+                       ctrl->value = dev->qctl_regs[i];
+                       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;
+
+       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;
+               }
+       return -EINVAL;
+}
+
+/* ------------------------------------------------------------------
+       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 /dev/video%d type=%s users=%d\n", dev->vfd->num,
+               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;
+
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               return videobuf_read_stream(&fh->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;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+               return POLLERR;
+
+       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;
+
+       int minor = video_devdata(file)->minor;
+
+       vivi_stop_thread(vidq);
+       videobuf_stop(&fh->vb_vidq);
+       videobuf_mmap_free(&fh->vb_vidq);
+
+       kfree(fh);
+
+       mutex_lock(&dev->mutex);
+       dev->users--;
+       mutex_unlock(&dev->mutex);
+
+       dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
+               minor, dev->users);
+
+       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;
+       int ret;
+
+       dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+       ret = videobuf_mmap_mapper(&fh->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,
+               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,
+       .ioctl          = video_ioctl2, /* V4L2 ioctl handler */
+       .mmap           = vivi_mmap,
+};
+
+static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+       .vidioc_reqbufs       = vidioc_reqbufs,
+       .vidioc_querybuf      = vidioc_querybuf,
+       .vidioc_qbuf          = vidioc_qbuf,
+       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .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
+};
+
+static struct video_device vivi_template = {
+       .name           = "vivi",
+       .fops           = &vivi_fops,
+       .ioctl_ops      = &vivi_ioctl_ops,
+       .minor          = -1,
+       .release        = video_device_release,
+
+       .tvnorms              = V4L2_STD_525_60,
+       .current_norm         = V4L2_STD_NTSC_M,
+};
+
+/* -----------------------------------------------------------------
+       Initialization and module stuff
+   ------------------------------------------------------------------*/
+
+static int vivi_release(void)
+{
+       struct vivi_dev *dev;
+       struct list_head *list;
+
+       while (!list_empty(&vivi_devlist)) {
+               list = vivi_devlist.next;
+               list_del(list);
+               dev = list_entry(list, struct vivi_dev, vivi_devlist);
+
+               v4l2_info(&dev->v4l2_dev, "unregistering /dev/video%d\n",
+                       dev->vfd->num);
+               video_unregister_device(dev->vfd);
+               v4l2_device_unregister(&dev->v4l2_dev);
+               kfree(dev);
+       }
+
+       return 0;
+}
+
+static int __init svvd_create_instance(int inst)
+{
+       struct vivi_dev *dev;
+       struct video_device *vfd;
+       int ret, i;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+                       "%s-%03d", VIVI_MODULE_NAME, inst);
+       ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+       if (ret)
+               goto free_dev;
+
+       /* init video dma queues */
+       INIT_LIST_HEAD(&dev->vidq.active);
+       init_waitqueue_head(&dev->vidq.wq);
+
+       /* initialize locks */
+       spin_lock_init(&dev->slock);
+       mutex_init(&dev->mutex);
+
+       ret = -ENOMEM;
+       vfd = video_device_alloc();
+       if (!vfd)
+               goto unreg_dev;
+
+       *vfd = vivi_template;
+       vfd->debug = debug;
+
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+       if (ret < 0)
+               goto rel_vdev;
+
+       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);
+
+       snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
+                       vivi_template.name, vfd->num);
+
+       if (video_nr >= 0)
+               video_nr++;
+
+       dev->vfd = vfd;
+       v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n",
+                       vfd->num);
+       return 0;
+
+rel_vdev:
+       video_device_release(vfd);
+unreg_dev:
+       v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+       kfree(dev);
+       return ret;
+}
+
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+   The real maximum number of virtual drivers will depend on how many drivers
+   will succeed. This is limited to the maximum number of devices that
+   videodev supports, which is equal to VIDEO_NUM_DEVICES.
+ */
+static int __init svvd_init(void)
+{
+       int ret = 0, i;
+
+       if (n_devs <= 0)
+               n_devs = 1;
+
+       for (i = 0; i < n_devs; i++) {
+               ret = svvd_create_instance(i);
+               if (ret) {
+                       /* If some instantiations succeeded, keep driver */
+                       if (i)
+                               ret = 0;
+                       break;
+               }
+       }
+
+       if (ret < 0) {
+               printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
+               return ret;
+       }
+
+       printk(KERN_INFO "Video Technology Magazine Virtual Video "
+                       "Capture Board ver %u.%u.%u successfully loaded.\n",
+                       (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
+                       VIVI_VERSION & 0xFF);
+
+       /* n_devs will reflect the actual number of allocated devices */
+       n_devs = i;
+
+       return ret;
+}
+
+static void __exit svvd_exit(void)
+{
+       vivi_release();
+}
+
+module_init(svvd_init);
+module_exit(svvd_exit);