include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / media / video / em28xx / em28xx-video.c
index 90aedae..0fe2011 100644 (file)
 #include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
 
 #include "em28xx.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/msp3400.h>
 #include <media/tuner.h>
 
@@ -47,9 +49,8 @@
                      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
                      "Sascha Sommer <saschasommer@freenet.de>"
 
-#define DRIVER_NAME         "em28xx"
 #define DRIVER_DESC         "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 0)
+#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 2)
 
 #define em28xx_videodbg(fmt, arg...) do {\
        if (video_debug) \
@@ -72,19 +73,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static LIST_HEAD(em28xx_devlist);
-static DEFINE_MUTEX(em28xx_devlist_mutex);
-
-static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 
-module_param_array(card,  int, NULL, 0444);
 module_param_array(video_nr, int, NULL, 0444);
 module_param_array(vbi_nr, int, NULL, 0444);
 module_param_array(radio_nr, int, NULL, 0444);
-MODULE_PARM_DESC(card,     "card type");
 MODULE_PARM_DESC(video_nr, "video device numbers");
 MODULE_PARM_DESC(vbi_nr,   "vbi device numbers");
 MODULE_PARM_DESC(radio_nr, "radio device numbers");
@@ -93,12 +88,44 @@ static unsigned int video_debug;
 module_param(video_debug, int, 0644);
 MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
 
-/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
-static unsigned long em28xx_devused;
+/* supported video standards */
+static struct em28xx_fmt format[] = {
+       {
+               .name     = "16 bpp YUY2, 4:2:2, packed",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+               .reg      = EM28XX_OUTFMT_YUV422_Y0UY1V,
+       }, {
+               .name     = "16 bpp RGB 565, LE",
+               .fourcc   = V4L2_PIX_FMT_RGB565,
+               .depth    = 16,
+               .reg      = EM28XX_OUTFMT_RGB_16_656,
+       }, {
+               .name     = "8 bpp Bayer BGBG..GRGR",
+               .fourcc   = V4L2_PIX_FMT_SBGGR8,
+               .depth    = 8,
+               .reg      = EM28XX_OUTFMT_RGB_8_BGBG,
+       }, {
+               .name     = "8 bpp Bayer GRGR..BGBG",
+               .fourcc   = V4L2_PIX_FMT_SGRBG8,
+               .depth    = 8,
+               .reg      = EM28XX_OUTFMT_RGB_8_GRGR,
+       }, {
+               .name     = "8 bpp Bayer GBGB..RGRG",
+               .fourcc   = V4L2_PIX_FMT_SGBRG8,
+               .depth    = 8,
+               .reg      = EM28XX_OUTFMT_RGB_8_GBGB,
+       }, {
+               .name     = "12 bpp YUV411",
+               .fourcc   = V4L2_PIX_FMT_YUV411P,
+               .depth    = 12,
+               .reg      = EM28XX_OUTFMT_YUV411,
+       },
+};
 
 /* supported controls */
 /* Common to all boards */
-static struct v4l2_queryctrl em28xx_qctrl[] = {
+static struct v4l2_queryctrl ac97_qctrl[] = {
        {
                .id = V4L2_CID_AUDIO_VOLUME,
                .type = V4L2_CTRL_TYPE_INTEGER,
@@ -107,7 +134,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
                .maximum = 0x1f,
                .step = 0x1,
                .default_value = 0x1f,
-               .flags = 0,
+               .flags = V4L2_CTRL_FLAG_SLIDER,
        }, {
                .id = V4L2_CID_AUDIO_MUTE,
                .type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -120,8 +147,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
        }
 };
 
-static struct usb_driver em28xx_usb_driver;
-
 /* ------------------------------------------------------------------
        DMA and thread functions
    ------------------------------------------------------------------*/
@@ -139,7 +164,24 @@ static inline void buffer_filled(struct em28xx *dev,
        buf->vb.field_count++;
        do_gettimeofday(&buf->vb.ts);
 
-       dev->isoc_ctl.buf = NULL;
+       dev->isoc_ctl.vid_buf = NULL;
+
+       list_del(&buf->vb.queue);
+       wake_up(&buf->vb.done);
+}
+
+static inline void vbi_buffer_filled(struct em28xx *dev,
+                                    struct em28xx_dmaqueue *dma_q,
+                                    struct em28xx_buffer *buf)
+{
+       /* Advice that buffer was filled */
+       em28xx_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);
@@ -170,15 +212,24 @@ static void em28xx_copy_video(struct em28xx *dev,
        startread = p;
        remain = len;
 
-       /* Interlaces frame */
-       if (buf->top_field)
+       if (dev->progressive)
                fieldstart = outp;
-       else
-               fieldstart = outp + bytesperline;
+       else {
+               /* Interlaces two half frames */
+               if (buf->top_field)
+                       fieldstart = outp;
+               else
+                       fieldstart = outp + bytesperline;
+       }
 
        linesdone = dma_q->pos / bytesperline;
        currlinedone = dma_q->pos % bytesperline;
-       offset = linesdone * bytesperline * 2 + currlinedone;
+
+       if (dev->progressive)
+               offset = linesdone * bytesperline + currlinedone;
+       else
+               offset = linesdone * bytesperline * 2 + currlinedone;
+
        startwrite = fieldstart + offset;
        lencopy = bytesperline - currlinedone;
        lencopy = lencopy > remain ? remain : lencopy;
@@ -187,7 +238,8 @@ static void em28xx_copy_video(struct em28xx *dev,
                em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
                               ((char *)startwrite + lencopy) -
                               ((char *)outp + buf->vb.size));
-               lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite;
+               remain = (char *)outp + buf->vb.size - (char *)startwrite;
+               lencopy = remain;
        }
        if (lencopy <= 0)
                return;
@@ -203,8 +255,10 @@ static void em28xx_copy_video(struct em28xx *dev,
                else
                        lencopy = bytesperline;
 
-               if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
-                       em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
+               if ((char *)startwrite + lencopy > (char *)outp +
+                   buf->vb.size) {
+                       em28xx_isocdbg("Overflow of %zi bytes past buffer end"
+                                      "(2)\n",
                                       ((char *)startwrite + lencopy) -
                                       ((char *)outp + buf->vb.size));
                        lencopy = remain = (char *)outp + buf->vb.size -
@@ -221,6 +275,63 @@ static void em28xx_copy_video(struct em28xx *dev,
        dma_q->pos += len;
 }
 
+static void em28xx_copy_vbi(struct em28xx *dev,
+                             struct em28xx_dmaqueue  *dma_q,
+                             struct em28xx_buffer *buf,
+                             unsigned char *p,
+                             unsigned char *outp, unsigned long len)
+{
+       void *startwrite, *startread;
+       int  offset;
+       int bytesperline = dev->vbi_width;
+
+       if (dev == NULL) {
+               em28xx_isocdbg("dev is null\n");
+               return;
+       }
+
+       if (dma_q == NULL) {
+               em28xx_isocdbg("dma_q is null\n");
+               return;
+       }
+       if (buf == NULL) {
+               return;
+       }
+       if (p == NULL) {
+               em28xx_isocdbg("p is null\n");
+               return;
+       }
+       if (outp == NULL) {
+               em28xx_isocdbg("outp is null\n");
+               return;
+       }
+
+       if (dma_q->pos + len > buf->vb.size)
+               len = buf->vb.size - dma_q->pos;
+
+       if ((p[0] == 0x33 && p[1] == 0x95) ||
+           (p[0] == 0x88 && p[1] == 0x88)) {
+               /* Header field, advance past it */
+               p += 4;
+       } else {
+               len += 4;
+       }
+
+       startread = p;
+
+       startwrite = outp + dma_q->pos;
+       offset = dma_q->pos;
+
+       /* Make sure the bottom field populates the second half of the frame */
+       if (buf->top_field == 0) {
+               startwrite += bytesperline * dev->vbi_height;
+               offset += bytesperline * dev->vbi_height;
+       }
+
+       memcpy(startwrite, startread, len);
+       dma_q->pos += len;
+}
+
 static inline void print_err_status(struct em28xx *dev,
                                     int packet, int status)
 {
@@ -271,7 +382,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
 
        if (list_empty(&dma_q->active)) {
                em28xx_isocdbg("No active queue to serve\n");
-               dev->isoc_ctl.buf = NULL;
+               dev->isoc_ctl.vid_buf = NULL;
                *buf = NULL;
                return;
        }
@@ -283,7 +394,34 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
        outp = videobuf_to_vmalloc(&(*buf)->vb);
        memset(outp, 0, (*buf)->vb.size);
 
-       dev->isoc_ctl.buf = *buf;
+       dev->isoc_ctl.vid_buf = *buf;
+
+       return;
+}
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q,
+                                   struct em28xx_buffer **buf)
+{
+       struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq);
+       char *outp;
+
+       if (list_empty(&dma_q->active)) {
+               em28xx_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 em28xx_buffer, vb.queue);
+       /* Cleans up buffer - Usefull 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;
 }
@@ -294,7 +432,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
 static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
 {
        struct em28xx_buffer    *buf;
-       struct em28xx_dmaqueue  *dma_q = urb->context;
+       struct em28xx_dmaqueue  *dma_q = &dev->vidq;
        unsigned char *outp = NULL;
        int i, len = 0, rc = 1;
        unsigned char *p;
@@ -311,7 +449,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
                        return 0;
        }
 
-       buf = dev->isoc_ctl.buf;
+       buf = dev->isoc_ctl.vid_buf;
        if (buf != NULL)
                outp = videobuf_to_vmalloc(&buf->vb);
 
@@ -348,9 +486,9 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
                }
                if (p[0] == 0x22 && p[1] == 0x5a) {
                        em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
-                                      len, (p[2] & 1)? "odd" : "even");
+                                      len, (p[2] & 1) ? "odd" : "even");
 
-                       if (!(p[2] & 1)) {
+                       if (dev->progressive || !(p[2] & 1)) {
                                if (buf != NULL)
                                        buffer_filled(dev, dma_q, buf);
                                get_next_buf(dma_q, &buf);
@@ -375,6 +513,152 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
        return rc;
 }
 
+/* Version of isoc handler that takes into account a mixture of video and
+   VBI data */
+static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
+{
+       struct em28xx_buffer    *buf, *vbi_buf;
+       struct em28xx_dmaqueue  *dma_q = &dev->vidq;
+       struct em28xx_dmaqueue  *vbi_dma_q = &dev->vbiq;
+       unsigned char *outp = NULL;
+       unsigned char *vbioutp = NULL;
+       int i, len = 0, rc = 1;
+       unsigned char *p;
+       int vbi_size;
+
+       if (!dev)
+               return 0;
+
+       if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+               return 0;
+
+       if (urb->status < 0) {
+               print_err_status(dev, -1, urb->status);
+               if (urb->status == -ENOENT)
+                       return 0;
+       }
+
+       buf = dev->isoc_ctl.vid_buf;
+       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;
+
+               if (status < 0) {
+                       print_err_status(dev, i, status);
+                       if (urb->iso_frame_desc[i].status != -EPROTO)
+                               continue;
+               }
+
+               len = urb->iso_frame_desc[i].actual_length - 4;
+
+               if (urb->iso_frame_desc[i].actual_length <= 0) {
+                       /* em28xx_isocdbg("packet %d is empty",i); - spammy */
+                       continue;
+               }
+               if (urb->iso_frame_desc[i].actual_length >
+                                               dev->max_pkt_size) {
+                       em28xx_isocdbg("packet bigger than packet size");
+                       continue;
+               }
+
+               p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+               /* capture type 0 = vbi start
+                  capture type 1 = video start
+                  capture type 2 = video in progress */
+               if (p[0] == 0x33 && p[1] == 0x95) {
+                       dev->capture_type = 0;
+                       dev->vbi_read = 0;
+                       em28xx_isocdbg("VBI START HEADER!!!\n");
+                       dev->cur_field = p[2];
+               }
+
+               vbi_size = dev->vbi_width * dev->vbi_height;
+
+               if (dev->capture_type == 0) {
+                       if (dev->vbi_read >= vbi_size) {
+                               /* We've already read all the VBI data, so
+                                  treat the rest as video */
+                               em28xx_isocdbg("dev->vbi_read > vbi_size\n");
+                       } else if ((dev->vbi_read + len) < vbi_size) {
+                               /* This entire frame is VBI data */
+                               if (dev->vbi_read == 0 &&
+                                   (!(dev->cur_field & 1))) {
+                                       /* Brand new frame */
+                                       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);
+                               }
+
+                               if (dev->vbi_read == 0) {
+                                       vbi_dma_q->pos = 0;
+                                       if (vbi_buf != NULL) {
+                                               if (dev->cur_field & 1)
+                                                       vbi_buf->top_field = 0;
+                                               else
+                                                       vbi_buf->top_field = 1;
+                                       }
+                               }
+
+                               dev->vbi_read += len;
+                               em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+                                               vbioutp, len);
+                       } else {
+                               /* Some of this frame is VBI data and some is
+                                  video data */
+                               int vbi_data_len = vbi_size - dev->vbi_read;
+                               dev->vbi_read += vbi_data_len;
+                               em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+                                               vbioutp, vbi_data_len);
+                               dev->capture_type = 1;
+                               p += vbi_data_len;
+                               len -= vbi_data_len;
+                       }
+               }
+
+               if (dev->capture_type == 1) {
+                       dev->capture_type = 2;
+                       em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
+                                      len, (p[2] & 1) ? "odd" : "even");
+
+                       if (dev->progressive || !(dev->cur_field & 1)) {
+                               if (buf != NULL)
+                                       buffer_filled(dev, dma_q, buf);
+                               get_next_buf(dma_q, &buf);
+                               if (buf == NULL)
+                                       outp = NULL;
+                               else
+                                       outp = videobuf_to_vmalloc(&buf->vb);
+                       }
+                       if (buf != NULL) {
+                               if (dev->cur_field & 1)
+                                       buf->top_field = 0;
+                               else
+                                       buf->top_field = 1;
+                       }
+
+                       dma_q->pos = 0;
+               }
+               if (buf != NULL && dev->capture_type == 2)
+                       em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+       }
+       return rc;
+}
+
+
 /* ------------------------------------------------------------------
        Videobuf operations
    ------------------------------------------------------------------*/
