V4L/DVB (12171): em28xx: fix webcam usage with different output formats
[safe/jmp/linux-2.6] / drivers / media / video / em28xx / em28xx-video.c
index 838e7ec..14316c9 100644 (file)
@@ -38,6 +38,8 @@
 
 #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>
 
@@ -46,9 +48,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) \
@@ -71,18 +72,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static LIST_HEAD(em28xx_devlist);
-
-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");
@@ -91,8 +87,40 @@ 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 */
@@ -118,8 +146,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
        }
 };
 
-static struct usb_driver em28xx_usb_driver;
-
 /* ------------------------------------------------------------------
        DMA and thread functions
    ------------------------------------------------------------------*/
@@ -185,7 +211,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;
@@ -201,7 +228,8 @@ static void em28xx_copy_video(struct em28xx *dev,
                else
                        lencopy = bytesperline;
 
-               if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+               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));
@@ -346,7 +374,7 @@ 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 (buf != NULL)
@@ -384,18 +412,20 @@ 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;
 }
@@ -436,9 +466,7 @@ 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;
@@ -475,7 +503,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;
@@ -488,7 +518,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;
 
@@ -506,69 +538,31 @@ static struct videobuf_queue_ops em28xx_video_qops = {
 
 /*********************  v4l2 interface  **************************************/
 
-/*
- * em28xx_config()
- * inits registers with sane defaults
- */
-static int em28xx_config(struct em28xx *dev)
-{
-
-       /* Sets I2C speed to 100 KHz */
-       if (!dev->is_em2800)
-               em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
-
-       /* enable vbi capturing */
-
-/*     em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */
-/*     em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */
-       em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1);
-
-       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;
-
-       route.input = INPUT(dev->ctl_input)->vmux;
-       route.output = 0;
-       em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
-       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;
+
+       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->has_msp34xx) {
+       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);
@@ -585,28 +579,24 @@ static int res_get(struct em28xx_fh *fh)
                return rc;
 
        if (dev->stream_on)
-               return -EINVAL;
+               return -EBUSY;
 
-       mutex_lock(&dev->lock);
        dev->stream_on = 1;
        fh->stream_on  = 1;
-       mutex_unlock(&dev->lock);
        return rc;
 }
 
 static int res_check(struct em28xx_fh *fh)
 {
-       return (fh->stream_on);
+       return fh->stream_on;
 }
 
 static void res_free(struct em28xx_fh *fh)
 {
        struct em28xx    *dev = fh->dev;
 
-       mutex_lock(&dev->lock);
        fh->stream_on = 0;
        dev->stream_on = 0;
-       mutex_unlock(&dev->lock);
 }
 
 /*
@@ -693,8 +683,8 @@ 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;
 
@@ -706,47 +696,54 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        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->is_em2800) {
+       if (dev->board.is_27xx) {
+               /* FIXME: This is the only supported fmt */
+               width  = 640;
+               height = 480;
+       } else 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 */
+               height = height > (3 * maxh / 4) ? maxh : maxh / 2;
+               width = width > (3 * maxw / 4) ? maxw : maxw / 2;
+               /* According to empiatech support the MaxPacketSize is too 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;
+       } 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);
@@ -756,13 +753,40 @@ 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;
 
-       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
+                                  unsigned width, unsigned height)
+{
+       struct em28xx_fmt     *fmt;
+
+       /* FIXME: This is the only supported fmt */
+       if (dev->board.is_27xx) {
+               width  = 640;
+               height = 480;
+       }
+
+       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);
+
        return 0;
 }
 
@@ -777,10 +801,10 @@ 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;
@@ -793,22 +817,15 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                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_s_std(struct file *file, void *priv, v4l2_std_id *norm)
 {
        struct em28xx_fh   *fh  = priv;
        struct em28xx      *dev = fh->dev;
@@ -821,22 +838,19 @@ 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;
@@ -906,10 +920,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;
 }
@@ -918,20 +932,38 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
        struct em28xx_fh   *fh    = priv;
        struct em28xx      *dev   = fh->dev;
-       unsigned int        index = a->index;
 
