Fix common misspellings
[linux-2.6.git] / drivers / media / video / au0828 / au0828-video.c
index ce80882..c03eb29 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/suspend.h>
 #include <linux/version.h>
-#include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-chip-ident.h>
 #include "au0828.h"
 #include "au0828-reg.h"
 
-static LIST_HEAD(au0828_devlist);
 static DEFINE_MUTEX(au0828_sysfs_lock);
 
 #define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1)
 
-/* Forward declarations */
-void au0828_analog_stream_reset(struct au0828_dev *dev);
-
 /* ------------------------------------------------------------------
        Videobuf operations
    ------------------------------------------------------------------*/
@@ -107,12 +103,12 @@ static inline void print_err_status(struct au0828_dev *dev,
 static int check_dev(struct au0828_dev *dev)
 {
        if (dev->dev_state & DEV_DISCONNECTED) {
-               printk("v4l2 ioctl: device not present\n");
+               printk(KERN_INFO "v4l2 ioctl: device not present\n");
                return -ENODEV;
        }
 
        if (dev->dev_state & DEV_MISCONFIGURED) {
-               printk("v4l2 ioctl: device is misconfigured; "
+               printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
                       "close and open it again\n");
                return -EIO;
        }
@@ -126,6 +122,7 @@ static void au0828_irq_callback(struct urb *urb)
 {
        struct au0828_dmaqueue  *dma_q = urb->context;
        struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+       unsigned long flags = 0;
        int rc, i;
 
        switch (urb->status) {
@@ -143,9 +140,9 @@ static void au0828_irq_callback(struct urb *urb)
        }
 
        /* Copy data from URB */
-       spin_lock(&dev->slock);
+       spin_lock_irqsave(&dev->slock, flags);
        rc = dev->isoc_ctl.isoc_copy(dev, urb);
-       spin_unlock(&dev->slock);
+       spin_unlock_irqrestore(&dev->slock, flags);
 
        /* Reset urb buffers */
        for (i = 0; i < urb->number_of_packets; i++) {
@@ -181,7 +178,7 @@ void au0828_uninit_isoc(struct au0828_dev *dev)
                                usb_unlink_urb(urb);
 
                        if (dev->isoc_ctl.transfer_buffer[i]) {
-                               usb_buffer_free(dev->usbdev,
+                               usb_free_coherent(dev->usbdev,
                                        urb->transfer_buffer_length,
                                        dev->isoc_ctl.transfer_buffer[i],
                                        urb->transfer_dma);
@@ -251,7 +248,7 @@ int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
                }
                dev->isoc_ctl.urb[i] = urb;
 
-               dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->usbdev,
+               dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev,
                        sb_size, GFP_KERNEL, &urb->transfer_dma);
                if (!dev->isoc_ctl.transfer_buffer[i]) {
                        printk("unable to allocate %i bytes for transfer"
@@ -271,7 +268,7 @@ int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
                                 au0828_irq_callback, dma_q, 1);
 
                urb->number_of_packets = max_packets;
-               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 
                k = 0;
                for (j = 0; j < max_packets; j++) {
@@ -318,6 +315,23 @@ static inline void buffer_filled(struct au0828_dev *dev,
        wake_up(&buf->vb.done);
 }
 
+static inline void vbi_buffer_filled(struct au0828_dev *dev,
+                                    struct au0828_dmaqueue *dma_q,
+                                    struct au0828_buffer *buf)
+{
+       /* Advice that buffer was filled */
+       au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+       buf->vb.state = VIDEOBUF_DONE;
+       buf->vb.field_count++;
+       do_gettimeofday(&buf->vb.ts);
+
+       dev->isoc_ctl.vbi_buf = NULL;
+
+       list_del(&buf->vb.queue);
+       wake_up(&buf->vb.done);
+}
+
 /*
  * Identify the buffer header type and properly handles
  */
@@ -331,6 +345,9 @@ static void au0828_copy_video(struct au0828_dev *dev,
        int  linesdone, currlinedone, offset, lencopy, remain;
        int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
 
+       if (len == 0)
+               return;
+
        if (dma_q->pos + len > buf->vb.size)
                len = buf->vb.size - dma_q->pos;
 
@@ -373,7 +390,7 @@ static void au0828_copy_video(struct au0828_dev *dev,
 
                if ((char *)startwrite + lencopy > (char *)outp +
                    buf->vb.size) {
-                       au0828_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
+                       au0828_isocdbg("Overflow %zi bytes past buf end (2)\n",
                                       ((char *)startwrite + lencopy) -
                                       ((char *)outp + buf->vb.size));
                        lencopy = remain = (char *)outp + buf->vb.size -
@@ -389,9 +406,8 @@ static void au0828_copy_video(struct au0828_dev *dev,
 
        if (offset > 1440) {
                /* We have enough data to check for greenscreen */
-               if (outp[0] < 0x60 && outp[1440] < 0x60) {
+               if (outp[0] < 0x60 && outp[1440] < 0x60)
                        dev->greenscreen_detected = 1;
-               }
        }
 
        dma_q->pos += len;
@@ -419,17 +435,98 @@ static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
        return;
 }
 
+static void au0828_copy_vbi(struct au0828_dev *dev,
+                             struct au0828_dmaqueue  *dma_q,
+                             struct au0828_buffer *buf,
+                             unsigned char *p,
+                             unsigned char *outp, unsigned long len)
+{
+       unsigned char *startwrite, *startread;
+       int bytesperline;
+       int i, j = 0;
+
+       if (dev == NULL) {
+               au0828_isocdbg("dev is null\n");
+               return;
+       }
+
+       if (dma_q == NULL) {
+               au0828_isocdbg("dma_q is null\n");
+               return;
+       }
+       if (buf == NULL)
+               return;
+       if (p == NULL) {
+               au0828_isocdbg("p is null\n");
+               return;
+       }
+       if (outp == NULL) {
+               au0828_isocdbg("outp is null\n");
+               return;
+       }
+
+       bytesperline = dev->vbi_width;
+
+       if (dma_q->pos + len > buf->vb.size)
+               len = buf->vb.size - dma_q->pos;
+
+       startread = p;
+       startwrite = outp + (dma_q->pos / 2);
+
+       /* Make sure the bottom field populates the second half of the frame */
+       if (buf->top_field == 0)
+               startwrite += bytesperline * dev->vbi_height;
+
+       for (i = 0; i < len; i += 2)
+               startwrite[j++] = startread[i+1];
+
+       dma_q->pos += len;
+}
+
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
+                                   struct au0828_buffer **buf)
+{
+       struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
+       char *outp;
+
+       if (list_empty(&dma_q->active)) {
+               au0828_isocdbg("No active queue to serve\n");
+               dev->isoc_ctl.vbi_buf = NULL;
+               *buf = NULL;
+               return;
+       }
+
+       /* Get the next buffer */
+       *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+       /* Cleans up buffer - Useful for testing for frame/URB loss */
+       outp = videobuf_to_vmalloc(&(*buf)->vb);
+       memset(outp, 0x00, (*buf)->vb.size);
+
+       dev->isoc_ctl.vbi_buf = *buf;
+
+       return;
+}
+
 /*
  * Controls the isoc copy of each urb packet
  */
 static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
 {
        struct au0828_buffer    *buf;
+       struct au0828_buffer    *vbi_buf;
        struct au0828_dmaqueue  *dma_q = urb->context;
+       struct au0828_dmaqueue  *vbi_dma_q = &dev->vbiq;
        unsigned char *outp = NULL;
+       unsigned char *vbioutp = NULL;
        int i, len = 0, rc = 1;
        unsigned char *p;
        unsigned char fbyte;
+       unsigned int vbi_field_size;
+       unsigned int remain, lencopy;
 
        if (!dev)
                return 0;
@@ -448,6 +545,10 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
        if (buf != NULL)
                outp = videobuf_to_vmalloc(&buf->vb);
 
+       vbi_buf = dev->isoc_ctl.vbi_buf;
+       if (vbi_buf != NULL)
+               vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
        for (i = 0; i < urb->number_of_packets; i++) {
                int status = urb->iso_frame_desc[i].status;
 
@@ -457,9 +558,9 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
                                continue;
                }
 
-               if (urb->iso_frame_desc[i].actual_length <= 0) {
+               if (urb->iso_frame_desc[i].actual_length <= 0)
                        continue;
-               }
+
                if (urb->iso_frame_desc[i].actual_length >
                                                dev->max_pkt_size) {
                        au0828_isocdbg("packet bigger than packet size");
@@ -476,29 +577,76 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
                        p += 4;
                        au0828_isocdbg("Video frame %s\n",
                                       (fbyte & 0x40) ? "odd" : "even");
-                       if (!(fbyte & 0x40)) {
+                       if (fbyte & 0x40) {
+                               /* VBI */
+                               if (vbi_buf != NULL)
+                                       vbi_buffer_filled(dev,
+                                                         vbi_dma_q,
+                                                         vbi_buf);
+                               vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+                               if (vbi_buf == NULL)
+                                       vbioutp = NULL;
+                               else
+                                       vbioutp = videobuf_to_vmalloc(
+                                               &vbi_buf->vb);
+
+                               /* Video */
                                if (buf != NULL)
                                        buffer_filled(dev, dma_q, buf);
                                get_next_buf(dma_q, &buf);
-                               if (buf == NULL) {
+                               if (buf == NULL)
                                        outp = NULL;
-                               } else
+                               else
                                        outp = videobuf_to_vmalloc(&buf->vb);
+
+                               /* As long as isoc traffic is arriving, keep
+                                  resetting the timer */
+                               if (dev->vid_timeout_running)
+                                       mod_timer(&dev->vid_timeout,
+                                                 jiffies + (HZ / 10));
+                               if (dev->vbi_timeout_running)
+                                       mod_timer(&dev->vbi_timeout,
+                                                 jiffies + (HZ / 10));
                        }
 
                        if (buf != NULL) {
-                               if (fbyte & 0x40) {
+                               if (fbyte & 0x40)
                                        buf->top_field = 1;
-                               } else {
+                               else
                                        buf->top_field = 0;
-                               }
                        }
 
+                       if (vbi_buf != NULL) {
+                               if (fbyte & 0x40)
+                                       vbi_buf->top_field = 1;
+                               else
+                                       vbi_buf->top_field = 0;
+                       }
+
+                       dev->vbi_read = 0;
+                       vbi_dma_q->pos = 0;
                        dma_q->pos = 0;
                }
-               if (buf != NULL) {
-                       au0828_copy_video(dev, dma_q, buf, p, outp, len);
+
+               vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
+               if (dev->vbi_read < vbi_field_size) {
+                       remain  = vbi_field_size - dev->vbi_read;
+                       if (len < remain)
+                               lencopy = len;
+                       else
+                               lencopy = remain;
+
+                       if (vbi_buf != NULL)
+                               au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+                                               vbioutp, len);
+
+                       len -= lencopy;
+                       p += lencopy;
+                       dev->vbi_read += lencopy;
                }
+
+               if (dev->vbi_read >= vbi_field_size && buf != NULL)
+                       au0828_copy_video(dev, dma_q, buf, p, outp, len);
        }
        return rc;
 }
@@ -566,7 +714,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
        if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
                rc = videobuf_iolock(vq, &buf->vb, NULL);
                if (rc < 0) {
-                       printk("videobuf_iolock failed\n");
+                       printk(KERN_INFO "videobuf_iolock failed\n");
                        goto fail;
                }
        }
@@ -579,7 +727,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                                      AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
                                      au0828_isoc_copy);
                if (rc < 0) {
-                       printk("au0828_init_isoc failed\n");
+                       printk(KERN_INFO "au0828_init_isoc failed\n");
                        goto fail;
                }
        }
@@ -649,7 +797,7 @@ int au0828_analog_stream_enable(struct au0828_dev *d)
        au0828_writereg(d, 0x114, 0xa0);
        au0828_writereg(d, 0x115, 0x05);
        /* set y position */
-       au0828_writereg(d, 0x112, 0x02);
+       au0828_writereg(d, 0x112, 0x00);
        au0828_writereg(d, 0x113, 0x00);
        au0828_writereg(d, 0x116, 0xf2);
        au0828_writereg(d, 0x117, 0x00);
@@ -681,11 +829,11 @@ static int au0828_stream_interrupt(struct au0828_dev *dev)
        int ret = 0;
 
        dev->stream_state = STREAM_INTERRUPT;
-       if(dev->dev_state == DEV_DISCONNECTED)
+       if (dev->dev_state == DEV_DISCONNECTED)
                return -ENODEV;
-       else if(ret) {
+       else if (ret) {
                dev->dev_state = DEV_MISCONFIGURED;
-               dprintk(1, "%s device is misconfigured!\n", __FUNCTION__);
+               dprintk(1, "%s device is misconfigured!\n", __func__);
                return ret;
        }
        return 0;
@@ -700,7 +848,6 @@ void au0828_analog_unregister(struct au0828_dev *dev)
        dprintk(1, "au0828_release_resources called\n");
        mutex_lock(&au0828_sysfs_lock);
 
-       list_del(&dev->au0828list);
        if (dev->vdev)
                video_unregister_device(dev->vdev);
        if (dev->vbi_dev)
@@ -711,64 +858,137 @@ void au0828_analog_unregister(struct au0828_dev *dev)
 
 
 /* Usage lock check functions */
-static int res_get(struct au0828_fh *fh)
+static int res_get(struct au0828_fh *fh, unsigned int bit)
 {
-       struct au0828_dev *dev = fh->dev;
-       int              rc   = 0;
+       struct au0828_dev    *dev = fh->dev;
 
-       /* This instance already has stream_on */
-       if (fh->stream_on)
-               return rc;
+       if (fh->resources & bit)
+               /* have it already allocated */
+               return 1;
 
-       if (dev->stream_on)
-               return -EBUSY;
+       /* is it free? */
+       mutex_lock(&dev->lock);
+       if (dev->resources & bit) {
+               /* no, someone else uses it */
+               mutex_unlock(&dev->lock);
+               return 0;
+       }
+       /* it's free, grab it */
+       fh->resources  |= bit;
+       dev->resources |= bit;
+       dprintk(1, "res: get %d\n", bit);
+       mutex_unlock(&dev->lock);
+       return 1;
+}
 
-       dev->stream_on = 1;
-       fh->stream_on  = 1;
-       return rc;
+static int res_check(struct au0828_fh *fh, unsigned int bit)
+{
+       return fh->resources & bit;
 }
 
-static int res_check(struct au0828_fh *fh)
+static int res_locked(struct au0828_dev *dev, unsigned int bit)
 {
-       return fh->stream_on;
+       return dev->resources & bit;
 }
 
-static void res_free(struct au0828_fh *fh)
+static void res_free(struct au0828_fh *fh, unsigned int bits)
 {
-       struct au0828_dev *dev = fh->dev;
+       struct au0828_dev    *dev = fh->dev;
+
+       BUG_ON((fh->resources & bits) != bits);
 
-       fh->stream_on = 0;
-       dev->stream_on = 0;
+       mutex_lock(&dev->lock);
+       fh->resources  &= ~bits;
+       dev->resources &= ~bits;
+       dprintk(1, "res: put %d\n", bits);
+       mutex_unlock(&dev->lock);
 }
 
+static int get_ressource(struct au0828_fh *fh)
+{
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return AU0828_RESOURCE_VIDEO;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               return AU0828_RESOURCE_VBI;
+       default:
+               BUG();
+               return 0;
+       }
+}
+
+/* This function ensures that video frames continue to be delivered even if
+   the ITU-656 input isn't receiving any data (thereby preventing applications
+   such as tvtime from hanging) */
+void au0828_vid_buffer_timeout(unsigned long data)
+{
+       struct au0828_dev *dev = (struct au0828_dev *) data;
+       struct au0828_dmaqueue *dma_q = &dev->vidq;
+       struct au0828_buffer *buf;
+       unsigned char *vid_data;
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&dev->slock, flags);
+
+       buf = dev->isoc_ctl.buf;
+       if (buf != NULL) {
+               vid_data = videobuf_to_vmalloc(&buf->vb);
+               memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */
+               buffer_filled(dev, dma_q, buf);
+       }
+       get_next_buf(dma_q, &buf);
+
+       if (dev->vid_timeout_running == 1)
+               mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+void au0828_vbi_buffer_timeout(unsigned long data)
+{
+       struct au0828_dev *dev = (struct au0828_dev *) data;
+       struct au0828_dmaqueue *dma_q = &dev->vbiq;
+       struct au0828_buffer *buf;
+       unsigned char *vbi_data;
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&dev->slock, flags);
+
+       buf = dev->isoc_ctl.vbi_buf;
+       if (buf != NULL) {
+               vbi_data = videobuf_to_vmalloc(&buf->vb);
+               memset(vbi_data, 0x00, buf->vb.size);
+               vbi_buffer_filled(dev, dma_q, buf);
+       }
+       vbi_get_next_buf(dma_q, &buf);
+
+       if (dev->vbi_timeout_running == 1)
+               mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
 static int au0828_v4l2_open(struct file *filp)
 {
-       int minor = video_devdata(filp)->minor;
        int ret = 0;
-       struct au0828_dev *h, *dev = NULL;
+       struct video_device *vdev = video_devdata(filp);
+       struct au0828_dev *dev = video_drvdata(filp);
        struct au0828_fh *fh;
-       int type = 0;
-       struct list_head *list;
-
-       list_for_each(list, &au0828_devlist) {
-               h = list_entry(list, struct au0828_dev, au0828list);
-               if(h->vdev->minor == minor) {
-                       dev = h;
-                       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               }
-#ifdef VBI_NOT_YET_WORKING
-               if(h->vbi_dev->minor == minor) {
-                       dev = h;
-                       type = V4L2_BUF_TYPE_VBI_CAPTURE;
-               }
-#endif
-       }
+       int type;
 
-       if(NULL == dev)
-               return -ENODEV;
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
+               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               break;
+       case VFL_TYPE_VBI:
+               type = V4L2_BUF_TYPE_VBI_CAPTURE;
+               break;
+       default:
+               return -EINVAL;
+       }
 
        fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
-       if(NULL == fh) {
+       if (NULL == fh) {
                dprintk(1, "Failed allocate au0828_fh struct!\n");
                return -ENOMEM;
        }
@@ -777,11 +997,11 @@ static int au0828_v4l2_open(struct file *filp)
        fh->dev = dev;
        filp->private_data = fh;
 
-       if(fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
                /* set au0828 interface0 to AS5 here again */
                ret = usb_set_interface(dev->usbdev, 0, 5);
-               if(ret < 0) {
-                       printk("Au0828 can't set alt setting to 5!\n");
+               if (ret < 0) {
+                       printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
                        return -EBUSY;
                }
                dev->width = NTSC_STD_W;
@@ -803,9 +1023,19 @@ static int au0828_v4l2_open(struct file *filp)
        dev->users++;
 
        videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
-                                   NULL, &dev->slock, fh->type,
+                                   NULL, &dev->slock,
+                                   V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    V4L2_FIELD_INTERLACED,
-                                   sizeof(struct au0828_buffer), fh);
+                                   sizeof(struct au0828_buffer), fh, NULL);
+
+       /* VBI Setup */
+       dev->vbi_width = 720;
+       dev->vbi_height = 1;
+       videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
+                                   NULL, &dev->slock,
+                                   V4L2_BUF_TYPE_VBI_CAPTURE,
+                                   V4L2_FIELD_SEQ_TB,
+                                   sizeof(struct au0828_buffer), fh, NULL);
 
        return ret;
 }
@@ -816,17 +1046,27 @@ static int au0828_v4l2_close(struct file *filp)
        struct au0828_fh *fh = filp->private_data;
        struct au0828_dev *dev = fh->dev;
 
-       mutex_lock(&dev->lock);
-       if (res_check(fh))
-               res_free(fh);
+       if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+               /* Cancel timeout thread in case they didn't call streamoff */
+               dev->vid_timeout_running = 0;
+               del_timer_sync(&dev->vid_timeout);
 
-       if(dev->users == 1) {
                videobuf_stop(&fh->vb_vidq);
-               videobuf_mmap_free(&fh->vb_vidq);
+               res_free(fh, AU0828_RESOURCE_VIDEO);
+       }
 
-               if(dev->dev_state & DEV_DISCONNECTED) {
+       if (res_check(fh, AU0828_RESOURCE_VBI)) {
+               /* Cancel timeout thread in case they didn't call streamoff */
+               dev->vbi_timeout_running = 0;
+               del_timer_sync(&dev->vbi_timeout);
+
+               videobuf_stop(&fh->vb_vbiq);
+               res_free(fh, AU0828_RESOURCE_VBI);
+       }
+
+       if (dev->users == 1) {
+               if (dev->dev_state & DEV_DISCONNECTED) {
                        au0828_analog_unregister(dev);
-                       mutex_unlock(&dev->lock);
                        kfree(dev);
                        return 0;
                }
@@ -835,17 +1075,21 @@ static int au0828_v4l2_close(struct file *filp)
 
                au0828_uninit_isoc(dev);
 
+               /* Save some power by putting tuner to sleep */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
                /* When close the device, set the usb intf0 into alt0 to free
                   USB bandwidth */
                ret = usb_set_interface(dev->usbdev, 0, 0);
-               if(ret < 0)
-                       printk("Au0828 can't set alt setting to 0!\n");
+               if (ret < 0)
+                       printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
        }
 
+       videobuf_mmap_free(&fh->vb_vidq);
+       videobuf_mmap_free(&fh->vb_vbiq);
        kfree(fh);
        dev->users--;
        wake_up_interruptible_nr(&dev->open, 1);
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -860,17 +1104,29 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
        if (rc < 0)
                return rc;
 
-       if(fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               mutex_lock(&dev->lock);
-               rc = res_get(fh);
-               mutex_unlock(&dev->lock);
-
-               if (unlikely(rc < 0))
-                       return rc;
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (res_locked(dev, AU0828_RESOURCE_VIDEO))
+                       return -EBUSY;
 
                return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
                                        filp->f_flags & O_NONBLOCK);
        }
+
+       if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               if (!res_get(fh, AU0828_RESOURCE_VBI))
+                       return -EBUSY;
+
+               if (dev->vbi_timeout_running == 0) {
+                       /* Handle case where caller tries to read without
+                          calling streamon first */
+                       dev->vbi_timeout_running = 1;
+                       mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+               }
+
+               return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+                                           filp->f_flags & O_NONBLOCK);
+       }
+
        return 0;
 }
 
@@ -884,17 +1140,17 @@ static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-       rc = res_get(fh);
-       mutex_unlock(&dev->lock);
-
-       if (unlikely(rc < 0))
-               return POLLERR;
-
-       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (!res_get(fh, AU0828_RESOURCE_VIDEO))
+                       return POLLERR;
+               return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+       } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               if (!res_get(fh, AU0828_RESOURCE_VBI))
+                       return POLLERR;
+               return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+       } else {
                return POLLERR;
-
-       return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+       }
 }
 
 static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -907,19 +1163,10 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-       rc = res_get(fh);