@@ -386,18 +670,21 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
        struct em28xx        *dev = fh->dev;
        struct v4l2_frequency f;
 
-       *size = 16 * fh->dev->width * fh->dev->height >> 3;
+       *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
+               >> 3;
+
        if (0 == *count)
                *count = EM28XX_DEF_BUF;
 
        if (*count < EM28XX_MIN_BUF)
                *count = EM28XX_MIN_BUF;
 
-       /* Ask tuner to go to analog mode */
+       /* Ask tuner to go to analog or radio mode */
        memset(&f, 0, sizeof(f));
        f.frequency = dev->ctl_freq;
+       f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 
-       em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
 
        return 0;
 }
@@ -421,8 +708,8 @@ static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
           VIDEOBUF_ACTIVE, it won't be, though.
        */
        spin_lock_irqsave(&dev->slock, flags);
-       if (dev->isoc_ctl.buf == buf)
-               dev->isoc_ctl.buf = NULL;
+       if (dev->isoc_ctl.vid_buf == buf)
+               dev->isoc_ctl.vid_buf = NULL;
        spin_unlock_irqrestore(&dev->slock, flags);
 
        videobuf_vmalloc_free(&buf->vb);
@@ -438,9 +725,8 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
        struct em28xx        *dev = fh->dev;
        int                  rc = 0, urb_init = 0;
 
-       /* FIXME: It assumes depth = 16 */
-       /* The only currently supported format is 16 bits/pixel */
-       buf->vb.size = 16 * dev->width * dev->height >> 3;
+       buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
+                       + 7) >> 3;
 
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
                return -EINVAL;
@@ -459,9 +745,16 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                urb_init = 1;
 
        if (urb_init) {
-               rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
-                                     EM28XX_NUM_BUFS, dev->max_pkt_size,
-                                     em28xx_isoc_copy);
+               if (em28xx_vbi_supported(dev) == 1)
+                       rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+                                             EM28XX_NUM_BUFS,
+                                             dev->max_pkt_size,
+                                             em28xx_isoc_copy_vbi);
+               else
+                       rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+                                             EM28XX_NUM_BUFS,
+                                             dev->max_pkt_size,
+                                             em28xx_isoc_copy);
                if (rc < 0)
                        goto fail;
        }
@@ -477,7 +770,9 @@ fail:
 static void
 buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
-       struct em28xx_buffer    *buf     = container_of(vb, struct em28xx_buffer, vb);
+       struct em28xx_buffer    *buf     = container_of(vb,
+                                                       struct em28xx_buffer,
+                                                       vb);
        struct em28xx_fh        *fh      = vq->priv_data;
        struct em28xx           *dev     = fh->dev;
        struct em28xx_dmaqueue  *vidq    = &dev->vidq;
@@ -490,7 +785,9 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 static void buffer_release(struct videobuf_queue *vq,
                                struct videobuf_buffer *vb)
 {
-       struct em28xx_buffer   *buf  = container_of(vb, struct em28xx_buffer, vb);
+       struct em28xx_buffer   *buf  = container_of(vb,
+                                                   struct em28xx_buffer,
+                                                   vb);
        struct em28xx_fh       *fh   = vq->priv_data;
        struct em28xx          *dev  = (struct em28xx *)fh->dev;
 
@@ -508,62 +805,8 @@ static struct videobuf_queue_ops em28xx_video_qops = {
 
 /*********************  v4l2 interface  **************************************/
 
-/*
- * em28xx_config()
- * inits registers with sane defaults
- */
-static int em28xx_config(struct em28xx *dev)
-{
-       int retval;
-
-       /* Sets I2C speed to 100 KHz */
-       if (!dev->board.is_em2800) {
-               retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
-               if (retval < 0) {
-                       em28xx_errdev("%s: em28xx_write_regs_req failed! retval [%d]\n",
-                               __func__, retval);
-                       return retval;
-               }
-       }
-
-       /* enable vbi capturing */
-
-/*     em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
-/*     em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */
-       em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
-
-       dev->mute = 1;          /* maybe not the right place... */
-       dev->volume = 0x1f;
-
-       em28xx_outfmt_set_yuv422(dev);
-       em28xx_colorlevels_set_default(dev);
-       em28xx_compression_disable(dev);
-
-       return 0;
-}
-
-/*
- * em28xx_config_i2c()
- * configure i2c attached devices
- */
-static void em28xx_config_i2c(struct em28xx *dev)
-{
-       struct v4l2_routing route;
-       int zero = 0;
-
-       route.input = INPUT(dev->ctl_input)->vmux;
-       route.output = 0;
-       em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero);
-       em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
-       em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
-}
-
 static void video_mux(struct em28xx *dev, int index)
 {
-       struct v4l2_routing route;
-
-       route.input = INPUT(index)->vmux;
-       route.output = 0;
        dev->ctl_input = index;
        dev->ctl_ainput = INPUT(index)->amux;
        dev->ctl_aoutput = INPUT(index)->aout;
@@ -571,61 +814,111 @@ static void video_mux(struct em28xx *dev, int index)
        if (!dev->ctl_aoutput)
                dev->ctl_aoutput = EM28XX_AOUT_MASTER;
 
-       em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+                       INPUT(index)->vmux, 0, 0);
 
        if (dev->board.has_msp34xx) {
                if (dev->i2s_speed) {
-                       em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ,
-                               &dev->i2s_speed);
+                       v4l2_device_call_all(&dev->v4l2_dev, 0, audio,
+                               s_i2s_clock_freq, dev->i2s_speed);
                }
-               route.input = dev->ctl_ainput;
-               route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
                /* Note: this is msp3400 specific */
-               em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
-                       &route);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+                        dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
+       }
+
+       if (dev->board.adecoder != EM28XX_NOADECODER) {
+               v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+                       dev->ctl_ainput, dev->ctl_aoutput, 0);
        }
 
        em28xx_audio_analog_set(dev);
 }
 
 /* Usage lock check functions */
