V4L/DVB (6152): cx23885: forward compatibility fixes for recent kernels
[safe/jmp/linux-2.6] / drivers / media / video / vivi.c
index 779db26..c10169e 100644 (file)
@@ -25,6 +25,7 @@
 #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>
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -36,6 +37,7 @@
 #include <media/v4l2-common.h>
 #include <linux/kthread.h>
 #include <linux/highmem.h>
+#include <linux/freezer.h>
 
 /* Wake up at about 30 fps */
 #define WAKE_NUMERATOR 30
 
 #include "font.h"
 
-#ifndef kzalloc
-#define kzalloc(size, flags)                            \
-({                                                      \
-       void *__ret = kmalloc(size, flags);             \
-       if (__ret)                                      \
-               memset(__ret, 0, size);                 \
-       __ret;                                          \
-})
-#endif
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-
 #define VIVI_MAJOR_VERSION 0
 #define VIVI_MINOR_VERSION 4
 #define VIVI_RELEASE 0
 #define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
 
-static int video_nr = -1;        /* /dev/videoN, -1 for autodetect */
-module_param(video_nr, int, 0);
-
-static int debug = 0;
-module_param(debug, int, 0);
-
-static unsigned int vid_limit = 16;
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16;    /* Video memory limit, in Mb */
+static struct video_device vivi;       /* Video device */
+static int video_nr = -1;              /* /dev/videoN, -1 for autodetect */
 
 /* supported controls */
 static struct v4l2_queryctrl vivi_qctrl[] = {
@@ -129,10 +112,10 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
 
 static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
 
-#define dprintk(level,fmt, arg...)                          \
-       do {                                                 \
-               if (debug >= (level))                        \
-                       printk(KERN_DEBUG "vivi: " fmt , ## arg);    \
+#define dprintk(level,fmt, arg...)                                     \
+       do {                                                            \
+               if (vivi.debug >= (level))                              \
+                       printk(KERN_DEBUG "vivi: " fmt , ## arg);       \
        } while (0)
 
 /* ------------------------------------------------------------------
@@ -163,7 +146,6 @@ struct vivi_buffer {
 
        struct vivi_fmt        *fmt;
 
-       struct sg_to_addr      *to_addr;
 };
 
 struct vivi_dmaqueue {
@@ -184,13 +166,13 @@ static LIST_HEAD(vivi_devlist);
 struct vivi_dev {
        struct list_head           vivi_devlist;
 
-       struct semaphore           lock;
+       struct mutex               lock;
 
        int                        users;
 
        /* various device info */
        unsigned int               resources;
-       struct video_device        video_dev;
+       struct video_device        vfd;
 
        struct vivi_dmaqueue       vidq;
 
@@ -248,51 +230,14 @@ static u8 bars[8][3] = {
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
-void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb)
-{
-       int i, pos=0;
-
-       for (i=0;i<vb->dma.nr_pages;i++) {
-               to_addr[i].sg=&vb->dma.sglist[i];
-               to_addr[i].pos=pos;
-               pos += vb->dma.sglist[i].length;
-       }
-}
-
-inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
-{
-       int p1=0,p2=pages-1,p3=pages/2;
-
-       /* Sanity test */
-       BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);
-
-       while (p1+1<p2) {
-               if (pos < to_addr[p3].pos) {
-                       p2=p3;
-               } else {
-                       p1=p3;
-               }
-               p3=(p1+p2)/2;
-       }
-       if (pos >= to_addr[p2].pos)
-               p1=p2;
-
-       return (p1);
-}
 
-void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
-                                       int hmax, int line, char *timestr)
+static void gen_line(char *basep,int inipos,int wmax,
+                    int hmax, int line, char *timestr)
 {
-       int  w,i,j,pos=inipos,pgpos,oldpg,y;
-       char *p,*s,*basep;
-       struct page *pg;
+       int  w,i,j,pos=inipos,y;
+       char *p,*s;
        u8   chr,r,g,b,color;
 
-       /* Get first addr pointed to pixel position */
-       oldpg=get_addr_pos(pos,pages,to_addr);
-       pg=pfn_to_page(to_addr[oldpg].sg->dma_address >> PAGE_SHIFT);
-       basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
-
        /* We will just duplicate the second pixel at the packet */
        wmax/=2;
 
@@ -303,14 +248,7 @@ void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
                b=bars[w*7/wmax][2];
 
                for (color=0;color<4;color++) {
-                       pgpos=get_addr_pos(pos,pages,to_addr);
-                       if (pgpos!=oldpg) {
-                               pg=pfn_to_page(to_addr[pgpos].sg->dma_address >> PAGE_SHIFT);
-                               kunmap_atomic(basep, KM_BOUNCE_READ);
-                               basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
-                               oldpg=pgpos;
-                       }
-                       p=basep+pos-to_addr[pgpos].pos;
+                       p=basep+pos;
 
                        switch (color) {
                                case 0:
@@ -355,19 +293,7 @@ void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
 
                                pos=inipos+j*2;
                                for (color=0;color<4;color++) {
-                                       pgpos=get_addr_pos(pos,pages,to_addr);
-                                       if (pgpos!=oldpg) {
-                                               pg=pfn_to_page(to_addr[pgpos].
-                                                               sg->dma_address
-                                                               >> PAGE_SHIFT);
-                                               kunmap_atomic(basep,
-                                                               KM_BOUNCE_READ);
-                                               basep= kmap_atomic(pg,
-                                                       KM_BOUNCE_READ)+
-                                                       to_addr[pgpos].sg->offset;
-                                               oldpg=pgpos;
-                                       }
-                                       p=basep+pos-to_addr[pgpos].pos;
+                                       p=basep+pos;
 
                                        y=TO_Y(r,g,b);
 
@@ -392,28 +318,32 @@ void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
 
 
 end:
-       kunmap_atomic(basep, KM_BOUNCE_READ);
+       return;
 }
 static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
 {
        int h,pos=0;
        int hmax  = buf->vb.height;
        int wmax  = buf->vb.width;
-       struct videobuf_buffer *vb=&buf->vb;
-       struct sg_to_addr *to_addr=buf->to_addr;
        struct timeval ts;
+       char *tmpbuf;
 
-       /* Test if DMA mapping is ready */
-       if (!vb->dma.sglist[0].dma_address)
-               return;
-
-       prep_to_addr(to_addr,vb);
+       if (buf->vb.dma.varea) {
+               tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
+       } else {
+               tmpbuf=buf->vb.dma.vmalloc;
+       }
 
-       /* Check if there is enough memory */
-       BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
 
        for (h=0;h<hmax;h++) {
-               gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
+               if (buf->vb.dma.varea) {
+                       gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
+                       /* FIXME: replacing to __copy_to_user */
+                       if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0)
+                               dprintk(2,"vivifill copy_to_user failed.\n");
+               } else {
+                       gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
+               }
                pos += wmax*2;
        }
 
@@ -439,7 +369,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
                        dev->h,dev->m,dev->s,(dev->us+500)/1000);
 
        dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
-                       (unsigned long)buf->vb.dma.vmalloc,pos);
+                       (unsigned long)buf->vb.dma.varea,pos);
 
        /* Advice that buffer was filled */
        buf->vb.state = STATE_DONE;
@@ -481,17 +411,18 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
 
                /* Fill buffer */
                vivi_fillbuff(dev,buf);
-       }
-       if (list_empty(&dma_q->active)) {
-               del_timer(&dma_q->timeout);
-       } else {
-               mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+
+               if (list_empty(&dma_q->active)) {
+                       del_timer(&dma_q->timeout);
+               } else {
+                       mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+               }
        }
        if (bc != 1)
                dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
 }
 