-       mutex_unlock(&dev->lock);
-
-       if (unlikely(rc < 0))
-               return rc;
-
-       rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
-
-       dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n",
-               (unsigned long)vma->vm_start,
-               (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
-               rc);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
 
        return rc;
 }
@@ -930,34 +1177,19 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
        int ret;
        int width = format->fmt.pix.width;
        int height = format->fmt.pix.height;
-       unsigned int maxwidth, maxheight;
-
-       maxwidth = 720;
-       maxheight = 480;
 
-#ifdef VBI_NOT_YET_WORKING
-       if(format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-               dprintk(1, "VBI format set: to be supported!\n");
-               return 0;
-       }
-       if(format->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-               return 0;
-       }
-#endif
-       if(format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+       if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       }
 
        /* If they are demanding a format other than the one we support,
           bail out (tvtime asks for UYVY and then retries with YUYV) */
-       if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY) {
+       if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
                return -EINVAL;
-       }
 
        /* format->fmt.pix.width only support 720 and height 480 */
-       if(width != 720)
+       if (width != 720)
                width = 720;
-       if(height != 480)
+       if (height != 480)
                height = 480;
 
        format->fmt.pix.width = width;
@@ -968,7 +1200,7 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
        format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
        format->fmt.pix.field = V4L2_FIELD_INTERLACED;
 