-static int res_get(struct em28xx_fh *fh)
+static int res_get(struct em28xx_fh *fh, unsigned int bit)
 {
        struct em28xx    *dev = fh->dev;
-       int              rc   = 0;
-
-       /* This instance already has stream_on */
-       if (fh->stream_on)
-               return rc;
 
-       if (dev->stream_on)
-               return -EINVAL;
+       if (fh->resources & bit)
+               /* have it already allocated */
+               return 1;
 
+       /* is it free? */
        mutex_lock(&dev->lock);
-       dev->stream_on = 1;
-       fh->stream_on  = 1;
+       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;
+       em28xx_videodbg("res: get %d\n", bit);
        mutex_unlock(&dev->lock);
-       return rc;
+       return 1;
+}
+
+static int res_check(struct em28xx_fh *fh, unsigned int bit)
+{
+       return fh->resources & bit;
 }
 
-static int res_check(struct em28xx_fh *fh)
+static int res_locked(struct em28xx *dev, unsigned int bit)
 {
-       return (fh->stream_on);
+       return dev->resources & bit;
 }
 
-static void res_free(struct em28xx_fh *fh)
+static void res_free(struct em28xx_fh *fh, unsigned int bits)
 {
        struct em28xx    *dev = fh->dev;
 
-       fh->stream_on = 0;
-       dev->stream_on = 0;
+       BUG_ON((fh->resources & bits) != bits);
+
+       mutex_lock(&dev->lock);
+       fh->resources  &= ~bits;
+       dev->resources &= ~bits;
+       em28xx_videodbg("res: put %d\n", bits);
+       mutex_unlock(&dev->lock);
+}
+
+static int get_ressource(struct em28xx_fh *fh)
+{
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return EM28XX_RESOURCE_VIDEO;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               return EM28XX_RESOURCE_VBI;
+       default:
+               BUG();
+               return 0;
+       }
+}
+
+/*
+ * ac97_queryctrl()
+ * return the ac97 supported controls
+ */
+static int ac97_queryctrl(struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+               if (qc->id && qc->id == ac97_qctrl[i].id) {
+                       memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
+                       return 0;
+               }
+       }
+
+       /* Control is not ac97 related */
+       return 1;
 }
 
 /*
- * em28xx_get_ctrl()
- * return the current saturation, brightness or contrast, mute state
+ * ac97_get_ctrl()
+ * return the current values for ac97 mute and volume
  */
-static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
 {
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -635,29 +928,41 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
                ctrl->value = dev->volume;
                return 0;
        default:
-               return -EINVAL;
+               /* Control is not ac97 related */
+               return 1;
        }
 }
 
 /*
- * em28xx_set_ctrl()
- * mute or set new saturation, brightness or contrast
+ * ac97_set_ctrl()
+ * set values for ac97 mute and volume
  */
-static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
 {
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
+               if (ctrl->id == ac97_qctrl[i].id)
+                       goto handle;
+
+       /* Announce that hasn't handle it */
+       return 1;
+
+handle:
+       if (ctrl->value < ac97_qctrl[i].minimum ||
+           ctrl->value > ac97_qctrl[i].maximum)
+               return -ERANGE;
+
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value != dev->mute) {
-                       dev->mute = ctrl->value;
-                       return em28xx_audio_analog_set(dev);
-               }
-               return 0;
+               dev->mute = ctrl->value;
+               break;
        case V4L2_CID_AUDIO_VOLUME:
                dev->volume = ctrl->value;
-               return em28xx_audio_analog_set(dev);
-       default:
-               return -EINVAL;
+               break;
        }
+
+       return em28xx_audio_analog_set(dev);
 }
 
 static int check_dev(struct em28xx *dev)
@@ -679,8 +984,8 @@ static void get_scale(struct em28xx *dev,
                        unsigned int width, unsigned int height,
                        unsigned int *hscale, unsigned int *vscale)
 {
-       unsigned int          maxw   = norm_maxw(dev);
-       unsigned int          maxh   = norm_maxh(dev);
+       unsigned int          maxw = norm_maxw(dev);
+       unsigned int          maxh = norm_maxh(dev);
 
        *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
        if (*hscale >= 0x4000)
@@ -705,60 +1010,61 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.width = dev->width;
        f->fmt.pix.height = dev->height;
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-       f->fmt.pix.bytesperline = dev->width * 2;
+       f->fmt.pix.pixelformat = dev->format->fourcc;
+       f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
        f->fmt.pix.sizeimage = f->fmt.pix.bytesperline  * dev->height;
        f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
        /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
-       f->fmt.pix.field = dev->interlaced ?
+       if (dev->progressive)
+               f->fmt.pix.field = V4L2_FIELD_NONE;
+       else
+               f->fmt.pix.field = dev->interlaced ?
                           V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
 
        mutex_unlock(&dev->lock);
        return 0;
 }
 
+static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(format); i++)
+               if (format[i].fourcc == fourcc)
+                       return &format[i];
+
+       return NULL;
+}
+
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                        struct v4l2_format *f)
 {
        struct em28xx_fh      *fh    = priv;
        struct em28xx         *dev   = fh->dev;
-       int                   width  = f->fmt.pix.width;
-       int                   height = f->fmt.pix.height;
+       unsigned int          width  = f->fmt.pix.width;
+       unsigned int          height = f->fmt.pix.height;
        unsigned int          maxw   = norm_maxw(dev);
        unsigned int          maxh   = norm_maxh(dev);
        unsigned int          hscale, vscale;
+       struct em28xx_fmt     *fmt;
 
-       /* width must even because of the YUYV format
-          height must be even because of interlacing */
-       height &= 0xfffe;
-       width &= 0xfffe;
-
-       if (height < 32)
-               height = 32;
-       if (height > maxh)
-               height = maxh;
-       if (width < 48)
-               width = 48;
-       if (width > maxw)
-               width = maxw;
-
-       mutex_lock(&dev->lock);
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (!fmt) {
+               em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+                               f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
 
        if (dev->board.is_em2800) {
                /* the em2800 can only scale down to 50% */
-               if (height % (maxh / 2))
-                       height = maxh;
-               if (width % (maxw / 2))
-                       width = maxw;
-               /* according to empiatech support */
-               /* the MaxPacketSize is to small to support */
-               /* framesizes larger than 640x480 @ 30 fps */
-               /* or 640x576 @ 25 fps. As this would cut */
-               /* of a part of the image we prefer */
-               /* 360x576 or 360x480 for now */
-               if (width == maxw && height == maxh)
-                       width /= 2;
+               height = height > (3 * maxh / 4) ? maxh : maxh / 2;
+               width = width > (3 * maxw / 4) ? maxw : maxw / 2;
+       } else {
+               /* width must even because of the YUYV format
+                  height must be even because of interlacing */
+               v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
+                                     1, 0);
        }
 
        get_scale(dev, width, height, &hscale, &vscale);
@@ -768,13 +1074,38 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.width = width;
        f->fmt.pix.height = height;
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-       f->fmt.pix.bytesperline = width * 2;
-       f->fmt.pix.sizeimage = width * 2 * height;
+       f->fmt.pix.pixelformat = fmt->fourcc;
+       f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+       f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
        f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       if (dev->progressive)
+               f->fmt.pix.field = V4L2_FIELD_NONE;
+       else
+               f->fmt.pix.field = dev->interlaced ?
+                          V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
+
+       return 0;
+}
+
+static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
+                                  unsigned width, unsigned height)
+{
+       struct em28xx_fmt     *fmt;
+
+       fmt = format_by_fourcc(fourcc);
+       if (!fmt)
+               return -EINVAL;
+
+       dev->format = fmt;
+       dev->width  = width;
+       dev->height = height;
+
+       /* set new image size */
+       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+       em28xx_set_alternate(dev);
+       em28xx_resolution_set(dev);
 
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -789,38 +1120,40 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       vidioc_try_fmt_vid_cap(file, priv, f);
-
        mutex_lock(&dev->lock);
 
+       vidioc_try_fmt_vid_cap(file, priv, f);
+
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
                em28xx_errdev("%s queue busy\n", __func__);
                rc = -EBUSY;
                goto out;
        }
 