-void vivi_sleep(struct vivi_dmaqueue  *dma_q)
+static void vivi_sleep(struct vivi_dmaqueue  *dma_q)
 {
        int timeout;
        DECLARE_WAITQUEUE(wait, current);
@@ -526,12 +457,15 @@ void vivi_sleep(struct vivi_dmaqueue  *dma_q)
        try_to_freeze();
 }
 
-int vivi_thread(void *data)
+static int vivi_thread(void *data)
 {
        struct vivi_dmaqueue  *dma_q=data;
 
        dprintk(1,"thread started\n");
 
+       mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+       set_freezable();
+
        for (;;) {
                vivi_sleep(dma_q);
 
@@ -542,25 +476,27 @@ int vivi_thread(void *data)
        return 0;
 }
 
-int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
+static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
 {
        dma_q->frame=0;
        dma_q->ini_jiffies=jiffies;
 
        dprintk(1,"%s\n",__FUNCTION__);
-       init_waitqueue_head(&dma_q->wq);
 
        dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
 
-       if (dma_q->kthread == NULL) {
+       if (IS_ERR(dma_q->kthread)) {
                printk(KERN_ERR "vivi: kernel_thread() failed\n");
-               return -EINVAL;
+               return PTR_ERR(dma_q->kthread);
        }
+       /* Wakes thread */
+       wake_up_interruptible(&dma_q->wq);
+
        dprintk(1,"returning from %s\n",__FUNCTION__);
        return 0;
 }
 
-void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
+static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
 {
        dprintk(1,"%s\n",__FUNCTION__);
        /* shutdown control thread */
@@ -666,17 +602,13 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
        return 0;
 }
 
-void
-free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
 {
        dprintk(1,"%s\n",__FUNCTION__);
 
        if (in_interrupt())
                BUG();
 
-       /*FIXME: Maybe a spinlock is required here */
-       kfree(buf->to_addr);
-       buf->to_addr=NULL;
 
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_unmap(vq, &buf->vb.dma);
@@ -722,11 +654,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 
        buf->vb.state = STATE_PREPARED;
 
-       if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
-               rc=-ENOMEM;
-               goto fail;
-       }
-
        return 0;
 
 fail:
@@ -791,56 +718,97 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
        free_buffer(vq,buf);
 }
 
-int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
-          int direction)
-{
-       int i;
 
-       dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents);
-       BUG_ON(direction == DMA_NONE);
+static struct videobuf_queue_ops vivi_video_qops = {
+       .buf_setup      = buffer_setup,
+       .buf_prepare    = buffer_prepare,
+       .buf_queue      = buffer_queue,
+       .buf_release    = buffer_release,
+
+       /* Non-pci handling routines */
+//     .vb_map_sg      = vivi_map_sg,
+//     .vb_dma_sync_sg = vivi_dma_sync_sg,
+//     .vb_unmap_sg    = vivi_unmap_sg,
+};
+
+/* ------------------------------------------------------------------
+       IOCTL handling
+   ------------------------------------------------------------------*/
 