-       if (a->index > 1)
-               return -EINVAL;
-
-       index = dev->ctl_ainput;
-
-       if (index == 0)
+       switch (a->index) {
+       case EM28XX_AMUX_VIDEO:
                strcpy(a->name, "Television");
-       else
+               break;
+       case EM28XX_AMUX_LINE_IN:
                strcpy(a->name, "Line In");
+               break;
+       case EM28XX_AMUX_VIDEO2:
+               strcpy(a->name, "Television alt");
+               break;
+       case EM28XX_AMUX_PHONE:
+               strcpy(a->name, "Phone");
+               break;
+       case EM28XX_AMUX_MIC:
+               strcpy(a->name, "Mic");
+               break;
+       case EM28XX_AMUX_CD:
+               strcpy(a->name, "CD");
+               break;
+       case EM28XX_AMUX_AUX:
+               strcpy(a->name, "Aux");
+               break;
+       case EM28XX_AMUX_PCM_OUT:
+               strcpy(a->name, "PCM");
+               break;
+       default:
+               return -EINVAL;
+       }
 
+       a->index = dev->ctl_ainput;
        a->capability = V4L2_AUDCAP_STEREO;
-       a->index = index;
 
        return 0;
 }
@@ -941,9 +973,21 @@ 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 (a->index != dev->ctl_ainput)
+
+       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;
 }
 
@@ -964,7 +1008,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 
        qc->id = id;
 
-       if (!dev->has_msp34xx) {
+       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));
@@ -972,8 +1016,9 @@ static int vidioc_queryctrl(struct file *file, void *priv,
                        }
                }
        }
+
        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)
@@ -992,16 +1037,18 @@ 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->has_msp34xx)
+       if (dev->board.has_msp34xx)
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+       else {
                rc = em28xx_get_ctrl(dev, ctrl);
-       else
-               rc = -EINVAL;
-
-       if (rc == -EINVAL) {
-               em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
-               rc = 0;
+               if (rc < 0) {
+                       v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+                       rc = 0;
+               }
        }
 
        mutex_unlock(&dev->lock);
@@ -1022,8 +1069,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
        mutex_lock(&dev->lock);
 
-       if (dev->has_msp34xx)
-               em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
+       if (dev->board.has_msp34xx)
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
        else {
                rc = 1;
                for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
@@ -1042,7 +1089,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
        /* Control not found - try to send it to the attached devices */
        if (rc == 1) {
-               em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
                rc = 0;
        }
 
@@ -1067,10 +1114,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;
 }
 
@@ -1089,10 +1135,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;
 }
 
@@ -1102,8 +1147,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;
 }
@@ -1130,9 +1177,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;
 }
 
@@ -1149,46 +1197,111 @@ 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))
+       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;
+
+               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:
+               /* Not supported yet */
                return -EINVAL;
+       default:
+               if (!v4l2_chip_match_host(&reg->match))
+                       return -EINVAL;
+       }
 
-       if (em28xx_reg_len(reg->reg) == 1) {
+       /* 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 v4l2_dbg_register *reg)
 {
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
-       __le64 buf;
+       __le16 buf;
+       int    rc;
 
-       buf = cpu_to_le64(reg->val);
+       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 em28xx_write_regs(dev, reg->reg, (char *)&buf,
-                                em28xx_reg_len(reg->reg));
+               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:
+               /* Not supported yet */
+               return -EINVAL;
+       default:
+               if (!v4l2_chip_match_host(&reg->match))
+                       return -EINVAL;
+       }
+
+       /* Match host */
+       buf = cpu_to_le16(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 rc;
 }
 #endif
 
@@ -1225,10 +1338,15 @@ static int vidioc_streamon(struct file *file, void *priv,
                return rc;
 
 
-       if (unlikely(res_get(fh) < 0))
-               return -EBUSY;
+       mutex_lock(&dev->lock);
+       rc = res_get(fh);
 
-       return (videobuf_streamon(&fh->vb_vidq));
+       if (likely(rc >= 0))
+               rc = videobuf_streamon(&fh->vb_vidq);
+
+       mutex_unlock(&dev->lock);
+
+       return rc;
 }
 
 static int vidioc_streamoff(struct file *file, void *priv,
@@ -1247,9 +1365,13 @@ static int vidioc_streamoff(struct file *file, void *priv,
        if (type != fh->type)
                return -EINVAL;
 
+       mutex_lock(&dev->lock);
+
        videobuf_streamoff(&fh->vb_vidq);
        res_free(fh);
 
+       mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1261,7 +1383,7 @@ 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->udev->dev.bus_id, sizeof(cap->bus_info));
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
        cap->version = EM28XX_VERSION_CODE;
 
@@ -1278,15 +1400,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;
 }