-       if(cmd == VIDIOC_TRY_FMT)
+       if (cmd == VIDIOC_TRY_FMT)
                return 0;
 
        /* maybe set new image format, driver current only support 720*480 */
@@ -978,9 +1210,10 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
        dev->field_size = width * height;
        dev->bytesperline = width * 2;
 
-       if(dev->stream_state == STREAM_ON) {
+       if (dev->stream_state == STREAM_ON) {
                dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n");
-               if((ret = au0828_stream_interrupt(dev))) {
+               ret = au0828_stream_interrupt(dev);
+               if (ret != 0) {
                        dprintk(1, "error interrupting video stream!\n");
                        return ret;
                }
@@ -988,8 +1221,8 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
 
        /* set au0828 interface0 to AS5 here again */
        ret = usb_set_interface(dev->usbdev, 0, 5);
-       if(ret < 0) {
-               printk("Au0828 can't set alt setting to 5!\n");
+       if (ret < 0) {
+               printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
                return -EBUSY;
        }
 
@@ -1004,7 +1237,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 {
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
-       au0828_call_i2c_clients(dev, VIDIOC_QUERYCTRL, qc);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
        if (qc->type)
                return 0;
        else
@@ -1017,18 +1250,15 @@ static int vidioc_querycap(struct file *file, void  *priv,
        struct au0828_fh *fh  = priv;
        struct au0828_dev *dev = fh->dev;
 
-       memset(cap, 0, sizeof(*cap));
        strlcpy(cap->driver, "au0828", sizeof(cap->driver));
        strlcpy(cap->card, dev->board.name, sizeof(cap->card));
-       strlcpy(cap->bus_info, dev->usbdev->dev.bus_id, sizeof(cap->bus_info));
+       strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
 
        cap->version = AU0828_VERSION_CODE;
 
        /*set the device capabilities */
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-#ifdef VBI_NOT_YET_WORKING
                V4L2_CAP_VBI_CAPTURE |
-#endif
                V4L2_CAP_AUDIO |
                V4L2_CAP_READWRITE |
                V4L2_CAP_STREAMING |
@@ -1039,17 +1269,15 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
                                        struct v4l2_fmtdesc *f)
 {
-       if(f->index)
+       if (f->index)
                return -EINVAL;
 
-       memset(f, 0, sizeof(*f));
        f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        strcpy(f->description, "Packed YUV2");
 
        f->flags = 0;
        f->pixelformat = V4L2_PIX_FMT_UYVY;
 
-       memset(f->reserved, 0, sizeof(f->reserved));
        return 0;
 }
 
@@ -1085,20 +1313,21 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        struct au0828_dev *dev = fh->dev;
        int rc;
 
-       if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-               printk("%s queue busy\n", __func__);
-               rc = -EBUSY;
-               goto out;
-       }
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
 
-       if (dev->stream_on && !fh->stream_on) {
-               printk("%s device in use by another fh\n", __func__);
+       mutex_lock(&dev->lock);
+
+       if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+               printk(KERN_INFO "%s queue busy\n", __func__);
                rc = -EBUSY;
                goto out;
        }
 
-       return au0828_set_format(dev, VIDIOC_S_FMT, f);
+       rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
 out:
+       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -1111,7 +1340,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
           have to make the au0828 bridge adjust the size of its capture
           buffer, which is currently hardcoded at 720x480 */
 
-       au0828_call_i2c_clients(dev, VIDIOC_S_STD, norm);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
        return 0;
 }
 
@@ -1123,6 +1352,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
        unsigned int tmp;
 
        static const char *inames[] = {
+               [AU0828_VMUX_UNDEFINED] = "Undefined",
                [AU0828_VMUX_COMPOSITE] = "Composite",
                [AU0828_VMUX_SVIDEO] = "S-Video",
                [AU0828_VMUX_CABLE] = "Cable TV",
@@ -1133,16 +1363,15 @@ static int vidioc_enum_input(struct file *file, void *priv,
 
        tmp = input->index;
 
-       if(tmp > AU0828_MAX_INPUT)
+       if (tmp >= AU0828_MAX_INPUT)
                return -EINVAL;
-       if(AUVI_INPUT(tmp).type == 0)
+       if (AUVI_INPUT(tmp).type == 0)
                return -EINVAL;
 
-       memset(input, 0, sizeof(*input));
        input->index = tmp;
        strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
-       if((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
-          (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
+       if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
+           (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
                input->type |= V4L2_INPUT_TYPE_TUNER;
        else
                input->type |= V4L2_INPUT_TYPE_CAMERA;
@@ -1165,45 +1394,38 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
        int i;
-       struct v4l2_routing route;
 
-       dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __FUNCTION__,
+       dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
                index);
-       if(index >= AU0828_MAX_INPUT)
+       if (index >= AU0828_MAX_INPUT)
                return -EINVAL;
-       if(AUVI_INPUT(index).type == 0)
+       if (AUVI_INPUT(index).type == 0)
                return -EINVAL;
        dev->ctrl_input = index;
 
-       switch(AUVI_INPUT(index).type) {
+       switch (AUVI_INPUT(index).type) {
        case AU0828_VMUX_SVIDEO:
-       {
                dev->input_type = AU0828_VMUX_SVIDEO;
                break;
-       }
        case AU0828_VMUX_COMPOSITE:
-       {
                dev->input_type = AU0828_VMUX_COMPOSITE;
                break;
-       }
        case AU0828_VMUX_TELEVISION:
-       {
                dev->input_type = AU0828_VMUX_TELEVISION;
                break;
-       }
        default:
-               ;
+               dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
+                       AUVI_INPUT(index).type);
+               break;
        }
 
-       route.input = AUVI_INPUT(index).vmux;
-       route.output = 0;
-       au0828_call_i2c_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+                       AUVI_INPUT(index).vmux, 0, 0);
 
        for (i = 0; i < AU0828_MAX_INPUT; i++) {
                int enable = 0;
-               if (AUVI_INPUT(i).audio_setup == NULL) {
+               if (AUVI_INPUT(i).audio_setup == NULL)
                        continue;
-               }
 
                if (i == index)
                        enable = 1;
@@ -1221,9 +1443,8 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
                }
        }
 
-       route.input = AUVI_INPUT(index).amux;
-       au0828_call_i2c_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
-                               &route);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+                       AUVI_INPUT(index).amux, 0, 0);
        return 0;
 }
 
@@ -1233,12 +1454,11 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
        struct au0828_dev *dev = fh->dev;
        unsigned int index = a->index;
 
-       if(a->index > 1)
+       if (a->index > 1)
                return -EINVAL;
 
-       memset(a, 0, sizeof(*a));
        index = dev->ctrl_ainput;
-       if(index == 0)
+       if (index == 0)
                strcpy(a->name, "Television");
        else
                strcpy(a->name, "Line in");
@@ -1252,7 +1472,7 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
-       if(a->index != dev->ctrl_ainput)
+       if (a->index != dev->ctrl_ainput)
                return -EINVAL;
        return 0;
 }
@@ -1263,7 +1483,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
 
-       au0828_call_i2c_clients(dev, VIDIOC_G_CTRL, ctrl);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
        return 0;
 
 }
@@ -1273,7 +1493,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 {
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
-       au0828_call_i2c_clients(dev, VIDIOC_S_CTRL, ctrl);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
        return 0;
 }
 
@@ -1282,13 +1502,11 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
 
-       if(t->index != 0)
+       if (t->index != 0)
                return -EINVAL;
 
-       memset(t, 0, sizeof(*t));
        strcpy(t->name, "Auvitek tuner");
-
-       au0828_call_i2c_clients(dev, VIDIOC_G_TUNER, t);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
        return 0;
 }
 