-       for (i = 0; i < nents; i++ ) {
-               BUG_ON(!sg[i].page);
 
-               sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+       /* is it free? */
+       mutex_lock(&dev->lock);
+       if (dev->resources) {
+               /* no, someone else uses it */
+               mutex_unlock(&dev->lock);
+               return 0;
        }
+       /* it's free, grab it */
+       dev->resources =1;
+       dprintk(1,"res: get\n");
+       mutex_unlock(&dev->lock);
+       return 1;
+}
 
-       return nents;
+static int res_locked(struct vivi_dev *dev)
+{
+       return (dev->resources);
 }
 
-int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
-                                       int direction)
+static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
 {
-       dprintk(1,"%s\n",__FUNCTION__);
+       mutex_lock(&dev->lock);
+       dev->resources = 0;
+       dprintk(1,"res: put\n");
+       mutex_lock(&dev->lock);
+}
+
+/* ------------------------------------------------------------------
+       IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+static int vidioc_querycap (struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "vivi");
+       strcpy(cap->card, "vivi");
+       cap->version = VIVI_VERSION;
+       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_STREAMING     |
+                               V4L2_CAP_READWRITE;
        return 0;
 }
 
-int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist,int nr_pages,
-                                       int direction)
+static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
 {
-//     dprintk(1,"%s\n",__FUNCTION__);
+       if (f->index > 0)
+               return -EINVAL;
 
-//     flush_write_buffers();
+       strlcpy(f->description,format.name,sizeof(f->description));
+       f->pixelformat = format.fourcc;
        return 0;
 }
 
-static struct videobuf_queue_ops vivi_video_qops = {
-       .buf_setup      = buffer_setup,
-       .buf_prepare    = buffer_prepare,
-       .buf_queue      = buffer_queue,
-       .buf_release    = buffer_release,
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct vivi_fh  *fh=priv;
 
-       /* Non-pci handling routines */
-       .vb_map_sg      = vivi_map_sg,
-       .vb_dma_sync_sg = vivi_dma_sync_sg,
-       .vb_unmap_sg    = vivi_unmap_sg,
-};
+       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;
 