-       if (dev->stream_on && !fh->stream_on) {
-               em28xx_errdev("%s device in use by another fh\n", __func__);
-               rc = -EBUSY;
-               goto out;
-       }
-
-       /* set new image size */
-       dev->width = f->fmt.pix.width;
-       dev->height = f->fmt.pix.height;
-       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
-
-       em28xx_set_alternate(dev);
-       em28xx_resolution_set(dev);
-
-       rc = 0;
+       rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
+                               f->fmt.pix.width, f->fmt.pix.height);
 
 out:
        mutex_unlock(&dev->lock);
        return rc;
 }
 
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+       struct em28xx_fh   *fh  = priv;
+       struct em28xx      *dev = fh->dev;
+       int                rc;
+
+       rc = check_dev(dev);
+       if (rc < 0)
+               return rc;
+
+       *norm = dev->norm;
+
+       return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
 {
        struct em28xx_fh   *fh  = priv;
        struct em28xx      *dev = fh->dev;
@@ -833,27 +1166,59 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
 
        mutex_lock(&dev->lock);
        dev->norm = *norm;
-       mutex_unlock(&dev->lock);
 
        /* Adjusts width/height, if needed */
        f.fmt.pix.width = dev->width;
        f.fmt.pix.height = dev->height;
        vidioc_try_fmt_vid_cap(file, priv, &f);
 
-       mutex_lock(&dev->lock);
-
        /* set new image size */
        dev->width = f.fmt.pix.width;
        dev->height = f.fmt.pix.height;
        get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 
        em28xx_resolution_set(dev);
-       em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
 
        mutex_unlock(&dev->lock);
        return 0;
 }
 
+static int vidioc_g_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *p)
+{
+       struct em28xx_fh   *fh  = priv;
+       struct em28xx      *dev = fh->dev;
+       int rc = 0;
+
+       if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (dev->board.is_webcam)
+               rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
+                                               video, g_parm, p);
+       else
+               v4l2_video_std_frame_period(dev->norm,
+                                                &p->parm.capture.timeperframe);
+
+       return rc;
+}
+
+static int vidioc_s_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *p)
+{
+       struct em28xx_fh   *fh  = priv;
+       struct em28xx      *dev = fh->dev;
+
+       if (!dev->board.is_webcam)
+               return -EINVAL;
+
+       if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
+}
+
 static const char *iname[] = {
        [EM28XX_VMUX_COMPOSITE1] = "Composite1",
        [EM28XX_VMUX_COMPOSITE2] = "Composite2",
@@ -918,10 +1283,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
        if (0 == INPUT(i)->type)
                return -EINVAL;
 
-       mutex_lock(&dev->lock);
-
-       video_mux(dev, i);
+       dev->ctl_input = i;
 
+       mutex_lock(&dev->lock);
+       video_mux(dev, dev->ctl_input);
        mutex_unlock(&dev->lock);
        return 0;
 }
@@ -931,6 +1296,9 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
        struct em28xx_fh   *fh    = priv;
        struct em28xx      *dev   = fh->dev;
 
+       if (!dev->audio_mode.has_audio)
+               return -EINVAL;
+
        switch (a->index) {
        case EM28XX_AMUX_VIDEO:
                strcpy(a->name, "Television");
@@ -971,11 +1339,24 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
        struct em28xx_fh   *fh  = priv;
        struct em28xx      *dev = fh->dev;
 
+
+       if (!dev->audio_mode.has_audio)
+               return -EINVAL;
+
+       if (a->index >= MAX_EM28XX_INPUT)
+               return -EINVAL;
+       if (0 == INPUT(a->index)->type)
+               return -EINVAL;
+
+       mutex_lock(&dev->lock);
+
        dev->ctl_ainput = INPUT(a->index)->amux;
        dev->ctl_aoutput = INPUT(a->index)->aout;
 
        if (!dev->ctl_aoutput)
                dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -985,7 +1366,6 @@ static int vidioc_queryctrl(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
        int                   id  = qc->id;
-       int                   i;
        int                   rc;
 
        rc = check_dev(dev);
@@ -996,16 +1376,16 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 
        qc->id = id;
 
-       if (!dev->board.has_msp34xx) {
-               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-                       if (qc->id && qc->id == em28xx_qctrl[i].id) {
-                               memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
-                               return 0;
-                       }
-               }
+       /* enumberate AC97 controls */
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+               rc = ac97_queryctrl(qc);
+               if (!rc)
+                       return 0;
        }
+
+       /* enumberate V4L2 device controls */
        mutex_lock(&dev->lock);
-       em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
        mutex_unlock(&dev->lock);
 
        if (qc->type)
@@ -1024,15 +1404,19 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
+       rc = 0;
+
        mutex_lock(&dev->lock);
 
-       if (!dev->board.has_msp34xx)
-               rc = em28xx_get_ctrl(dev, ctrl);
+       /* Set an AC97 control */
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+               rc = ac97_get_ctrl(dev, ctrl);
        else
-               rc = -EINVAL;
+               rc = 1;
 
-       if (rc == -EINVAL) {
-               em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
+       /* It were not an AC97 control. Sends it to the v4l2 dev interface */
+       if (rc == 1) {
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
                rc = 0;
        }
 
@@ -1045,7 +1429,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 {
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
-       u8                    i;
        int                   rc;
 
        rc = check_dev(dev);
@@ -1054,28 +1437,31 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
        mutex_lock(&dev->lock);
 
-       if (dev->board.has_msp34xx)
-               em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
-       else {
+       /* Set an AC97 control */
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+               rc = ac97_set_ctrl(dev, ctrl);
+       else
                rc = 1;
-               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-                       if (ctrl->id == em28xx_qctrl[i].id) {
-                               if (ctrl->value < em28xx_qctrl[i].minimum ||
-                                   ctrl->value > em28xx_qctrl[i].maximum) {
-                                       rc = -ERANGE;
-                                       break;
-                               }
-
-                               rc = em28xx_set_ctrl(dev, ctrl);
-                               break;
-                       }
-               }
-       }
 
-       /* Control not found - try to send it to the attached devices */
+       /* It isn't an AC97 control. Sends it to the v4l2 dev interface */
        if (rc == 1) {
-               em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
-               rc = 0;
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+
+               /*
+                * In the case of non-AC97 volume controls, we still need
+                * to do some setups at em28xx, in order to mute/unmute
+                * and to adjust audio volume. However, the value ranges
+                * should be checked by the corresponding V4L subdriver.
+                */
+               switch (ctrl->id) {
+               case V4L2_CID_AUDIO_MUTE:
+                       dev->mute = ctrl->value;
+                       rc = em28xx_audio_analog_set(dev);
+                       break;
+               case V4L2_CID_AUDIO_VOLUME:
+                       dev->volume = ctrl->value;
+                       rc = em28xx_audio_analog_set(dev);
+               }
        }
 
        mutex_unlock(&dev->lock);
@@ -1099,10 +1485,9 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        strcpy(t->name, "Tuner");
 
        mutex_lock(&dev->lock);
-
-       em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
-
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
        mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1121,10 +1506,9 @@ static int vidioc_s_tuner(struct file *file, void *priv,
                return -EINVAL;
 
        mutex_lock(&dev->lock);
-
-       em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
-
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
        mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1134,8 +1518,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
 
+       mutex_lock(&dev->lock);
        f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->ctl_freq;
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1162,9 +1548,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        mutex_lock(&dev->lock);
 
        dev->ctl_freq = f->frequency;
-       em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
 
        mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1181,46 +1568,113 @@ static int em28xx_reg_len(int reg)
        }
 }
 
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+              struct v4l2_dbg_chip_ident *chip)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
+
+       return 0;
+}
+
+
 static int vidioc_g_register(struct file *file, void *priv,
-                            struct v4l2_register *reg)
+                            struct v4l2_dbg_register *reg)
 {
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
        int ret;
 
-       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-               return -EINVAL;
+       switch (reg->match.type) {
+       case V4L2_CHIP_MATCH_AC97:
+               mutex_lock(&dev->lock);
+               ret = em28xx_read_ac97(dev, reg->reg);
+               mutex_unlock(&dev->lock);
+               if (ret < 0)
+                       return ret;
 
-       if (em28xx_reg_len(reg->reg) == 1) {
+               reg->val = ret;
+               reg->size = 1;
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               /* TODO: is this correct? */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+               return 0;
+       default:
+               if (!v4l2_chip_match_host(&reg->match))
+                       return -EINVAL;
+       }
+
+       /* Match host */
+       reg->size = em28xx_reg_len(reg->reg);
+       if (reg->size == 1) {
+               mutex_lock(&dev->lock);
                ret = em28xx_read_reg(dev, reg->reg);
+               mutex_unlock(&dev->lock);
+
                if (ret < 0)
                        return ret;
 
                reg->val = ret;
        } else {
-               __le64 val = 0;
+               __le16 val = 0;
+               mutex_lock(&dev->lock);
                ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
                                                   reg->reg, (char *)&val, 2);
+               mutex_unlock(&dev->lock);
                if (ret < 0)
                        return ret;
 
-               reg->val = le64_to_cpu(val);
+               reg->val = le16_to_cpu(val);
        }
 
        return 0;
 }
 