@@ -1298,11 +1516,11 @@ static int vidioc_s_tuner(struct file *file, void *priv,
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
 
-       if(t->index != 0)
+       if (t->index != 0)
                return -EINVAL;
 
        t->type = V4L2_TUNER_ANALOG_TV;
-       au0828_call_i2c_clients(dev, VIDIOC_S_TUNER, t);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
        dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
                t->afc);
        return 0;
@@ -1314,7 +1532,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
-       memset(freq, 0, sizeof(*freq));
+
        freq->type = V4L2_TUNER_ANALOG_TV;
        freq->frequency = dev->ctrl_freq;
        return 0;
@@ -1326,20 +1544,43 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
 
-       if(freq->tuner != 0)
+       if (freq->tuner != 0)
                return -EINVAL;
-       if(freq->type != V4L2_TUNER_ANALOG_TV)
+       if (freq->type != V4L2_TUNER_ANALOG_TV)
                return -EINVAL;
 
        dev->ctrl_freq = freq->frequency;
 
-       au0828_call_i2c_clients(dev, VIDIOC_S_FREQUENCY, freq);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
 
        au0828_analog_stream_reset(dev);
 
        return 0;
 }
 
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+                               struct v4l2_format *format)
+{
+       struct au0828_fh      *fh  = priv;
+       struct au0828_dev     *dev = fh->dev;
+
+       format->fmt.vbi.samples_per_line = dev->vbi_width;
+       format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+       format->fmt.vbi.offset = 0;
+       format->fmt.vbi.flags = 0;
+       format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+
+       format->fmt.vbi.count[0] = dev->vbi_height;
+       format->fmt.vbi.count[1] = dev->vbi_height;
+       format->fmt.vbi.start[0] = 21;
+       format->fmt.vbi.start[1] = 284;
+
+       return 0;
+}
+
 static int vidioc_g_chip_ident(struct file *file, void *priv,
               struct v4l2_dbg_chip_ident *chip)
 {
@@ -1353,7 +1594,7 @@ static int vidioc_g_chip_ident(struct file *file, void *priv,
                return 0;
        }
 
-       au0828_call_i2c_clients(dev, VIDIOC_DBG_G_CHIP_IDENT, chip);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
        if (chip->ident == V4L2_IDENT_NONE)
                return -EINVAL;
 
@@ -1366,7 +1607,7 @@ static int vidioc_cropcap(struct file *file, void *priv,
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
 
-       if(cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
        cc->bounds.left = 0;
@@ -1385,26 +1626,37 @@ static int vidioc_cropcap(struct file *file, void *priv,
 static int vidioc_streamon(struct file *file, void *priv,
                           enum v4l2_buf_type type)
 {
-       struct au0828_fh *fh = priv;
-       struct au0828_dev *dev = fh->dev;
-       int b = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       int rc;
+       struct au0828_fh      *fh  = priv;
+       struct au0828_dev     *dev = fh->dev;
+       int                   rc = -EINVAL;
 
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
 
+       if (unlikely(type != fh->type))
+               return -EINVAL;
+
+       dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+               fh, type, fh->resources, dev->resources);
+
+       if (unlikely(!res_get(fh, get_ressource(fh))))
+               return -EBUSY;
+
        if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                au0828_analog_stream_enable(dev);
-               au0828_call_i2c_clients(dev, VIDIOC_STREAMON, &b);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
        }
 
-       mutex_lock(&dev->lock);
-       rc = res_get(fh);
-
-       if (likely(rc >= 0))
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                rc = videobuf_streamon(&fh->vb_vidq);
-       mutex_unlock(&dev->lock);
+               dev->vid_timeout_running = 1;
+               mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+       } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               rc = videobuf_streamon(&fh->vb_vbiq);
+               dev->vbi_timeout_running = 1;
+               mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+       }
 
        return rc;
 }