@@ -1306,13 +1426,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;
 }
 
@@ -1328,7 +1448,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)
@@ -1349,7 +1469,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return (videobuf_reqbufs(&fh->vb_vidq, rb));
+       return videobuf_reqbufs(&fh->vb_vidq, rb);
 }
 
 static int vidioc_querybuf(struct file *file, void *priv,
@@ -1363,7 +1483,7 @@ static int vidioc_querybuf(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return (videobuf_querybuf(&fh->vb_vidq, b));
+       return videobuf_querybuf(&fh->vb_vidq, b);
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1376,7 +1496,7 @@ 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));
+       return videobuf_qbuf(&fh->vb_vidq, b);
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1389,8 +1509,7 @@ 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));
+       return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -1414,7 +1533,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->udev->dev.bus_id, 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;
@@ -1432,7 +1551,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;
 }
 
@@ -1464,7 +1586,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;
 }
@@ -1503,32 +1627,21 @@ 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;
+       int minor = video_devdata(filp)->minor;
+       int errCode = 0, radio;
+       struct em28xx *dev;
+       enum v4l2_buf_type fh_type;
        struct em28xx_fh *fh;
-       enum v4l2_buf_type fh_type = 0;
 
-       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;
-               }
-       }
+       dev = em28xx_get_device(minor, &fh_type, &radio);
+
        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);
 
@@ -1536,20 +1649,15 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
        fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
        if (!fh) {
                em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+               mutex_unlock(&dev->lock);
                return -ENOMEM;
        }
-       mutex_lock(&dev->lock);
        fh->dev = dev;
        fh->radio = radio;
        fh->type = fh_type;
        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);
@@ -1557,12 +1665,12 @@ 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++;
@@ -1581,17 +1689,11 @@ 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 */
 
-       em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
-                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
-                               dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
-       list_del(&dev->devlist);
-       if (dev->sbutton_input_dev)
-               em28xx_deregister_snapshot_button(dev);
        if (dev->radio_dev) {
                if (-1 != dev->radio_dev->minor)
                        video_unregister_device(dev->radio_dev);
@@ -1600,6 +1702,8 @@ static void em28xx_release_resources(struct em28xx *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)
                        video_unregister_device(dev->vbi_dev);
                else
@@ -1607,17 +1711,14 @@ static void em28xx_release_resources(struct em28xx *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)
                        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);
 }
 
 /*
@@ -1625,7 +1726,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;
@@ -1634,11 +1735,10 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
        em28xx_videodbg("users=%d\n", dev->users);
 
 
+       mutex_lock(&dev->lock);
        if (res_check(fh))
                res_free(fh);
 
-       mutex_lock(&dev->lock);
-
        if (dev->users == 1) {
                videobuf_stop(&fh->vb_vidq);
                videobuf_mmap_free(&fh->vb_vidq);
@@ -1652,9 +1752,12 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
                        return 0;
                }
 
+               /* Save some power by putting tuner to sleep */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
+
                /* do this before setting alternate! */
                em28xx_uninit_isoc(dev);
-               em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+               em28xx_set_mode(dev, EM28XX_SUSPEND);
 
                /* set alternate 0 */
                dev->alt = 0;
@@ -1693,8 +1796,12 @@ 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)))
-                       return -EBUSY;
+               mutex_lock(&dev->lock);
+               rc = res_get(fh);
+               mutex_unlock(&dev->lock);
+
+               if (unlikely(rc < 0))
+                       return rc;
 
                return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
                                        filp->f_flags & O_NONBLOCK);
@@ -1706,7 +1813,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;
@@ -1716,7 +1823,11 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
        if (rc < 0)
                return rc;
 
-       if (unlikely(res_get(fh) < 0))
+       mutex_lock(&dev->lock);
+       rc = res_get(fh);
+       mutex_unlock(&dev->lock);
+
+       if (unlikely(rc < 0))
                return POLLERR;
 
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
@@ -1734,13 +1845,17 @@ 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;
 