-static int vidioc_s_register(struct file *file, void *priv,
-                            struct v4l2_register *reg)
-{
-       struct em28xx_fh      *fh  = priv;
-       struct em28xx         *dev = fh->dev;
-       __le64 buf;
+static int vidioc_s_register(struct file *file, void *priv,
+                            struct v4l2_dbg_register *reg)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+       __le16 buf;
+       int    rc;
+
+       switch (reg->match.type) {
+       case V4L2_CHIP_MATCH_AC97:
+               mutex_lock(&dev->lock);
+               rc = em28xx_write_ac97(dev, reg->reg, reg->val);
+               mutex_unlock(&dev->lock);
+
+               return rc;
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               /* TODO: is this correct? */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+               return 0;
+       default:
+               if (!v4l2_chip_match_host(&reg->match))
+                       return -EINVAL;
+       }
+
+       /* Match host */
+       buf = cpu_to_le16(reg->val);
 
-       buf = cpu_to_le64(reg->val);
+       mutex_lock(&dev->lock);
+       rc = em28xx_write_regs(dev, reg->reg, (char *)&buf,
+                              em28xx_reg_len(reg->reg));
+       mutex_unlock(&dev->lock);
 
-       return em28xx_write_regs(dev, reg->reg, (char *)&buf,
-                                em28xx_reg_len(reg->reg));
+       return rc;
 }
 #endif
 
@@ -1250,17 +1704,27 @@ static int vidioc_streamon(struct file *file, void *priv,
 {
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
-       int                   rc;
+       int                   rc = -EINVAL;
 
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
 
+       if (unlikely(type != fh->type))
+               return -EINVAL;
+
+       em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+                       fh, type, fh->resources, dev->resources);
 
-       if (unlikely(res_get(fh) < 0))
+       if (unlikely(!res_get(fh, get_ressource(fh))))
                return -EBUSY;
 
-       return (videobuf_streamon(&fh->vb_vidq));
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_streamon(&fh->vb_vidq);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_streamon(&fh->vb_vbiq);
+
+       return rc;
 }
 
 static int vidioc_streamoff(struct file *file, void *priv,
@@ -1274,15 +1738,22 @@ static int vidioc_streamoff(struct file *file, void *priv,
        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;
 
-       videobuf_streamoff(&fh->vb_vidq);
-       mutex_lock(&dev->lock);
-       res_free(fh);
-       mutex_unlock(&dev->lock);
+       em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+                       fh, type, fh->resources, dev->resources);
+
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               videobuf_streamoff(&fh->vb_vidq);
+               res_free(fh, EM28XX_RESOURCE_VIDEO);
+       } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               videobuf_streamoff(&fh->vb_vbiq);
+               res_free(fh, EM28XX_RESOURCE_VBI);
+       }
 
        return 0;
 }
@@ -1295,16 +1766,21 @@ static int vidioc_querycap(struct file *file, void  *priv,
 
        strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
-       strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
        cap->version = EM28XX_VERSION_CODE;
 
        cap->capabilities =
                        V4L2_CAP_SLICED_VBI_CAPTURE |
                        V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_AUDIO |
                        V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
 
+       if (dev->vbi_dev)
+               cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
+
+       if (dev->audio_mode.has_audio)
+               cap->capabilities |= V4L2_CAP_AUDIO;
+
        if (dev->tuner_type != TUNER_ABSENT)
                cap->capabilities |= V4L2_CAP_TUNER;
 
@@ -1312,15 +1788,13 @@ static int vidioc_querycap(struct file *file, void  *priv,
 }
 
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
-                                       struct v4l2_fmtdesc *fmtd)
+                                       struct v4l2_fmtdesc *f)
 {
-       if (fmtd->index != 0)
+       if (unlikely(f->index >= ARRAY_SIZE(format)))
                return -EINVAL;
 
-       fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       strcpy(fmtd->description, "Packed YUY2");
-       fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
-       memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+       strlcpy(f->description, format[f->index].name, sizeof(f->description));
+       f->pixelformat = format[f->index].fourcc;
 
        return 0;
 }
@@ -1340,13 +1814,13 @@ static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
        mutex_lock(&dev->lock);
 
        f->fmt.sliced.service_set = 0;
-
-       em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, g_fmt, f);
 
        if (f->fmt.sliced.service_set == 0)
                rc = -EINVAL;
 
        mutex_unlock(&dev->lock);
+
        return rc;
 }
 
@@ -1362,7 +1836,7 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
                return rc;
 
        mutex_lock(&dev->lock);
-       em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, g_fmt, f);
        mutex_unlock(&dev->lock);
 
        if (f->fmt.sliced.service_set == 0)
@@ -1371,6 +1845,63 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
        return 0;
 }
 
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+                               struct v4l2_format *format)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *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;
+
+       /* Varies by video standard (NTSC, PAL, etc.) */
+       if (dev->norm & V4L2_STD_525_60) {
+               /* NTSC */
+               format->fmt.vbi.start[0] = 10;
+               format->fmt.vbi.start[1] = 273;
+       } else if (dev->norm & V4L2_STD_625_50) {
+               /* PAL */
+               format->fmt.vbi.start[0] = 6;
+               format->fmt.vbi.start[1] = 318;
+       }
+
+       return 0;
+}
+
+static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+                               struct v4l2_format *format)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *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;
+
+       /* Varies by video standard (NTSC, PAL, etc.) */
+       if (dev->norm & V4L2_STD_525_60) {
+               /* NTSC */
+               format->fmt.vbi.start[0] = 10;
+               format->fmt.vbi.start[1] = 273;
+       } else if (dev->norm & V4L2_STD_625_50) {
+               /* PAL */
+               format->fmt.vbi.start[0] = 6;
+               format->fmt.vbi.start[1] = 318;
+       }
+
+       return 0;
+}
 
 static int vidioc_reqbufs(struct file *file, void *priv,
                          struct v4l2_requestbuffers *rb)
@@ -1383,7 +1914,10 @@ 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)
+               return videobuf_reqbufs(&fh->vb_vidq, rb);
+       else
+               return videobuf_reqbufs(&fh->vb_vbiq, rb);
 }
 
 static int vidioc_querybuf(struct file *file, void *priv,
@@ -1397,7 +1931,19 @@ 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)
+               return videobuf_querybuf(&fh->vb_vidq, b);
+       else {
+               /* FIXME: I'm not sure yet whether this is a bug in zvbi or
+                  the videobuf framework, but we probably shouldn't be
+                  returning a buffer larger than that which was asked for.
+                  At a minimum, it causes a crash in zvbi since it does
+                  a memcpy based on the source buffer length */
+               int result = videobuf_querybuf(&fh->vb_vbiq, b);
+               b->length = dev->vbi_width * dev->vbi_height * 2;
+
+               return result;
+       }
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1410,7 +1956,10 @@ 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)
+               return videobuf_qbuf(&fh->vb_vidq, b);
+       else
+               return videobuf_qbuf(&fh->vb_vbiq, b);
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1423,8 +1972,12 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
        if (rc < 0)
                return rc;
 
-       return (videobuf_dqbuf(&fh->vb_vidq, b,
-                               file->f_flags & O_NONBLOCK));
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
+                                     O_NONBLOCK);
+       else
+               return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
+                                     O_NONBLOCK);
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -1432,7 +1985,10 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
 {
        struct em28xx_fh  *fh = priv;
 
-       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+       else
+               return videobuf_cgmbuf(&fh->vb_vbiq, mbuf, 8);
 }
 #endif
 