-/* ------------------------------------------------------------------
-       IOCTL handling
-   ------------------------------------------------------------------*/
+       return (0);
+}
 
-static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
                        struct v4l2_format *f)
 {
        struct vivi_fmt *fmt;
@@ -848,7 +816,8 @@ static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
        unsigned int maxw, maxh;
 
        if (format.fourcc != f->fmt.pix.pixelformat) {
-               dprintk(1,"Fourcc format invalid.\n");
+               dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
+                       "only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
                return -EINVAL;
        }
        fmt=&format;
@@ -884,356 +853,189 @@ static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
        return 0;
 }
 
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+                                       struct v4l2_format *f)
 {
-       /* is it free? */
-       down(&dev->lock);
-       if (dev->resources) {
-               /* no, someone else uses it */
-               up(&dev->lock);
-               return 0;
-       }
-       /* it's free, grab it */
-       dev->resources =1;
-       dprintk(1,"res: get\n");
-       up(&dev->lock);
-       return 1;
+       struct vivi_fh  *fh=priv;
+       int ret = vidioc_try_fmt_cap(file,fh,f);
+       if (ret < 0)
+               return (ret);
+
+       fh->fmt           = &format;
+       fh->width         = f->fmt.pix.width;
+       fh->height        = f->fmt.pix.height;
+       fh->vb_vidq.field = f->fmt.pix.field;
+       fh->type          = f->type;
+
+       return (0);
 }
 
-static inline int res_locked(struct vivi_dev *dev)
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
 {
-       return (dev->resources);
+       struct vivi_fh  *fh=priv;
+
+       return (videobuf_reqbufs(&fh->vb_vidq, p));
 }
 
-static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       down(&dev->lock);
-       dev->resources = 0;
-       dprintk(1,"res: put\n");
-       up(&dev->lock);
+       struct vivi_fh  *fh=priv;
+
+       return (videobuf_querybuf(&fh->vb_vidq, p));
 }
 
-static int vivi_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct vivi_fh  *fh     = file->private_data;
-       struct vivi_dev *dev    = fh->dev;
-       int ret=0;
-
-       if (debug) {
-               if (_IOC_DIR(cmd) & _IOC_WRITE)
-                       v4l_printk_ioctl_arg("vivi(w)",cmd, arg);
-               else if (!_IOC_DIR(cmd) & _IOC_READ) {
-                       v4l_print_ioctl("vivi", cmd);
-               }
-       }
+       struct vivi_fh  *fh=priv;
 
-       switch(cmd) {
-       /* --- capabilities ------------------------------------------ */
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = (struct v4l2_capability*)arg;
-
-               memset(cap, 0, sizeof(*cap));
-
-               strcpy(cap->driver, "vivi");
-               strcpy(cap->card, "vivi");
-               cap->version = VIVI_VERSION;
-               cap->capabilities =
-                                       V4L2_CAP_VIDEO_CAPTURE |
-                                       V4L2_CAP_STREAMING     |
-                                       V4L2_CAP_READWRITE;
-               break;
-       }
-       /* --- capture ioctls ---------------------------------------- */
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *f = arg;
-               enum v4l2_buf_type type;
-               unsigned int index;
+       return (videobuf_qbuf(&fh->vb_vidq, p));
+}
 
-               index = f->index;
-               type  = f->type;
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct vivi_fh  *fh=priv;
 
-               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
+       return (videobuf_dqbuf(&fh->vb_vidq, p,
+                               file->f_flags & O_NONBLOCK));
+}
 