+       mutex_lock(&dev->lock);
+       rc = res_get(fh);
+       mutex_unlock(&dev->lock);
+
+       if (unlikely(rc < 0))
+               return rc;
+
        rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 
        em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
@@ -1751,7 +1866,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,
@@ -1759,24 +1874,9 @@ 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 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 video_device em28xx_video_template = {
-       .fops                       = &em28xx_v4l_fops,
-       .release                    = video_device_release,
-
-       .minor                      = -1,
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_querycap            = vidioc_querycap,
        .vidioc_enum_fmt_vid_cap    = vidioc_enum_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
@@ -1810,20 +1910,32 @@ static const struct video_device em28xx_video_template = {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register          = vidioc_g_register,
        .vidioc_s_register          = vidioc_s_register,
+       .vidioc_g_chip_ident        = vidioc_g_chip_ident,
 #endif
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf                = vidiocgmbuf,
 #endif
+};
+
+static const struct video_device em28xx_video_template = {
+       .fops                       = &em28xx_v4l_fops,
+       .release                    = video_device_release,
+       .ioctl_ops                  = &video_ioctl_ops,
+
+       .minor                      = -1,
 
        .tvnorms                    = V4L2_STD_ALL,
        .current_norm               = V4L2_STD_PAL,
 };
 
-static struct video_device em28xx_radio_template = {
-       .name                 = "em28xx-radio",
-       .type                 = VID_TYPE_TUNER,
-       .fops                 = &radio_fops,
-       .minor                = -1,
+static const struct v4l2_file_operations radio_fops = {
+       .owner         = THIS_MODULE,
+       .open          = em28xx_v4l2_open,
+       .release       = em28xx_v4l2_close,
+       .ioctl         = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
        .vidioc_querycap      = radio_querycap,
        .vidioc_g_tuner       = radio_g_tuner,
        .vidioc_enum_input    = radio_enum_input,
@@ -1842,60 +1954,32 @@ static struct video_device em28xx_radio_template = {
 #endif
 };
 
-/******************************** 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_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);
-       return 0;
-}
-EXPORT_SYMBOL(em28xx_register_extension);
+static struct video_device em28xx_radio_template = {
+       .name                 = "em28xx-radio",
+       .fops                 = &radio_fops,
+       .ioctl_ops            = &radio_ioctl_ops,
+       .minor                = -1,
+};
 
-void em28xx_unregister_extension(struct em28xx_ops *ops)
-{
-       struct em28xx *dev = NULL;
+/******************************** usb interface ******************************/
 
-       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);
-}
-EXPORT_SYMBOL(em28xx_unregister_extension);
 
 static struct video_device *em28xx_vdev_init(struct em28xx *dev,
-                                            const struct video_device *template,
-                                            const int type,
-                                            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->type = type;
-       vfd->debug = video_debug;
+
+       *vfd            = *template;
+       vfd->minor      = -1;
+       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);
@@ -1903,398 +1987,90 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
        return vfd;
 }
 
+int em28xx_register_analog_devices(struct em28xx *dev)
+{
+      u8 val;
+       int ret;
 
-/*
- * 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);
-       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->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");
-               em28xx_devused &= ~(1<<dev->devno);
-               kfree(dev);
-               return -ENOMEM;
-       }
-
-       /* register i2c bus */
-       em28xx_i2c_register(dev);
-
-       /* Do board specific init and eeprom reading */
-       em28xx_card_setup(dev);
-
-       /* Configure audio */
-       em28xx_audio_analog_set(dev);
-
-       /* configure the device */
-       em28xx_config_i2c(dev);
+       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;
 
-       maxw = norm_maxw(dev);
-       maxh = norm_maxh(dev);
+       /* Analog specific initialization */
+       dev->format = &format[0];
+       em28xx_set_video_format(dev, format[0].fourcc,
+                               norm_maxw(dev), 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;
+       video_mux(dev, dev->ctl_input);
+
+       /* Audio defaults */
+       dev->mute = 1;
+       dev->volume = 0x1f;
+
+       /* enable vbi capturing */
 
-       errCode = em28xx_config(dev);
+/*     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_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
 
-       list_add_tail(&dev->devlist, &em28xx_devlist);
+       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,
-                                         VID_TYPE_CAPTURE, "video");
-       if (NULL == dev->vdev) {
+       dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
+       if (!dev->vdev) {
                em28xx_errdev("cannot allocate video_device.\n");
-               goto fail_unreg;
+               return -ENODEV;
        }
-       if (dev->tuner_type != TUNER_ABSENT)
-               dev->vdev->type |= VID_TYPE_TUNER;
 
        /* register v4l2 video video_device */
-       retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+       ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
                                       video_nr[dev->devno]);
-       if (retval) {
+       if (ret) {
                em28xx_errdev("unable to register video device (error=%i).\n",
-                             retval);
-               goto fail_unreg;
+                             ret);
+               return ret;
        }
 
        /* Allocate and fill vbi video_device struct */
-       dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
-                                         VFL_TYPE_VBI, "vbi");
+       dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi");
+
        /* register v4l2 vbi video_device */