@@ -1412,43 +1664,53 @@ static int vidioc_streamon(struct file *file, void *priv,
 static int vidioc_streamoff(struct file *file, void *priv,
                            enum v4l2_buf_type type)
 {
-       struct au0828_fh *fh = priv;
-       struct au0828_dev *dev = fh->dev;
-       int b = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       int i;
-       int ret;
-       int rc;
+       struct au0828_fh      *fh  = priv;
+       struct au0828_dev     *dev = fh->dev;
+       int                   rc;
+       int                   i;
 
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
 
-       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
                return -EINVAL;
        if (type != fh->type)
                return -EINVAL;
 
-       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               au0828_call_i2c_clients(dev, VIDIOC_STREAMOFF, &b);
-               if((ret = au0828_stream_interrupt(dev)) != 0)
-                       return ret;
-       }
+       dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+               fh, type, fh->resources, dev->resources);
 
-       for (i = 0; i < AU0828_MAX_INPUT; i++) {
-               if (AUVI_INPUT(i).audio_setup == NULL) {
-                       continue;
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev->vid_timeout_running = 0;
+               del_timer_sync(&dev->vid_timeout);
+
+               v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+               rc = au0828_stream_interrupt(dev);
+               if (rc != 0)
+                       return rc;
+
+               for (i = 0; i < AU0828_MAX_INPUT; i++) {
+                       if (AUVI_INPUT(i).audio_setup == NULL)
+                               continue;
+                       (AUVI_INPUT(i).audio_setup)(dev, 0);
                }
-               (AUVI_INPUT(i).audio_setup)(dev, 0);
-       }
 
-       mutex_lock(&dev->lock);
-       videobuf_streamoff(&fh->vb_vidq);
-       res_free(fh);
-       mutex_unlock(&dev->lock);
+               videobuf_streamoff(&fh->vb_vidq);
+               res_free(fh, AU0828_RESOURCE_VIDEO);
+       } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               dev->vbi_timeout_running = 0;
+               del_timer_sync(&dev->vbi_timeout);
+
+               videobuf_streamoff(&fh->vb_vbiq);
+               res_free(fh, AU0828_RESOURCE_VBI);
+       }
 
        return 0;
 }
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
 static int vidioc_g_register(struct file *file, void *priv,
                             struct v4l2_dbg_register *reg)
 {
@@ -1457,7 +1719,7 @@ static int vidioc_g_register(struct file *file, void *priv,
 
        switch (reg->match.type) {
        case V4L2_CHIP_MATCH_I2C_DRIVER:
-               au0828_call_i2c_clients(dev, VIDIOC_DBG_G_REGISTER, reg);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
                return 0;
        default:
                return -EINVAL;
@@ -1472,13 +1734,14 @@ static int vidioc_s_register(struct file *file, void *priv,
 
        switch (reg->match.type) {
        case V4L2_CHIP_MATCH_I2C_DRIVER:
-               au0828_call_i2c_clients(dev, VIDIOC_DBG_S_REGISTER, reg);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
                return 0;
        default:
                return -EINVAL;
        }
        return 0;
 }
+#endif
 
 static int vidioc_reqbufs(struct file *file, void *priv,
                          struct v4l2_requestbuffers *rb)
@@ -1491,7 +1754,12 @@ static int vidioc_reqbufs(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return videobuf_reqbufs(&fh->vb_vidq, rb);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_reqbufs(&fh->vb_vidq, rb);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_reqbufs(&fh->vb_vbiq, rb);
+
+       return rc;
 }
 
 static int vidioc_querybuf(struct file *file, void *priv,
@@ -1505,7 +1773,12 @@ static int vidioc_querybuf(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return videobuf_querybuf(&fh->vb_vidq, b);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_querybuf(&fh->vb_vidq, b);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_querybuf(&fh->vb_vbiq, b);
+
+       return rc;
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1518,7 +1791,12 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
        if (rc < 0)
                return rc;
 
-       return videobuf_qbuf(&fh->vb_vidq, b);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_qbuf(&fh->vb_vidq, b);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_qbuf(&fh->vb_vbiq, b);
+
+       return rc;
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1539,17 +1817,13 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
                dev->greenscreen_detected = 0;
        }
 
-       return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
-}
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK);
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
-       struct au0828_fh *fh = priv;
-
-       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+       return rc;
 }
-#endif
 
 static struct v4l2_file_operations au0828_v4l_fops = {
        .owner      = THIS_MODULE,
@@ -1567,19 +1841,11 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .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,
-#ifdef VBI_NOT_YET_WORKING
        .vidioc_g_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
-       .vidioc_try_fmt_vbi_cap     = vidioc_s_fmt_vbi_cap,
-       .vidioc_s_fmt_vbi_cap       = vidioc_s_fmt_vbi_cap,
-#endif
+       .vidioc_s_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
        .vidioc_g_audio             = vidioc_g_audio,
        .vidioc_s_audio             = vidioc_s_audio,
        .vidioc_cropcap             = vidioc_cropcap,
-#ifdef VBI_NOT_YET_WORKING
-       .vidioc_g_fmt_sliced_vbi_cap   = vidioc_g_fmt_sliced_vbi_cap,
-       .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
-       .vidioc_s_fmt_sliced_vbi_cap   = vidioc_try_set_sliced_vbi_cap,
-#endif
        .vidioc_reqbufs             = vidioc_reqbufs,
        .vidioc_querybuf            = vidioc_querybuf,
        .vidioc_qbuf                = vidioc_qbuf,
@@ -1600,36 +1866,77 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register          = vidioc_g_register,
        .vidioc_s_register          = vidioc_s_register,
-       .vidioc_g_chip_ident        = vidioc_g_chip_ident,
-#endif
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf                = vidiocgmbuf,
 #endif
+       .vidioc_g_chip_ident        = vidioc_g_chip_ident,
 };
 
 static const struct video_device au0828_video_template = {
        .fops                       = &au0828_v4l_fops,
        .release                    = video_device_release,
        .ioctl_ops                  = &video_ioctl_ops,
-       .minor                      = -1,
        .tvnorms                    = V4L2_STD_NTSC_M,
        .current_norm               = V4L2_STD_NTSC_M,
 };
 
 /**************************************************************************/
 
-int au0828_analog_register(struct au0828_dev *dev)
+int au0828_analog_register(struct au0828_dev *dev,
+                          struct usb_interface *interface)
 {
        int retval = -ENOMEM;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       int i;
 
        dprintk(1, "au0828_analog_register called!\n");
 
+       /* set au0828 usb interface0 to as5 */
+       retval = usb_set_interface(dev->usbdev,
+                       interface->cur_altsetting->desc.bInterfaceNumber, 5);
+       if (retval != 0) {
+               printk(KERN_INFO "Failure setting usb interface0 to as5\n");
+               return retval;
+       }
+
+       /* Figure out which endpoint has the isoc interface */
+       iface_desc = interface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+               endpoint = &iface_desc->endpoint[i].desc;
+               if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                    == USB_DIR_IN) &&
+                   ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                    == USB_ENDPOINT_XFER_ISOC)) {
+
+                       /* we find our isoc in endpoint */
+                       u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
+                       dev->max_pkt_size = (tmp & 0x07ff) *
+                               (((tmp & 0x1800) >> 11) + 1);
+                       dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
+               }
+       }
+       if (!(dev->isoc_in_endpointaddr)) {
+               printk(KERN_INFO "Could not locate isoc endpoint\n");
+               kfree(dev);
+               return -ENODEV;
+       }
+
        init_waitqueue_head(&dev->open);
        spin_lock_init(&dev->slock);
        mutex_init(&dev->lock);
 