-               switch (type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       if (index > 0){
-                               ret=-EINVAL;
-                               break;
-                       }
-                       memset(f,0,sizeof(*f));
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+       struct vivi_fh  *fh=priv;
+       struct videobuf_queue *q=&fh->vb_vidq;
+       struct v4l2_requestbuffers req;
+       unsigned int i;
+       int ret;
 
-                       f->index = index;
-                       f->type  = type;
-                       strlcpy(f->description,format.name,sizeof(f->description));
-                       f->pixelformat = format.fourcc;
-                       break;
-               default:
-                       ret=-EINVAL;
-               }
-               break;
+       req.type   = q->type;
+       req.count  = 8;
+       req.memory = V4L2_MEMORY_MMAP;
+       ret = videobuf_reqbufs(q,&req);
+       if (ret < 0)
+               return (ret);
+
+       mbuf->frames = req.count;
+       mbuf->size   = 0;
+       for (i = 0; i < mbuf->frames; i++) {
+               mbuf->offsets[i]  = q->bufs[i]->boff;
+               mbuf->size       += q->bufs[i]->bsize;
        }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = (struct v4l2_format *)arg;
+       return (0);
+}
+#endif
 
-               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct vivi_fh  *fh=priv;
+       struct vivi_dev *dev    = fh->dev;
 
-               memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
-               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;
-               break;
-       }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
 
-               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       dprintk(1,"Only capture supported.\n");
-                       ret=-EINVAL;
-                       break;
-               }
+       if (!res_get(dev,fh))
+               return -EBUSY;
+       return (videobuf_streamon(&fh->vb_vidq));
+}
 
-               ret = vivi_try_fmt(dev,fh,f);
-               if (ret < 0)
-                       break;
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct vivi_fh  *fh=priv;
+       struct vivi_dev *dev    = fh->dev;
 
-               fh->fmt           = &format;
-               fh->width         = f->fmt.pix.width;
-               fh->height        = f->fmt.pix.height;
-               fh->vb_vidq.field = f->fmt.pix.field;
-               fh->type          = f->type;
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
 
-               break;
-       }
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = arg;
-               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
+       videobuf_streamoff(&fh->vb_vidq);
+       res_free(dev,fh);
 
-               ret=vivi_try_fmt(dev,fh,f);
-               break;
-       }
-       case VIDIOC_REQBUFS:
-               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
-               ret=videobuf_reqbufs(&fh->vb_vidq, arg);
-               break;
-       case VIDIOC_QUERYBUF:
-               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
-               ret=videobuf_querybuf(&fh->vb_vidq, arg);
-               break;
-       case VIDIOC_QBUF:
-               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
-               ret=videobuf_qbuf(&fh->vb_vidq, arg);
-               break;
-       case VIDIOC_DQBUF:
-               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
-               ret=videobuf_dqbuf(&fh->vb_vidq, arg,
-                                       file->f_flags & O_NONBLOCK);
-               break;
-#ifdef HAVE_V4L1
-       /* --- streaming capture ------------------------------------- */
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *mbuf = arg;
-               struct videobuf_queue *q=&fh->vb_vidq;
-               struct v4l2_requestbuffers req;
-               unsigned int i;
-
-               memset(&req,0,sizeof(req));
-               req.type   = q->type;
-               req.count  = 8;
-               req.memory = V4L2_MEMORY_MMAP;
-               ret = videobuf_reqbufs(q,&req);
-               if (ret < 0)
-                       break;
-               memset(mbuf,0,sizeof(*mbuf));
-               mbuf->frames = req.count;
-               mbuf->size   = 0;
-               for (i = 0; i < mbuf->frames; i++) {
-                       mbuf->offsets[i]  = q->bufs[i]->boff;
-                       mbuf->size       += q->bufs[i]->bsize;
-               }
-               break;
-       }
-#endif
-       case VIDIOC_STREAMON:
-       {
-               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               if (!res_get(dev,fh))
-                       return -EBUSY;
-               ret=videobuf_streamon(&fh->vb_vidq);
-               break;
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       ret=-EINVAL;
-                       break;
-               }
-               ret = videobuf_streamoff(&fh->vb_vidq);
-               if (ret < 0)
-                       break;
-               res_free(dev,fh);
-               break;
-       }
-       /* ---------- tv norms ---------- */
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *e = arg;
-
-               if (e->index>0) {
-                       ret=-EINVAL;
-                       break;
-               }
-               ret = v4l2_video_std_construct(e, V4L2_STD_NTSC_M, "NTSC-M");
+       return (0);
+}
 