-       if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
-                                       vbi_nr[dev->devno]) < 0) {
+       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");
-               retval = -ENODEV;
-               goto fail_unreg;
+               return ret;
        }
 
        if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
                dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
-                                       VFL_TYPE_RADIO, "radio");
-               if (NULL == dev->radio_dev) {
+                                                 "radio");
+               if (!dev->radio_dev) {
                        em28xx_errdev("cannot allocate video_device.\n");
-                       goto fail_unreg;
+                       return -ENODEV;
                }
-               retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+               ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
                                            radio_nr[dev->devno]);
-               if (retval < 0) {
+               if (ret < 0) {
                        em28xx_errdev("can't register radio device\n");
-                       goto fail_unreg;
+                       return ret;
                }
                em28xx_info("Registered radio device as /dev/radio%d\n",
-                           dev->radio_dev->minor & 0x1f);
-       }
-
-       /* init video dma queues */
-       INIT_LIST_HEAD(&dev->vidq.active);
-       INIT_LIST_HEAD(&dev->vidq.queued);
-
-
-       if (dev->has_msp34xx) {
-               /* Send a reset to other chips via gpio */
-               em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
-               msleep(3);
-               em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
-               msleep(3);
+                           dev->radio_dev->num);
        }
 
-       video_mux(dev, 0);
-
        em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
-                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
-                               dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
-
-       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);
+                               dev->vdev->num, dev->vbi_dev->num);
 
        return 0;
-
-fail_unreg:
-       em28xx_release_resources(dev);
-       mutex_unlock(&dev->lock);
-       kfree(dev);
-       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
-               request_module("em28xx-alsa");
-
-       if (dev->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;
-
-       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",
-                               udev->descriptor.idVendor,
-                               udev->descriptor.idProduct,
-                               ifnum,
-                               interface->altsetting[0].desc.bInterfaceClass);
-
-               em28xx_devused &= ~(1<<nr);
-               return -ENODEV;
-       }
-
-       em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
-                       udev->descriptor.idVendor,
-                       udev->descriptor.idProduct,
-                       ifnum,
-                       interface->altsetting[0].desc.bInterfaceClass);
-
-       endpoint = &interface->cur_altsetting->endpoint[1].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) {
-               em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
-               em28xx_devused &= ~(1<<nr);
-               return -ENODEV;
-       }
-       if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
-               em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
-               em28xx_devused &= ~(1<<nr);
-               return -ENODEV;
-       }
-
-       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;
-               }
-       }
-
-       printk(KERN_INFO DRIVER_NAME " %s usb audio class\n",
-                  dev->has_audio_class ? "Has" : "Doesn't have");
-
-       /* compute alternate max packet sizes */
-       uif = udev->actconfig->interface[0];
-
-       dev->num_alt = uif->num_altsetting;
-       em28xx_info("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[1].desc.
-                                                       wMaxPacketSize);
-               dev->alt_max_pkt_size[i] =
-                   (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
-               em28xx_info("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)
-               return retval;
-
-       em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
-
-       /* save our data pointer in this interface device */
-       usb_set_intfdata(interface, dev);
-
-       request_modules(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->minor-MINOR_VFL_TYPE_GRABBER_MIN);
-
-               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);