+       /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
        INIT_LIST_HEAD(&dev->vidq.queued);
+       INIT_LIST_HEAD(&dev->vbiq.active);
+       INIT_LIST_HEAD(&dev->vbiq.queued);
+
+       dev->vid_timeout.function = au0828_vid_buffer_timeout;
+       dev->vid_timeout.data = (unsigned long) dev;
+       init_timer(&dev->vid_timeout);
+
+       dev->vbi_timeout.function = au0828_vbi_buffer_timeout;
+       dev->vbi_timeout.data = (unsigned long) dev;
+       init_timer(&dev->vbi_timeout);
 
        dev->width = NTSC_STD_W;
        dev->height = NTSC_STD_H;
@@ -1640,56 +1947,51 @@ int au0828_analog_register(struct au0828_dev *dev)
 
        /* allocate and fill v4l2 video struct */
        dev->vdev = video_device_alloc();
-       if(NULL == dev->vdev) {
+       if (NULL == dev->vdev) {
                dprintk(1, "Can't allocate video_device.\n");
                return -ENOMEM;
        }
 
-#ifdef VBI_NOT_YET_WORKING
+       /* allocate the VBI struct */
        dev->vbi_dev = video_device_alloc();
-       if(NULL == dev->vbi_dev) {
+       if (NULL == dev->vbi_dev) {
                dprintk(1, "Can't allocate vbi_device.\n");
                kfree(dev->vdev);
                return -ENOMEM;
        }
-#endif
 
        /* Fill the video capture device struct */
        *dev->vdev = au0828_video_template;
-       dev->vdev->vfl_type = VID_TYPE_CAPTURE | VID_TYPE_TUNER;
        dev->vdev->parent = &dev->usbdev->dev;
        strcpy(dev->vdev->name, "au0828a video");
 
-#ifdef VBI_NOT_YET_WORKING
        /* Setup the VBI device */
        *dev->vbi_dev = au0828_video_template;
-       dev->vbi_dev->vfl_type = VFL_TYPE_VBI;
        dev->vbi_dev->parent = &dev->usbdev->dev;
        strcpy(dev->vbi_dev->name, "au0828a vbi");
-#endif
-
-       list_add_tail(&dev->au0828list, &au0828_devlist);
 
        /* Register the v4l2 device */
-       if((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1)) != 0) {
-               dprintk(1, "unable to register video device (error = %d).\n", retval);
-               list_del(&dev->au0828list);
+       video_set_drvdata(dev->vdev, dev);
+       retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
+       if (retval != 0) {
+               dprintk(1, "unable to register video device (error = %d).\n",
+                       retval);
                video_device_release(dev->vdev);
                return -ENODEV;
        }
 
-#ifdef VBI_NOT_YET_WORKING
        /* Register the vbi device */
-       if((retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1)) != 0) {
-               dprintk(1, "unable to register vbi device (error = %d).\n", retval);
-               list_del(&dev->au0828list);
+       video_set_drvdata(dev->vbi_dev, dev);
+       retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
+       if (retval != 0) {
+               dprintk(1, "unable to register vbi device (error = %d).\n",
+                       retval);
                video_device_release(dev->vbi_dev);
                video_device_release(dev->vdev);
                return -ENODEV;
        }
-#endif
 
-       dprintk(1, "%s completed!\n", __FUNCTION__);
+       dprintk(1, "%s completed!\n", __func__);
 
        return 0;
 }