@@ -1448,7 +2004,7 @@ static int radio_querycap(struct file *file, void  *priv,
 
        strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
-       strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
        cap->version = EM28XX_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
@@ -1466,7 +2022,10 @@ static int radio_g_tuner(struct file *file, void *priv,
        strcpy(t->name, "Radio");
        t->type = V4L2_TUNER_RADIO;
 
-       em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+       mutex_lock(&dev->lock);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+       mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1498,7 +2057,9 @@ static int radio_s_tuner(struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
 
-       em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+       mutex_lock(&dev->lock);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1523,9 +2084,9 @@ static int radio_queryctrl(struct file *file, void *priv,
                qc->id >= V4L2_CID_LASTP1)
                return -EINVAL;
 
-       for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-               if (qc->id && qc->id == em28xx_qctrl[i].id) {
-                       memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
+       for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+               if (qc->id && qc->id == ac97_qctrl[i].id) {
+                       memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
                        return 0;
                }
        }
@@ -1537,38 +2098,32 @@ static int radio_queryctrl(struct file *file, void *priv,
  * em28xx_v4l2_open()
  * inits the device and starts isoc transfer
  */
-static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+static int em28xx_v4l2_open(struct file *filp)
 {
-       int minor = iminor(inode);
        int errCode = 0, radio = 0;
-       struct em28xx *h, *dev = NULL;
-       struct em28xx_fh *fh;
+       struct video_device *vdev = video_devdata(filp);
+       struct em28xx *dev = video_drvdata(filp);
        enum v4l2_buf_type fh_type = 0;
+       struct em28xx_fh *fh;
+       enum v4l2_field field;
 
-       mutex_lock(&em28xx_devlist_mutex);
-       list_for_each_entry(h, &em28xx_devlist, devlist) {
-               if (h->vdev->minor == minor) {
-                       dev  = h;
-                       fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               }
-               if (h->vbi_dev->minor == minor) {
-                       dev  = h;
-                       fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
-               }
-               if (h->radio_dev &&
-                   h->radio_dev->minor == minor) {
-                       radio = 1;
-                       dev   = h;
-               }
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
+               fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               break;
+       case VFL_TYPE_VBI:
+               fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+               break;
+       case VFL_TYPE_RADIO:
+               radio = 1;
+               break;
        }
-       mutex_unlock(&em28xx_devlist_mutex);
-       if (NULL == dev)
-               return -ENODEV;
 
        mutex_lock(&dev->lock);
 
-       em28xx_videodbg("open minor=%d type=%s users=%d\n",
-                               minor, v4l2_type_names[fh_type], dev->users);
+       em28xx_videodbg("open dev=%s type=%s users=%d\n",
+                       video_device_node_name(vdev), v4l2_type_names[fh_type],
+                       dev->users);
 
 
        fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
@@ -1583,11 +2138,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
        filp->private_data = fh;
 
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
-               dev->width = norm_maxw(dev);
-               dev->height = norm_maxh(dev);
-               dev->hscale = 0;
-               dev->vscale = 0;
-
                em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
                em28xx_set_alternate(dev);
                em28xx_resolution_set(dev);
@@ -1595,19 +2145,31 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
                /* Needed, since GPIO might have disabled power of
                   some i2c device
                 */
-               em28xx_config_i2c(dev);
+               em28xx_wake_i2c(dev);
 
        }
        if (fh->radio) {
                em28xx_videodbg("video_open: setting radio device\n");
-               em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
        }
 
        dev->users++;
 
+       if (dev->progressive)
+               field = V4L2_FIELD_NONE;
+       else
+               field = V4L2_FIELD_INTERLACED;
+
        videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
-                       NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
-                       sizeof(struct em28xx_buffer), fh);
+                                   NULL, &dev->slock,
+                                   V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
+                                   sizeof(struct em28xx_buffer), fh);
+
+       videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
+                                   NULL, &dev->slock,
+                                   V4L2_BUF_TYPE_VBI_CAPTURE,
+                                   V4L2_FIELD_SEQ_TB,
+                                   sizeof(struct em28xx_buffer), fh);
 
        mutex_unlock(&dev->lock);
 
@@ -1619,48 +2181,36 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
  * unregisters the v4l2,i2c and usb devices
  * called when the device gets disconected or at module unload
 */
-static void em28xx_release_resources(struct em28xx *dev)
+void em28xx_release_analog_resources(struct em28xx *dev)
 {
 
        /*FIXME: I2C IR should be disconnected */
 
-       list_del(&dev->devlist);
-       if (dev->sbutton_input_dev)
-               em28xx_deregister_snapshot_button(dev);
-
-       if (dev->ir)
-               em28xx_ir_fini(dev);
-
        if (dev->radio_dev) {
-               if (-1 != dev->radio_dev->minor)
+               if (video_is_registered(dev->radio_dev))
                        video_unregister_device(dev->radio_dev);
                else
                        video_device_release(dev->radio_dev);
                dev->radio_dev = NULL;
        }
        if (dev->vbi_dev) {
-               em28xx_info("V4L2 device /dev/vbi%d deregistered\n",
-                           dev->vbi_dev->num);
-               if (-1 != dev->vbi_dev->minor)
+               em28xx_info("V4L2 device %s deregistered\n",
+                           video_device_node_name(dev->vbi_dev));
+               if (video_is_registered(dev->vbi_dev))
                        video_unregister_device(dev->vbi_dev);
                else
                        video_device_release(dev->vbi_dev);
                dev->vbi_dev = NULL;
        }
        if (dev->vdev) {
-               em28xx_info("V4L2 device /dev/video%d deregistered\n",
-                           dev->vdev->num);
-               if (-1 != dev->vdev->minor)
+               em28xx_info("V4L2 device %s deregistered\n",
+                           video_device_node_name(dev->vdev));
+               if (video_is_registered(dev->vdev))
                        video_unregister_device(dev->vdev);
                else
                        video_device_release(dev->vdev);
                dev->vdev = NULL;
        }
-       em28xx_i2c_unregister(dev);
-       usb_put_dev(dev->udev);
-
-       /* Mark device as unused */
-       em28xx_devused &= ~(1<<dev->devno);
 }
 
 /*
@@ -1668,7 +2218,7 @@ static void em28xx_release_resources(struct em28xx *dev)
  * stops streaming and deallocates all resources allocated by the v4l2
  * calls and ioctls
  */
-static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
+static int em28xx_v4l2_close(struct file *filp)
 {
        struct em28xx_fh *fh  = filp->private_data;
        struct em28xx    *dev = fh->dev;
@@ -1676,26 +2226,27 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
 
        em28xx_videodbg("users=%d\n", dev->users);
 
+       if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
+               videobuf_stop(&fh->vb_vidq);
+               res_free(fh, EM28XX_RESOURCE_VIDEO);
+       }
 
-       mutex_lock(&dev->lock);
-       if (res_check(fh))
-               res_free(fh);
+       if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+               videobuf_stop(&fh->vb_vbiq);
+               res_free(fh, EM28XX_RESOURCE_VBI);
+       }
 
        if (dev->users == 1) {
-               videobuf_stop(&fh->vb_vidq);
-               videobuf_mmap_free(&fh->vb_vidq);
-
                /* the device is already disconnect,
                   free the remaining resources */
                if (dev->state & DEV_DISCONNECTED) {
                        em28xx_release_resources(dev);
-                       mutex_unlock(&dev->lock);
                        kfree(dev);
                        return 0;
                }
 
                /* Save some power by putting tuner to sleep */
-               em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
 
                /* do this before setting alternate! */
                em28xx_uninit_isoc(dev);
@@ -1710,10 +2261,12 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
                                        "0 (error=%i)\n", errCode);
                }
        }
+
+       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;
 }
 
@@ -1738,12 +2291,22 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
         */
 
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               if (unlikely(res_get(fh)))
+               if (res_locked(dev, EM28XX_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, EM28XX_RESOURCE_VBI))
+                       return -EBUSY;
+
+               return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+                                       filp->f_flags & O_NONBLOCK);
+       }
+
        return 0;
 }
 
@@ -1751,7 +2314,7 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
  * em28xx_v4l2_poll()
  * will allocate buffers when called for the first time
  */
-static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
 {
        struct em28xx_fh *fh = filp->private_data;
        struct em28xx *dev = fh->dev;
@@ -1761,13 +2324,17 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
        if (rc < 0)
                return rc;
 
-       if (unlikely(res_get(fh) < 0))
-               return POLLERR;
-
-       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (!res_get(fh, EM28XX_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, EM28XX_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);
+       }
 }
 
 /*
@@ -1779,14 +2346,14 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        struct em28xx    *dev   = fh->dev;
        int              rc;
 
-       if (unlikely(res_get(fh) < 0))
-               return -EBUSY;
-
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
 
-       rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       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);
 
        em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
@@ -1796,7 +2363,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        return rc;
 }
 
-static const struct file_operations em28xx_v4l_fops = {
+static const struct v4l2_file_operations em28xx_v4l_fops = {
        .owner         = THIS_MODULE,
        .open          = em28xx_v4l2_open,
        .release       = em28xx_v4l2_close,
@@ -1804,8 +2371,6 @@ static const struct file_operations em28xx_v4l_fops = {
        .poll          = em28xx_v4l2_poll,
        .mmap          = em28xx_v4l2_mmap,
        .ioctl         = video_ioctl2,
-       .llseek        = no_llseek,
-       .compat_ioctl  = v4l_compat_ioctl32,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1814,6 +2379,8 @@ 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,
+       .vidioc_g_fmt_vbi_cap       = vidioc_g_fmt_vbi_cap,
+       .vidioc_s_fmt_vbi_cap       = vidioc_s_fmt_vbi_cap,
        .vidioc_g_audio             = vidioc_g_audio,
        .vidioc_s_audio             = vidioc_s_audio,
        .vidioc_cropcap             = vidioc_cropcap,
@@ -1826,7 +2393,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_querybuf            = vidioc_querybuf,
        .vidioc_qbuf                = vidioc_qbuf,
        .vidioc_dqbuf               = vidioc_dqbuf,
+       .vidioc_g_std               = vidioc_g_std,
        .vidioc_s_std               = vidioc_s_std,
+       .vidioc_g_parm              = vidioc_g_parm,
+       .vidioc_s_parm              = vidioc_s_parm,
        .vidioc_enum_input          = vidioc_enum_input,
        .vidioc_g_input             = vidioc_g_input,
        .vidioc_s_input             = vidioc_s_input,
@@ -1842,6 +2412,7 @@ 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,
@@ -1853,19 +2424,15 @@ static const struct video_device em28xx_video_template = {
        .release                    = video_device_release,
        .ioctl_ops                  = &video_ioctl_ops,
 
-       .minor                      = -1,
-
        .tvnorms                    = V4L2_STD_ALL,
        .current_norm               = V4L2_STD_PAL,
 };
 
-static const struct file_operations radio_fops = {
+static const struct v4l2_file_operations radio_fops = {
        .owner         = THIS_MODULE,
        .open          = em28xx_v4l2_open,
        .release       = em28xx_v4l2_close,
        .ioctl         = video_ioctl2,
-       .compat_ioctl  = v4l_compat_ioctl32,
-       .llseek        = no_llseek,
 };
 
 static const struct v4l2_ioctl_ops radio_ioctl_ops = {
@@ -1891,76 +2458,69 @@ static struct video_device em28xx_radio_template = {
        .name                 = "em28xx-radio",
        .fops                 = &radio_fops,
        .ioctl_ops            = &radio_ioctl_ops,
-       .minor                = -1,
 };
 
 /******************************** usb interface ******************************/
 
 