-               /* Allows vivi to use different fps from video std */
-               e->frameperiod.numerator = WAKE_NUMERATOR;
-               e->frameperiod.denominator = WAKE_DENOMINATOR;
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
+{
+       return 0;
+}
 
-               break;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
+/* only one input in this sample driver */
+static int vidioc_enum_input (struct file *file, void *priv,
+                               struct v4l2_input *inp)
+{
+       if (inp->index != 0)
+               return -EINVAL;
 
-               *id = V4L2_STD_NTSC_M;
-               break;
-       }
-       case VIDIOC_S_STD:
-       {
-               break;
-       }
-       /* ------ input switching ---------- */
-       case VIDIOC_ENUMINPUT:
-       { /* only one input in this sample driver */
-               struct v4l2_input *inp = arg;
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->std = V4L2_STD_NTSC_M;
+       strcpy(inp->name,"Camera");
 
-               if (inp->index != 0) {
-                       ret=-EINVAL;
-                       break;
-               }
-               memset(inp, 0, sizeof(*inp));
+       return (0);
+}
 
-               inp->index = 0;
-               inp->type = V4L2_INPUT_TYPE_CAMERA;
-               inp->std = V4L2_STD_NTSC_M;
-               strcpy(inp->name,"Camera");
-               break;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               unsigned int *i = arg;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+       *i = 0;
 
-               *i = 0;
-               break;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               unsigned int *i = arg;
+       return (0);
+}
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+       if (i > 0)
+               return -EINVAL;
 
-               if (*i > 0)
-                       ret=-EINVAL;
-               break;
-       }
+       return (0);
+}
 
        /* --- controls ---------------------------------------------- */
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
-               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));
-                               break;
-                       }
+static int vidioc_queryctrl (struct file *file, void *priv,
+                               struct v4l2_queryctrl *qc)
+{
+       int i;
 
-               ret=-EINVAL;
-               break;
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-               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);
+               }
 
-               for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-                       if (ctrl->id == vivi_qctrl[i].id) {
-                               ctrl->value=qctl_regs[i];
-                               break;
-                       }
+       return -EINVAL;
+}
 
-               ret=-EINVAL;
-               break;
-       }
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-               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) {
-                                               ret=-ERANGE;
-                                               break;
-                                       }
-                               qctl_regs[i]=ctrl->value;
-                               break;
-                       }
-               ret=-EINVAL;
-               break;
-       }
-       default:
-               ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,vivi_do_ioctl);
-       }
+static int vidioc_g_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       int i;
 
-       if (debug) {
-               if (ret<0) {
-                       v4l_print_ioctl("vivi(err)", cmd);
-                       dprintk(1,"errcode=%d\n",ret);
-               } else if (_IOC_DIR(cmd) & _IOC_READ)
-                       v4l_printk_ioctl_arg("vivi(r)",cmd, arg);
-       }
+       for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+               if (ctrl->id == vivi_qctrl[i].id) {
+                       ctrl->value=qctl_regs[i];
+                       return (0);
+               }
 
-       return ret;
+       return -EINVAL;
 }
-
-static int vivi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int vidioc_s_ctrl (struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
 {
-       return video_usercopy(inode, file, cmd, arg, vivi_do_ioctl);
+       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);
+                               }
+                       qctl_regs[i]=ctrl->value;
+                       return (0);
+               }
+       return -EINVAL;
 }
 
 /* ------------------------------------------------------------------
@@ -1255,7 +1057,7 @@ static int vivi_open(struct inode *inode, struct file *file)
 
        list_for_each(list,&vivi_devlist) {
                h = list_entry(list, struct vivi_dev, vivi_devlist);
-               if (h->video_dev.minor == minor) {
+               if (h->vfd.minor == minor) {
                        dev  = h;
                        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                }
@@ -1264,6 +1066,7 @@ static int vivi_open(struct inode *inode, struct file *file)
                return -ENODEV;
 
 
+
        /* If more than one user, mutex should be added */
        dev->users++;
 