-static LIST_HEAD(em28xx_extension_devlist);
-static DEFINE_MUTEX(em28xx_extension_devlist_lock);
-
-int em28xx_register_extension(struct em28xx_ops *ops)
-{
-       struct em28xx *dev = NULL;
-
-       mutex_lock(&em28xx_devlist_mutex);
-       mutex_lock(&em28xx_extension_devlist_lock);
-       list_add_tail(&ops->next, &em28xx_extension_devlist);
-       list_for_each_entry(dev, &em28xx_devlist, devlist) {
-               if (dev)
-                       ops->init(dev);
-       }
-       printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
-       mutex_unlock(&em28xx_extension_devlist_lock);
-       mutex_unlock(&em28xx_devlist_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(em28xx_register_extension);
-
-void em28xx_unregister_extension(struct em28xx_ops *ops)
-{
-       struct em28xx *dev = NULL;
-
-       mutex_lock(&em28xx_devlist_mutex);
-       list_for_each_entry(dev, &em28xx_devlist, devlist) {
-               if (dev)
-                       ops->fini(dev);
-       }
-
-       mutex_lock(&em28xx_extension_devlist_lock);
-       printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
-       list_del(&ops->next);
-       mutex_unlock(&em28xx_extension_devlist_lock);
-       mutex_unlock(&em28xx_devlist_mutex);
-}
-EXPORT_SYMBOL(em28xx_unregister_extension);
 
 static struct video_device *em28xx_vdev_init(struct em28xx *dev,
-                                            const struct video_device *template,
-                                            const char *type_name)
+                                       const struct video_device *template,
+                                       const char *type_name)
 {
        struct video_device *vfd;
 
        vfd = video_device_alloc();
        if (NULL == vfd)
                return NULL;
-       *vfd = *template;
-       vfd->minor   = -1;
-       vfd->parent = &dev->udev->dev;
-       vfd->release = video_device_release;
-       vfd->debug = video_debug;
+
+       *vfd            = *template;
+       vfd->v4l2_dev   = &dev->v4l2_dev;
+       vfd->release    = video_device_release;
+       vfd->debug      = video_debug;
 
        snprintf(vfd->name, sizeof(vfd->name), "%s %s",
                 dev->name, type_name);
 
+       video_set_drvdata(vfd, dev);
        return vfd;
 }
 
-static int register_analog_devices(struct em28xx *dev)
+int em28xx_register_analog_devices(struct em28xx *dev)
 {
+      u8 val;
        int ret;
 
+       printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n",
+               dev->name,
+               (EM28XX_VERSION_CODE >> 16) & 0xff,
+               (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+
+       /* set default norm */
+       dev->norm = em28xx_video_template.current_norm;
+       dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+       dev->ctl_input = 0;
+
+       /* Analog specific initialization */
+       dev->format = &format[0];
+       em28xx_set_video_format(dev, format[0].fourcc,
+                               norm_maxw(dev), norm_maxh(dev));
+
+       video_mux(dev, dev->ctl_input);
+
+       /* Audio defaults */
+       dev->mute = 1;
+       dev->volume = 0x1f;
+
+/*     em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
+       val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
+       em28xx_write_reg(dev, EM28XX_R0F_XCLK,
+                        (EM28XX_XCLK_AUDIO_UNMUTE | val));
+
+       em28xx_set_outfmt(dev);
+       em28xx_colorlevels_set_default(dev);
+       em28xx_compression_disable(dev);
+
        /* allocate and fill video video_device struct */
        dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
        if (!dev->vdev) {
@@ -1978,18 +2538,22 @@ static int register_analog_devices(struct em28xx *dev)
        }
 
        /* Allocate and fill vbi video_device struct */
-       dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi");
+       if (em28xx_vbi_supported(dev) == 1) {
+               dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
+                                               "vbi");
 
-       /* register v4l2 vbi video_device */
-       ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
-                                       vbi_nr[dev->devno]);
-       if (ret < 0) {
-               em28xx_errdev("unable to register vbi device\n");
-               return ret;
+               /* register v4l2 vbi video_device */
+               ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+                                           vbi_nr[dev->devno]);
+               if (ret < 0) {
+                       em28xx_errdev("unable to register vbi device\n");
+                       return ret;
+               }
        }
 
        if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
-               dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio");
+               dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
+                                                 "radio");
                if (!dev->radio_dev) {
                        em28xx_errdev("cannot allocate video_device.\n");
                        return -ENODEV;
@@ -2000,442 +2564,16 @@ static int register_analog_devices(struct em28xx *dev)
                        em28xx_errdev("can't register radio device\n");
                        return ret;
                }