@@ -1279,6 +1082,7 @@ static int vivi_open(struct inode *inode, struct file *file)
 
        file->private_data = fh;
        fh->dev      = dev;
+
        fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fh->fmt      = &format;
        fh->width    = 640;
@@ -1314,12 +1118,12 @@ static int vivi_open(struct inode *inode, struct file *file)
 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_fh        *fh = file->private_data;
 
        if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                if (res_locked(fh->dev))
                        return -EBUSY;
-               return videobuf_read_one(&fh->vb_vidq, data, count, ppos,
+               return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
                                        file->f_flags & O_NONBLOCK);
        }
        return 0;
@@ -1328,8 +1132,8 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
-       struct vivi_fh *fh = file->private_data;
-       struct vivi_buffer *buf;
+       struct vivi_fh        *fh = file->private_data;
+       struct vivi_buffer    *buf;
 
        dprintk(1,"%s\n",__FUNCTION__);
 
@@ -1358,8 +1162,8 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
 
 static int vivi_release(struct inode *inode, struct file *file)
 {
-       struct vivi_fh  *fh     = file->private_data;
-       struct vivi_dev *dev    = fh->dev;
+       struct vivi_fh         *fh = file->private_data;
+       struct vivi_dev *dev       = fh->dev;
        struct vivi_dmaqueue *vidq = &dev->vidq;
 
        int minor = iminor(inode);
@@ -1379,7 +1183,7 @@ static int vivi_release(struct inode *inode, struct file *file)
 static int
 vivi_mmap(struct file *file, struct vm_area_struct * vma)
 {
-       struct vivi_fh *fh = file->private_data;
+       struct vivi_fh        *fh = file->private_data;
        int ret;
 
        dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
@@ -1394,26 +1198,50 @@ vivi_mmap(struct file *file, struct vm_area_struct * vma)
        return ret;
 }
 
-static struct file_operations vivi_fops = {
+static const struct file_operations vivi_fops = {
        .owner          = THIS_MODULE,
        .open           = vivi_open,
        .release        = vivi_release,
        .read           = vivi_read,
        .poll           = vivi_poll,
-       .ioctl          = vivi_ioctl,
+       .ioctl          = video_ioctl2, /* V4L2 ioctl handler */
        .mmap           = vivi_mmap,
        .llseek         = no_llseek,
 };
 
 static struct video_device vivi = {
-       .name           = "VTM Virtual Video Capture Board",
+       .name           = "vivi",
        .type           = VID_TYPE_CAPTURE,
        .hardware       = 0,
        .fops           = &vivi_fops,
        .minor          = -1,
 //     .release        = video_device_release,
+
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
+       .vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
+       .vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
+       .vidioc_s_fmt_cap     = vidioc_s_fmt_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
+       .tvnorms              = V4L2_STD_NTSC_M,
+       .current_norm         = V4L2_STD_NTSC_M,
 };
-/* ------------------------------------------------------------------
+/* -----------------------------------------------------------------
        Initialization and module stuff
    ------------------------------------------------------------------*/
 
@@ -1430,9 +1258,10 @@ static int __init vivi_init(void)
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
        INIT_LIST_HEAD(&dev->vidq.queued);
+       init_waitqueue_head(&dev->vidq.wq);
 
        /* initialize locks */
-       init_MUTEX(&dev->lock);
+       mutex_init(&dev->lock);
 
        dev->vidq.timeout.function = vivi_vid_timeout;
        dev->vidq.timeout.data     = (unsigned long)dev;
@@ -1448,7 +1277,9 @@ static void __exit vivi_exit(void)
        struct vivi_dev *h;
        struct list_head *list;
 
-       list_for_each(list,&vivi_devlist) {
+       while (!list_empty(&vivi_devlist)) {
+               list = vivi_devlist.next;
+               list_del(list);
                h = list_entry(list, struct vivi_dev, vivi_devlist);
                kfree (h);
        }
@@ -1457,3 +1288,16 @@ static void __exit vivi_exit(void)
 
 module_init(vivi_init);
 module_exit(vivi_exit);
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+
+module_param(video_nr, int, 0);
+
+module_param_named(debug,vivi.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
+
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+