-               em28xx_info("Registered radio device as /dev/radio%d\n",
-                           dev->radio_dev->num);
-       }
-
-       em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
-                               dev->vdev->num, dev->vbi_dev->num);
-
-       return 0;
-}
-
-
-/*
- * em28xx_init_dev()
- * allocates and inits the device structs, registers i2c bus and v4l device
- */
-static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
-                          int minor)
-{
-       struct em28xx_ops *ops = NULL;
-       struct em28xx *dev = *devhandle;
-       int retval = -ENOMEM;
-       int errCode;
-       unsigned int maxh, maxw;
-
-       dev->udev = udev;
-       mutex_init(&dev->lock);
-       mutex_init(&dev->ctrl_urb_lock);
-       spin_lock_init(&dev->slock);
-       init_waitqueue_head(&dev->open);
-       init_waitqueue_head(&dev->wait_frame);
-       init_waitqueue_head(&dev->wait_stream);
-
-       dev->em28xx_write_regs = em28xx_write_regs;
-       dev->em28xx_read_reg = em28xx_read_reg;
-       dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
-       dev->em28xx_write_regs_req = em28xx_write_regs_req;
-       dev->em28xx_read_reg_req = em28xx_read_reg_req;
-       dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800;
-
-       em28xx_pre_card_setup(dev);
-
-       errCode = em28xx_config(dev);
-       if (errCode) {
-               em28xx_errdev("error configuring device\n");
-               return -ENOMEM;
-       }
-
-       /* register i2c bus */
-       errCode = em28xx_i2c_register(dev);
-       if (errCode < 0) {
-               em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
-                       __func__, errCode);
-               return errCode;
-       }
-
-       /* Do board specific init and eeprom reading */
-       em28xx_card_setup(dev);
-
-       /* Configure audio */
-       errCode = em28xx_audio_setup(dev);
-       if (errCode < 0) {
-               em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n",
-                       __func__, errCode);
-       }
-
-       /* configure the device */
-       em28xx_config_i2c(dev);
-
-       /* set default norm */
-       dev->norm = em28xx_video_template.current_norm;
-
-       maxw = norm_maxw(dev);
-       maxh = norm_maxh(dev);
-
-       /* set default image size */
-       dev->width = maxw;
-       dev->height = maxh;
-       dev->interlaced = EM28XX_INTERLACED_DEFAULT;
-       dev->hscale = 0;
-       dev->vscale = 0;
-       dev->ctl_input = 2;
-
-       errCode = em28xx_config(dev);
-       if (errCode < 0) {
-               em28xx_errdev("%s: em28xx_config - errCode [%d]!\n",
-                       __func__, errCode);
-               return errCode;
-       }
-
-       /* init video dma queues */
-       INIT_LIST_HEAD(&dev->vidq.active);
-       INIT_LIST_HEAD(&dev->vidq.queued);
-
-
-       if (dev->board.has_msp34xx) {
-               /* Send a reset to other chips via gpio */
-               errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
-               if (errCode < 0) {
-                       em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(1) failed! errCode [%d]\n",
-                               __func__, errCode);
-                       return errCode;
-               }
-               msleep(3);
-
-               errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
-               if (errCode < 0) {
-                       em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(2) failed! errCode [%d]\n",
-                               __func__, errCode);
-                       return errCode;
-               }
-               msleep(3);
-       }
-
-       video_mux(dev, 0);
-
-       mutex_lock(&em28xx_devlist_mutex);
-       list_add_tail(&dev->devlist, &em28xx_devlist);
-       retval = register_analog_devices(dev);
-       if (retval < 0) {
-               em28xx_release_resources(dev);
-               mutex_unlock(&em28xx_devlist_mutex);
-               goto fail_reg_devices;
-       }
-
-       mutex_lock(&em28xx_extension_devlist_lock);
-       if (!list_empty(&em28xx_extension_devlist)) {
-               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-                       if (ops->id)
-                               ops->init(dev);
-               }
-       }
-       mutex_unlock(&em28xx_extension_devlist_lock);
-       mutex_unlock(&em28xx_devlist_mutex);
-
-       /* Save some power by putting tuner to sleep */
-       em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
-
-       return 0;
-
-fail_reg_devices:
-       mutex_unlock(&dev->lock);
-       return retval;
-}
-
-#if defined(CONFIG_MODULES) && defined(MODULE)
-static void request_module_async(struct work_struct *work)
-{
-       struct em28xx *dev = container_of(work,
-                            struct em28xx, request_module_wk);
-
-       if (dev->has_audio_class)
-               request_module("snd-usb-audio");
-       else if (dev->has_alsa_audio)
-               request_module("em28xx-alsa");
-
-       if (dev->board.has_dvb)
-               request_module("em28xx-dvb");
-}
-
-static void request_modules(struct em28xx *dev)
-{
-       INIT_WORK(&dev->request_module_wk, request_module_async);
-       schedule_work(&dev->request_module_wk);
-}
-#else
-#define request_modules(dev)
-#endif /* CONFIG_MODULES */
-
-/*
- * em28xx_usb_probe()
- * checks for supported devices
- */
-static int em28xx_usb_probe(struct usb_interface *interface,
-                           const struct usb_device_id *id)
-{
-       const struct usb_endpoint_descriptor *endpoint;
-       struct usb_device *udev;
-       struct usb_interface *uif;
-       struct em28xx *dev = NULL;
-       int retval = -ENODEV;
-       int i, nr, ifnum, isoc_pipe;
-       char *speed;
-       char descr[255] = "";
-
-       udev = usb_get_dev(interface_to_usbdev(interface));
-       ifnum = interface->altsetting[0].desc.bInterfaceNumber;
-
-       /* Check to see next free device and mark as used */
-       nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
-       em28xx_devused |= 1<<nr;
-
-       /* Don't register audio interfaces */
-       if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-               em28xx_err(DRIVER_NAME " audio device (%04x:%04x): "
-                       "interface %i, class %i\n",
-                       le16_to_cpu(udev->descriptor.idVendor),
-                       le16_to_cpu(udev->descriptor.idProduct),
-                       ifnum,
-                       interface->altsetting[0].desc.bInterfaceClass);
-
-               em28xx_devused &= ~(1<<nr);
-               return -ENODEV;
-       }
-
-       endpoint = &interface->cur_altsetting->endpoint[0].desc;
-
-       /* check if the device has the iso in endpoint at the correct place */
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-           USB_ENDPOINT_XFER_ISOC &&
-           (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940))
-       {
-               /* It's a newer em2874/em2875 device */
-               isoc_pipe = 0;
-       } else {
-               int check_interface = 1;
-               isoc_pipe = 1;
-               endpoint = &interface->cur_altsetting->endpoint[1].desc;
-               if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
-                   USB_ENDPOINT_XFER_ISOC)
-                       check_interface = 0;
-
-               if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
-                       check_interface = 0;
-
-               if (!check_interface) {
-                       em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
-                               "interface %i, class %i found.\n",
-                               le16_to_cpu(udev->descriptor.idVendor),
-                               le16_to_cpu(udev->descriptor.idProduct),
-                               ifnum,
-                               interface->altsetting[0].desc.bInterfaceClass);
-
-                       em28xx_err(DRIVER_NAME " This is an anciliary "
-                               "interface not used by the driver\n");
-
-                       em28xx_devused &= ~(1<<nr);
-                       return -ENODEV;
-               }
-       }
-
-       switch (udev->speed) {
-       case USB_SPEED_LOW:
-               speed = "1.5";
-               break;
-       case USB_SPEED_UNKNOWN:
-       case USB_SPEED_FULL:
-               speed = "12";
-               break;
-       case USB_SPEED_HIGH:
-               speed = "480";
-               break;
-       default:
-               speed = "unknown";
-       }
-
-       if (udev->manufacturer)
-               strlcpy(descr, udev->manufacturer, sizeof(descr));
-
-       if (udev->product) {
-               if (*descr)
-                       strlcat(descr, " ", sizeof(descr));
-               strlcat(descr, udev->product, sizeof(descr));
-       }
-       if (*descr)
-               strlcat(descr, " ", sizeof(descr));
-
-       printk(DRIVER_NAME ": New device %s@ %s Mbps "
-               "(%04x:%04x, interface %d, class %d)\n",
-               descr,
-               speed,
-               le16_to_cpu(udev->descriptor.idVendor),
-               le16_to_cpu(udev->descriptor.idProduct),
-               ifnum,
-               interface->altsetting->desc.bInterfaceNumber);
-
-       if (nr >= EM28XX_MAXBOARDS) {
-               printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
-                               EM28XX_MAXBOARDS);
-               em28xx_devused &= ~(1<<nr);
-               return -ENOMEM;
-       }
-
-       /* allocate memory for our device state and initialize it */
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (dev == NULL) {
-               em28xx_err(DRIVER_NAME ": out of memory!\n");
-               em28xx_devused &= ~(1<<nr);
-               return -ENOMEM;
-       }
-
-       snprintf(dev->name, 29, "em28xx #%d", nr);
-       dev->devno = nr;
-       dev->model = id->driver_info;
-       dev->alt   = -1;
-
-       /* Checks if audio is provided by some interface */
-       for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
-               uif = udev->config->interface[i];
-               if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-                       dev->has_audio_class = 1;
-                       break;
-               }
+               em28xx_info("Registered radio device as %s\n",
+                           video_device_node_name(dev->radio_dev));
        }
 
-       /* compute alternate max packet sizes */
-       uif = udev->actconfig->interface[0];
+       em28xx_info("V4L2 video device registered as %s\n",
+                   video_device_node_name(dev->vdev));
 
-       dev->num_alt = uif->num_altsetting;
-       em28xx_videodbg("Alternate settings: %i\n", dev->num_alt);
-/*     dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */
-       dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
-
-       if (dev->alt_max_pkt_size == NULL) {
-               em28xx_errdev("out of memory!\n");
-               em28xx_devused &= ~(1<<nr);
-               kfree(dev);
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < dev->num_alt ; i++) {
-               u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
-                                                       wMaxPacketSize);
-               dev->alt_max_pkt_size[i] =
-                   (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
-               em28xx_videodbg("Alternate setting %i, max size= %i\n", i,
-                                               dev->alt_max_pkt_size[i]);
-       }
-
-       if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
-               dev->model = card[nr];
-
-       /* allocate device struct */
-       retval = em28xx_init_dev(&dev, udev, nr);
-       if (retval) {
-               em28xx_devused &= ~(1<<dev->devno);
-               kfree(dev);
-
-               return retval;
-       }
-
-       /* save our data pointer in this interface device */
-       usb_set_intfdata(interface, dev);
-
-       request_modules(dev);
+       if (dev->vbi_dev)
+               em28xx_info("V4L2 VBI device registered as %s\n",
+                           video_device_node_name(dev->vbi_dev));
 
        return 0;
 }
-
-/*
- * em28xx_usb_disconnect()
- * called when the device gets diconencted
- * video device will be unregistered on v4l2_close in case it is still open
- */
-static void em28xx_usb_disconnect(struct usb_interface *interface)
-{
-       struct em28xx *dev;
-       struct em28xx_ops *ops = NULL;
-
-       dev = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
-
-       if (!dev)
-               return;
-
-       em28xx_info("disconnecting %s\n", dev->vdev->name);
-
-       /* wait until all current v4l2 io is finished then deallocate
-          resources */
-       mutex_lock(&dev->lock);
-
-       wake_up_interruptible_all(&dev->open);
-
-       if (dev->users) {
-               em28xx_warn
-                   ("device /dev/video%d is open! Deregistration and memory "
-                    "deallocation are deferred on close.\n",
-                               dev->vdev->num);
-
-               dev->state |= DEV_MISCONFIGURED;
-               em28xx_uninit_isoc(dev);
-               dev->state |= DEV_DISCONNECTED;
-               wake_up_interruptible(&dev->wait_frame);
-               wake_up_interruptible(&dev->wait_stream);
-       } else {
-               dev->state |= DEV_DISCONNECTED;
-               em28xx_release_resources(dev);
-       }
-       mutex_unlock(&dev->lock);
-
-       mutex_lock(&em28xx_extension_devlist_lock);
-       if (!list_empty(&em28xx_extension_devlist)) {
-               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-                       ops->fini(dev);
-               }
-       }
-       mutex_unlock(&em28xx_extension_devlist_lock);
-
-       if (!dev->users) {
-               kfree(dev->alt_max_pkt_size);
-               kfree(dev);
-       }
-}
-
-static struct usb_driver em28xx_usb_driver = {
-       .name = "em28xx",
-       .probe = em28xx_usb_probe,
-       .disconnect = em28xx_usb_disconnect,
-       .id_table = em28xx_id_table,
-};
-
-static int __init em28xx_module_init(void)
-{
-       int result;
-
-       printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
-              (EM28XX_VERSION_CODE >> 16) & 0xff,
-              (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
-#endif
-
-       /* register this driver with the USB subsystem */
-       result = usb_register(&em28xx_usb_driver);
-       if (result)
-               em28xx_err(DRIVER_NAME
-                          " usb_register failed. Error number %d.\n", result);
-
-       return result;
-}
-
-static void __exit em28xx_module_exit(void)
-{
-       /* deregister this driver with the USB subsystem */
-       usb_deregister(&em28xx_usb_driver);
-}
-
-module_init(em28xx_module_init);
-module_exit(em28xx_module_exit);