Staging: go7007: Convert driver to use video_ioctl2
authorMauro Carvalho Chehab <mchehab@infradead.org>
Wed, 12 Nov 2008 00:54:30 +0000 (22:54 -0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 6 Jan 2009 21:52:06 +0000 (13:52 -0800)
go7007: Convert driver to use video_ioctl2

go7007 driver were using the old method of having a big switch for handling
ioctls. Use instead the new video_ioctl2 method.

This patch also adds support for the 2.6.19 new ioctls to enumberate video
formats and intervals.

Still lacking the implementation of compression ioctls needed on go7007.

This patch weren't tested, due to the lack of a hardware with me.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/go7007/go7007-v4l2.c

index e0b17a0..7717fef 100644 (file)
@@ -600,526 +600,584 @@ static int mpeg_g_control(struct v4l2_control *ctrl, struct go7007 *go)
        return 0;
 }
 
-static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int vidioc_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
 {
-       struct go7007_file *gofh = file->private_data;
+       struct go7007_file *gofh = priv;
        struct go7007 *go = gofh->go;
-       unsigned long flags;
-       int retval = 0;
 
-       switch (cmd) {
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-
-               memset(cap, 0, sizeof(*cap));
-               strcpy(cap->driver, "go7007");
-               strncpy(cap->card, go->name, sizeof(cap->card));
-               cap->version = KERNEL_VERSION(0, 9, 8);
-               cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-                               V4L2_CAP_STREAMING | V4L2_CAP_AUDIO;
-               if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
-                       cap->capabilities |= V4L2_CAP_TUNER;
-               return 0;
-       }
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *fmt = arg;
-               unsigned int index;
-               char *desc;
-               u32 pixelformat;
+       strlcpy(cap->driver, "go7007", sizeof(cap->driver));
+       strlcpy(cap->card, go->name, sizeof(cap->card));
+#if 0
+       strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
+#endif
 
-               if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               switch (fmt->index) {
-               case 0:
-                       pixelformat = V4L2_PIX_FMT_MJPEG;
-                       desc = "Motion-JPEG";
-                       break;
-               case 1:
-                       pixelformat = V4L2_PIX_FMT_MPEG;
-                       desc = "MPEG1/MPEG2/MPEG4";
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               index = fmt->index;
-               memset(fmt, 0, sizeof(*fmt));
-               fmt->index = index;
-               fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               fmt->flags = V4L2_FMT_FLAG_COMPRESSED;
-               strncpy(fmt->description, desc, sizeof(fmt->description));
-               fmt->pixelformat = pixelformat;
+       cap->version = KERNEL_VERSION(0, 9, 8);
 
-               return 0;
-       }
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *fmt = arg;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+                           V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */
 
-               if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               return set_capture_size(go, fmt, 1);
-       }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *fmt = arg;
+       if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
+               cap->capabilities |= V4L2_CAP_TUNER;
 
-               if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               memset(fmt, 0, sizeof(*fmt));
-               fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               fmt->fmt.pix.width = go->width;
-               fmt->fmt.pix.height = go->height;
-               fmt->fmt.pix.pixelformat = go->format == GO7007_FORMAT_MJPEG ?
-                       V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG;
-               fmt->fmt.pix.field = V4L2_FIELD_NONE;
-               fmt->fmt.pix.bytesperline = 0;
-               fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
-               fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */
-               return 0;
-       }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *fmt = arg;
+       return 0;
+}
 
-               if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               if (go->streaming)
-                       return -EBUSY;
-               return set_capture_size(go, fmt, 0);
-       }
-       case VIDIOC_ENUMAUDIO:
-       case VIDIOC_G_AUDIO:
-       case VIDIOC_S_AUDIO:
-       {
-               struct v4l2_audio *audio = arg;
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *fmt)
+{
+       char *desc = NULL;
 
-               if (!go->i2c_adapter_online)
-                       return -EIO;
-               i2c_clients_command(&go->i2c_adapter, cmd, arg);
-               if (cmd == VIDIOC_ENUMAUDIO && !audio->name[0])
-                       return -EINVAL;
-               return 0;
-       }
-       case VIDIOC_G_FBUF:
-       case VIDIOC_S_FBUF:
+       switch (fmt->index) {
+       case 0:
+               fmt->pixelformat = V4L2_PIX_FMT_MJPEG;
+               desc = "Motion-JPEG";
+               break;
+       case 1:
+               fmt->pixelformat = V4L2_PIX_FMT_MPEG;
+               desc = "MPEG1/MPEG2/MPEG4";
+               break;
+       default:
                return -EINVAL;
-       case VIDIOC_REQBUFS:
-       {
-               struct v4l2_requestbuffers *req = arg;
-               unsigned int count, i;
+       }
+       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt->flags = V4L2_FMT_FLAG_COMPRESSED;
 
-               if (go->streaming)
-                       return -EBUSY;
-               if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                               req->memory != V4L2_MEMORY_MMAP)
-                       return -EINVAL;
+       strncpy(fmt->description, desc, sizeof(fmt->description));
 
-               down(&gofh->lock);
-               retval = -EBUSY;
-               for (i = 0; i < gofh->buf_count; ++i)
-                       if (gofh->bufs[i].mapped > 0)
-                               goto unlock_and_return;
-               down(&go->hw_lock);
-               if (go->in_use > 0 && gofh->buf_count == 0) {
-                       up(&go->hw_lock);
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *fmt)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt->fmt.pix.width = go->width;
+       fmt->fmt.pix.height = go->height;
+       fmt->fmt.pix.pixelformat = (go->format == GO7007_FORMAT_MJPEG) ?
+                                  V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG;
+       fmt->fmt.pix.field = V4L2_FIELD_NONE;
+       fmt->fmt.pix.bytesperline = 0;
+       fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
+       fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *fmt)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       return set_capture_size(go, fmt, 1);
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *fmt)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (go->streaming)
+               return -EBUSY;
+
+       return set_capture_size(go, fmt, 0);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *req)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       int retval = -EBUSY;
+       unsigned int count, i;
+
+       if (go->streaming)
+               return retval;
+
+       if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                       req->memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       down(&gofh->lock);
+       for (i = 0; i < gofh->buf_count; ++i)
+               if (gofh->bufs[i].mapped > 0)
                        goto unlock_and_return;
-               }
-               if (gofh->buf_count > 0)
-                       kfree(gofh->bufs);
-               retval = -ENOMEM;
-               count = req->count;
-               if (count > 0) {
-                       if (count < 2)
-                               count = 2;
-                       if (count > 32)
-                               count = 32;
-                       gofh->bufs = kmalloc(count *
-                                               sizeof(struct go7007_buffer),
-                                       GFP_KERNEL);
-                       if (gofh->bufs == NULL) {
-                               up(&go->hw_lock);
-                               goto unlock_and_return;
-                       }
-                       memset(gofh->bufs, 0,
-                                       count * sizeof(struct go7007_buffer));
-                       for (i = 0; i < count; ++i) {
-                               gofh->bufs[i].go = go;
-                               gofh->bufs[i].index = i;
-                               gofh->bufs[i].state = BUF_STATE_IDLE;
-                               gofh->bufs[i].mapped = 0;
-                       }
-                       go->in_use = 1;
-               } else {
-                       go->in_use = 0;
-               }
-               gofh->buf_count = count;
+
+       down(&go->hw_lock);
+       if (go->in_use > 0 && gofh->buf_count == 0) {
                up(&go->hw_lock);
-               up(&gofh->lock);
-               memset(req, 0, sizeof(*req));
-               req->count = count;
-               req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               req->memory = V4L2_MEMORY_MMAP;
-               return 0;
+               goto unlock_and_return;
        }
-       case VIDIOC_QUERYBUF:
-       {
-               struct v4l2_buffer *buf = arg;
-               unsigned int index;
 
-               retval = -EINVAL;
-               if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               index = buf->index;
-               down(&gofh->lock);
-               if (index >= gofh->buf_count)
-                       goto unlock_and_return;
-               memset(buf, 0, sizeof(*buf));
-               buf->index = index;
-               buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               switch (gofh->bufs[index].state) {
-               case BUF_STATE_QUEUED:
-                       buf->flags = V4L2_BUF_FLAG_QUEUED;
-                       break;
-               case BUF_STATE_DONE:
-                       buf->flags = V4L2_BUF_FLAG_DONE;
-                       break;
-               default:
-                       buf->flags = 0;
-               }
-               if (gofh->bufs[index].mapped)
-                       buf->flags |= V4L2_BUF_FLAG_MAPPED;
-               buf->memory = V4L2_MEMORY_MMAP;
-               buf->m.offset = index * GO7007_BUF_SIZE;
-               buf->length = GO7007_BUF_SIZE;
-               up(&gofh->lock);
+       if (gofh->buf_count > 0)
+               kfree(gofh->bufs);
 
-               return 0;
-       }
-       case VIDIOC_QBUF:
-       {
-               struct v4l2_buffer *buf = arg;
-               struct go7007_buffer *gobuf;
-               int ret;
+       retval = -ENOMEM;
+       count = req->count;
+       if (count > 0) {
+               if (count < 2)
+                       count = 2;
+               if (count > 32)
+                       count = 32;
 
-               retval = -EINVAL;
-               if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                               buf->memory != V4L2_MEMORY_MMAP)
-                       return -EINVAL;
-               down(&gofh->lock);
-               if (buf->index < 0 || buf->index >= gofh->buf_count)
-                       goto unlock_and_return;
-               gobuf = &gofh->bufs[buf->index];
-               if (gobuf->mapped == 0)
-                       goto unlock_and_return;
-               retval = -EBUSY;
-               if (gobuf->state != BUF_STATE_IDLE)
-                       goto unlock_and_return;
-               /* offset will be 0 until we really support USERPTR streaming */
-               gobuf->offset = gobuf->user_addr & ~PAGE_MASK;
-               gobuf->bytesused = 0;
-               gobuf->frame_offset = 0;
-               gobuf->modet_active = 0;
-               if (gobuf->offset > 0)
-                       gobuf->page_count = GO7007_BUF_PAGES + 1;
-               else
-                       gobuf->page_count = GO7007_BUF_PAGES;
-               retval = -ENOMEM;
-               down_read(&current->mm->mmap_sem);
-               ret = get_user_pages(current, current->mm,
-                               gobuf->user_addr & PAGE_MASK, gobuf->page_count,
-                               1, 1, gobuf->pages, NULL);
-               up_read(&current->mm->mmap_sem);
-               if (ret != gobuf->page_count) {
-                       int i;
-                       for (i = 0; i < ret; ++i)
-                               page_cache_release(gobuf->pages[i]);
-                       gobuf->page_count = 0;
+               gofh->bufs = kmalloc(count * sizeof(struct go7007_buffer),
+                                    GFP_KERNEL);
+
+               if (!gofh->bufs) {
+                       up(&go->hw_lock);
                        goto unlock_and_return;
                }
-               gobuf->state = BUF_STATE_QUEUED;
-               spin_lock_irqsave(&go->spinlock, flags);
-               list_add_tail(&gobuf->stream, &go->stream);
-               spin_unlock_irqrestore(&go->spinlock, flags);
-               up(&gofh->lock);
-               return 0;
-       }
-       case VIDIOC_DQBUF:
-       {
-               struct v4l2_buffer *buf = arg;
-               struct go7007_buffer *gobuf;
-               u32 frame_type_flag;
-               DEFINE_WAIT(wait);
 
-               if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               if (buf->memory != V4L2_MEMORY_MMAP)
-                       return -EINVAL;
-               down(&gofh->lock);
-               retval = -EINVAL;
-               if (list_empty(&go->stream))
-                       goto unlock_and_return;
-               gobuf = list_entry(go->stream.next,
-                               struct go7007_buffer, stream);
-               retval = -EAGAIN;
-               if (gobuf->state != BUF_STATE_DONE &&
-                               !(file->f_flags & O_NONBLOCK)) {
-                       for (;;) {
-                               prepare_to_wait(&go->frame_waitq, &wait,
-                                               TASK_INTERRUPTIBLE);
-                               if (gobuf->state == BUF_STATE_DONE)
-                                       break;
-                               if (signal_pending(current)) {
-                                       retval = -ERESTARTSYS;
-                                       break;
-                               }
-                               schedule();
-                       }
-                       finish_wait(&go->frame_waitq, &wait);
+               memset(gofh->bufs, 0, count * sizeof(struct go7007_buffer));
+
+               for (i = 0; i < count; ++i) {
+                       gofh->bufs[i].go = go;
+                       gofh->bufs[i].index = i;
+                       gofh->bufs[i].state = BUF_STATE_IDLE;
+                       gofh->bufs[i].mapped = 0;
                }
-               if (gobuf->state != BUF_STATE_DONE)
-                       goto unlock_and_return;
-               spin_lock_irqsave(&go->spinlock, flags);
-               deactivate_buffer(gobuf);
-               spin_unlock_irqrestore(&go->spinlock, flags);
-               frame_type_flag = get_frame_type_flag(gobuf, go->format);
-               gobuf->state = BUF_STATE_IDLE;
-               memset(buf, 0, sizeof(*buf));
-               buf->index = gobuf->index;
-               buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               buf->bytesused = gobuf->bytesused;
-               buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag;
-               buf->field = V4L2_FIELD_NONE;
-               buf->timestamp = gobuf->timestamp;
-               buf->sequence = gobuf->seq;
-               buf->memory = V4L2_MEMORY_MMAP;
-               buf->m.offset = gobuf->index * GO7007_BUF_SIZE;
-               buf->length = GO7007_BUF_SIZE;
-               buf->reserved = gobuf->modet_active;
-               up(&gofh->lock);
-               return 0;
+
+               go->in_use = 1;
+       } else {
+               go->in_use = 0;
        }
-       case VIDIOC_STREAMON:
-       {
-               unsigned int *type = arg;
 
-               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               down(&gofh->lock);
-               down(&go->hw_lock);
-               if (!go->streaming) {
-                       go->streaming = 1;
-                       go->next_seq = 0;
-                       go->active_buf = NULL;
-                       if (go7007_start_encoder(go) < 0)
-                               retval = -EIO;
-                       else
-                               retval = 0;
-               }
-               up(&go->hw_lock);
-               up(&gofh->lock);
+       gofh->buf_count = count;
+       up(&go->hw_lock);
+       up(&gofh->lock);
+
+       memset(req, 0, sizeof(*req));
+
+       req->count = count;
+       req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       req->memory = V4L2_MEMORY_MMAP;
+
+       return 0;
+
+unlock_and_return:
+       up(&gofh->lock);
+       return retval;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *buf)
+{
+       struct go7007_file *gofh = priv;
+       int retval = -EINVAL;
+       unsigned int index;
+
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return retval;
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               unsigned int *type = arg;
 
-               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               down(&gofh->lock);
-               go7007_streamoff(go);
-               up(&gofh->lock);
-               return 0;
-       }
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *ctrl = arg;
-               u32 id;
+       index = buf->index;
 
-               id = ctrl->id;
-               memset(ctrl, 0, sizeof(*ctrl));
-               ctrl->id = id;
-               if (go->i2c_adapter_online)
-                       i2c_clients_command(&go->i2c_adapter,
-                                               VIDIOC_QUERYCTRL, arg);
-               else if (go->hpi_ops && go->hpi_ops->send_command)
-                       go->hpi_ops->send_command(go, cmd, arg);
-               if (id & V4L2_CTRL_FLAG_NEXT_CTRL || ctrl->name[0] == 0)
-                       return mpeg_queryctrl(id, ctrl);
-               return ctrl->name[0] == 0 ? -EINVAL : 0;
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-               struct v4l2_queryctrl query;
+       down(&gofh->lock);
+       if (index >= gofh->buf_count)
+               goto unlock_and_return;
 
-               memset(&query, 0, sizeof(query));
-               query.id = ctrl->id;
-               if (go->i2c_adapter_online)
-                       i2c_clients_command(&go->i2c_adapter,
-                                               VIDIOC_QUERYCTRL, &query);
-               else if (go->hpi_ops && go->hpi_ops->send_command)
-                       if (0 == go->hpi_ops->send_command(go, cmd, arg))
-                               return 0;
-               if (query.name[0] == 0)
-                       return mpeg_g_control(ctrl, go);
-               i2c_clients_command(&go->i2c_adapter, VIDIOC_G_CTRL, arg);
-               return 0;
+       memset(buf, 0, sizeof(*buf));
+       buf->index = index;
+       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       switch (gofh->bufs[index].state) {
+       case BUF_STATE_QUEUED:
+               buf->flags = V4L2_BUF_FLAG_QUEUED;
+               break;
+       case BUF_STATE_DONE:
+               buf->flags = V4L2_BUF_FLAG_DONE;
+               break;
+       default:
+               buf->flags = 0;
        }
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-               struct v4l2_queryctrl query;
 
-               memset(&query, 0, sizeof(query));
-               query.id = ctrl->id;
-               if (go->i2c_adapter_online)
-                       i2c_clients_command(&go->i2c_adapter,
-                                               VIDIOC_QUERYCTRL, &query);
-               else if (go->hpi_ops && go->hpi_ops->send_command)
-                       if (0 == go->hpi_ops->send_command(go, cmd, arg))
-                               return 0;
-               if (query.name[0] == 0)
-                       return mpeg_s_control(ctrl, go);
-               i2c_clients_command(&go->i2c_adapter, VIDIOC_S_CTRL, arg);
-               return 0;
+       if (gofh->bufs[index].mapped)
+               buf->flags |= V4L2_BUF_FLAG_MAPPED;
+       buf->memory = V4L2_MEMORY_MMAP;
+       buf->m.offset = index * GO7007_BUF_SIZE;
+       buf->length = GO7007_BUF_SIZE;
+       up(&gofh->lock);
+
+       return 0;
+
+unlock_and_return:
+       up(&gofh->lock);
+       return retval;
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       struct go7007_buffer *gobuf;
+       unsigned long flags;
+       int retval = -EINVAL;
+       int ret;
+
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                       buf->memory != V4L2_MEMORY_MMAP)
+               return retval;
+
+       down(&gofh->lock);
+       if (buf->index < 0 || buf->index >= gofh->buf_count)
+               goto unlock_and_return;
+
+       gobuf = &gofh->bufs[buf->index];
+       if (!gobuf->mapped)
+               goto unlock_and_return;
+
+       retval = -EBUSY;
+       if (gobuf->state != BUF_STATE_IDLE)
+               goto unlock_and_return;
+
+       /* offset will be 0 until we really support USERPTR streaming */
+       gobuf->offset = gobuf->user_addr & ~PAGE_MASK;
+       gobuf->bytesused = 0;
+       gobuf->frame_offset = 0;
+       gobuf->modet_active = 0;
+       if (gobuf->offset > 0)
+               gobuf->page_count = GO7007_BUF_PAGES + 1;
+       else
+               gobuf->page_count = GO7007_BUF_PAGES;
+
+       retval = -ENOMEM;
+       down_read(&current->mm->mmap_sem);
+       ret = get_user_pages(current, current->mm,
+                       gobuf->user_addr & PAGE_MASK, gobuf->page_count,
+                       1, 1, gobuf->pages, NULL);
+       up_read(&current->mm->mmap_sem);
+
+       if (ret != gobuf->page_count) {
+               int i;
+               for (i = 0; i < ret; ++i)
+                       page_cache_release(gobuf->pages[i]);
+               gobuf->page_count = 0;
+               goto unlock_and_return;
        }
-       case VIDIOC_G_PARM:
-       {
-               struct v4l2_streamparm *parm = arg;
-               struct v4l2_fract timeperframe = {
-                       .numerator = 1001 *  go->fps_scale,
-                       .denominator = go->sensor_framerate,
-               };
 
-               if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               memset(parm, 0, sizeof(*parm));
-               parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
-               parm->parm.capture.timeperframe = timeperframe;
-               return 0;
+       gobuf->state = BUF_STATE_QUEUED;
+       spin_lock_irqsave(&go->spinlock, flags);
+       list_add_tail(&gobuf->stream, &go->stream);
+       spin_unlock_irqrestore(&go->spinlock, flags);
+       up(&gofh->lock);
+
+       return 0;
+
+unlock_and_return:
+       up(&gofh->lock);
+       return retval;
+}
+
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       struct go7007_buffer *gobuf;
+       int retval = -EINVAL;
+       unsigned long flags;
+       u32 frame_type_flag;
+       DEFINE_WAIT(wait);
+
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return retval;
+       if (buf->memory != V4L2_MEMORY_MMAP)
+               return retval;
+
+       down(&gofh->lock);
+       if (list_empty(&go->stream))
+               goto unlock_and_return;
+       gobuf = list_entry(go->stream.next,
+                       struct go7007_buffer, stream);
+
+       retval = -EAGAIN;
+       if (gobuf->state != BUF_STATE_DONE &&
+                       !(file->f_flags & O_NONBLOCK)) {
+               for (;;) {
+                       prepare_to_wait(&go->frame_waitq, &wait,
+                                       TASK_INTERRUPTIBLE);
+                       if (gobuf->state == BUF_STATE_DONE)
+                               break;
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+               }
+               finish_wait(&go->frame_waitq, &wait);
+       }
+       if (gobuf->state != BUF_STATE_DONE)
+               goto unlock_and_return;
+
+       spin_lock_irqsave(&go->spinlock, flags);
+       deactivate_buffer(gobuf);
+       spin_unlock_irqrestore(&go->spinlock, flags);
+       frame_type_flag = get_frame_type_flag(gobuf, go->format);
+       gobuf->state = BUF_STATE_IDLE;
+
+       memset(buf, 0, sizeof(*buf));
+       buf->index = gobuf->index;
+       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       buf->bytesused = gobuf->bytesused;
+       buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag;
+       buf->field = V4L2_FIELD_NONE;
+       buf->timestamp = gobuf->timestamp;
+       buf->sequence = gobuf->seq;
+       buf->memory = V4L2_MEMORY_MMAP;
+       buf->m.offset = gobuf->index * GO7007_BUF_SIZE;
+       buf->length = GO7007_BUF_SIZE;
+       buf->reserved = gobuf->modet_active;
+
+       up(&gofh->lock);
+       return 0;
+
+unlock_and_return:
+       up(&gofh->lock);
+       return retval;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       int retval = 0;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       down(&gofh->lock);
+       down(&go->hw_lock);
+
+       if (!go->streaming) {
+               go->streaming = 1;
+               go->next_seq = 0;
+               go->active_buf = NULL;
+               if (go7007_start_encoder(go) < 0)
+                       retval = -EIO;
+               else
+                       retval = 0;
        }
-       case VIDIOC_S_PARM:
-       {
-               struct v4l2_streamparm *parm = arg;
-               unsigned int n, d;
+       up(&go->hw_lock);
+       up(&gofh->lock);
 
-               if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               if (parm->parm.capture.capturemode != 0)
+       return retval;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       down(&gofh->lock);
+       go7007_streamoff(go);
+       up(&gofh->lock);
+
+       return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+                          struct v4l2_queryctrl *query)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, query);
+
+       return (!query->name[0]) ? -EINVAL : 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       struct v4l2_queryctrl query;
+
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       memset(&query, 0, sizeof(query));
+       query.id = ctrl->id;
+       i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
+       if (query.name[0] == 0)
+               return -EINVAL;
+       i2c_clients_command(&go->i2c_adapter, VIDIOC_G_CTRL, ctrl);
+
+       return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       struct v4l2_queryctrl query;
+
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       memset(&query, 0, sizeof(query));
+       query.id = ctrl->id;
+       i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
+       if (query.name[0] == 0)
+               return -EINVAL;
+       i2c_clients_command(&go->i2c_adapter, VIDIOC_S_CTRL, ctrl);
+
+       return 0;
+}
+
+static int vidioc_g_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parm)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       struct v4l2_fract timeperframe = {
+               .numerator = 1001 *  go->fps_scale,
+               .denominator = go->sensor_framerate,
+       };
+
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
+       parm->parm.capture.timeperframe = timeperframe;
+
+       return 0;
+}
+
+static int vidioc_s_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parm)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       unsigned int n, d;
+
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (parm->parm.capture.capturemode != 0)
+               return -EINVAL;
+
+       n = go->sensor_framerate *
+               parm->parm.capture.timeperframe.numerator;
+       d = 1001 * parm->parm.capture.timeperframe.denominator;
+       if (n != 0 && d != 0 && n > d)
+               go->fps_scale = (n + d/2) / d;
+       else
+               go->fps_scale = 1;
+
+       return 0;
+}
+
+/* VIDIOC_ENUMSTD on go7007 were used for enumberating the supported fps and
+   its resolution, when the device is not connected to TV.
+   This were an API abuse, probably used by the lack of specific IOCTL's to
+   enumberate it, by the time the driver were written.
+
+   However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS
+   and VIDIOC_ENUM_FRAMESIZES) were added for this purpose.
+
+   The two functions bellow implements the newer ioctls
+*/
+
+static int vidioc_enum_framesizes(struct file *filp, void *priv,
+                                 struct v4l2_frmsizeenum *fsize)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       /* Return -EINVAL, if it is a TV board */
+       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
+           (go->board_info->sensor_flags & GO7007_SENSOR_TV))
+               return -EINVAL;
+
+       if (fsize->index > 0)
+               return -EINVAL;
+
+       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+       fsize->discrete.width = go->board_info->sensor_width;
+       fsize->discrete.height = go->board_info->sensor_height;
+
+       return 0;
+}
+
+static int vidioc_enum_frameintervals(struct file *filp, void *priv,
+                                     struct v4l2_frmivalenum *fival)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       /* Return -EINVAL, if it is a TV board */
+       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
+           (go->board_info->sensor_flags & GO7007_SENSOR_TV))
+               return -EINVAL;
+
+       if (fival->index > 0)
+               return -EINVAL;
+
+       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+       fival->discrete.numerator = 1001;
+       fival->discrete.denominator = go->board_info->sensor_framerate;
+
+       return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (go->streaming)
+               return -EBUSY;
+
+       if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) &&
+                       *std != 0)
+               return -EINVAL;
+
+       if (*std == 0)
+               return -EINVAL;
+
+       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+                       go->input == go->board_info->num_inputs - 1) {
+               if (!go->i2c_adapter_online)
+                       return -EIO;
+               i2c_clients_command(&go->i2c_adapter,
+                                       VIDIOC_S_STD, std);
+               if (!*std) /* hack to indicate EINVAL from tuner */
                        return -EINVAL;
-               n = go->sensor_framerate *
-                       parm->parm.capture.timeperframe.numerator;
-               d = 1001 * parm->parm.capture.timeperframe.denominator;
-               if (n != 0 && d != 0 && n > d)
-                       go->fps_scale = (n + d/2) / d;
-               else
-                       go->fps_scale = 1;
-               return 0;
        }
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *std = arg;
 
-               if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
-                               go->input == go->board_info->num_inputs - 1) {
-                       if (!go->i2c_adapter_online)
-                               return -EIO;
-                       i2c_clients_command(&go->i2c_adapter,
-                                               VIDIOC_ENUMSTD, arg);
-                       if (!std->id) /* hack to indicate EINVAL from tuner */
-                               return -EINVAL;
-               } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
-                       switch (std->index) {
-                       case 0:
-                               v4l2_video_std_construct(std,
-                                               V4L2_STD_NTSC, "NTSC");
-                               break;
-                       case 1:
-                               v4l2_video_std_construct(std,
-                                               V4L2_STD_PAL | V4L2_STD_SECAM,
-                                               "PAL/SECAM");
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-               } else {
-                       if (std->index != 0)
-                               return -EINVAL;
-                       memset(std, 0, sizeof(*std));
-                       snprintf(std->name, sizeof(std->name), "%dx%d, %dfps",
-                               go->board_info->sensor_width,
-                               go->board_info->sensor_height,
-                               go->board_info->sensor_framerate / 1000);
-                       std->frameperiod.numerator = 1001;
-                       std->frameperiod.denominator =
-                                       go->board_info->sensor_framerate;
-               }
-               return 0;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *std = arg;
+       if (*std & V4L2_STD_NTSC) {
+               go->standard = GO7007_STD_NTSC;
+               go->sensor_framerate = 30000;
+       } else if (*std & V4L2_STD_PAL) {
+               go->standard = GO7007_STD_PAL;
+               go->sensor_framerate = 25025;
+       } else if (*std & V4L2_STD_SECAM) {
+               go->standard = GO7007_STD_PAL;
+               go->sensor_framerate = 25025;
+       } else
+               return -EINVAL;
 
-               if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
-                               go->input == go->board_info->num_inputs - 1) {
-                       if (!go->i2c_adapter_online)
-                               return -EIO;
-                       i2c_clients_command(&go->i2c_adapter,
-                                               VIDIOC_G_STD, arg);
-               } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
-                       if (go->standard == GO7007_STD_NTSC)
-                               *std = V4L2_STD_NTSC;
-                       else
-                               *std = V4L2_STD_PAL | V4L2_STD_SECAM;
-               } else if (go->hpi_ops && go->hpi_ops->send_command) {
-                       go->hpi_ops->send_command(go, cmd, arg);
-               } else
-                       *std = 0;
-               return 0;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *std = arg;
+       if (go->i2c_adapter_online)
+               i2c_clients_command(&go->i2c_adapter,
+                                       VIDIOC_S_STD, std);
+       set_capture_size(go, NULL, 0);
 
-               if (go->streaming)
-                       return -EBUSY;
-               if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) &&
-                               *std != 0)
-                       return -EINVAL;
-               if (*std == 0)
-                       return -EINVAL;
-               if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
-                               go->input == go->board_info->num_inputs - 1) {
-                       if (!go->i2c_adapter_online)
-                               return -EIO;
-                       i2c_clients_command(&go->i2c_adapter,
-                                               VIDIOC_S_STD, arg);
-                       if (!*std) /* hack to indicate EINVAL from tuner */
-                               return -EINVAL;
-               }
-               if (*std & V4L2_STD_NTSC) {
-                       go->standard = GO7007_STD_NTSC;
-                       go->sensor_framerate = 30000;
-               } else if (*std & V4L2_STD_PAL) {
-                       go->standard = GO7007_STD_PAL;
-                       go->sensor_framerate = 25025;
-               } else if (*std & V4L2_STD_SECAM) {
-                       go->standard = GO7007_STD_PAL;
-                       go->sensor_framerate = 25025;
-               } else
-                       return -EINVAL;
-               if (go->i2c_adapter_online)
-                       i2c_clients_command(&go->i2c_adapter,
-                                           VIDIOC_S_STD, std);
-               if (go->hpi_ops && go->hpi_ops->send_command)
-                       go->hpi_ops->send_command(go, cmd, arg);
+       return 0;
+}
 
-               set_capture_size(go, NULL, 0);
-               return 0;
-       }
+#if 0
        case VIDIOC_QUERYSTD:
        {
                v4l2_std_id *std = arg;
@@ -1136,219 +1194,269 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        *std = 0;
                return 0;
        }
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *inp = arg;
-               int index;
+#endif
 
-               if (inp->index >= go->board_info->num_inputs)
-                       return -EINVAL;
-               index = inp->index;
-               memset(inp, 0, sizeof(*inp));
-               inp->index = index;
-               strncpy(inp->name, go->board_info->inputs[index].name,
-                               sizeof(inp->name));
-               /* If this board has a tuner, it will be the last input */
-               if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
-                               index == go->board_info->num_inputs - 1)
-                       inp->type = V4L2_INPUT_TYPE_TUNER;
-               else
-                       inp->type = V4L2_INPUT_TYPE_CAMERA;
-               inp->audioset = 0;
-               inp->tuner = 0;
-               if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
-                       inp->std = V4L2_STD_NTSC | V4L2_STD_PAL |
-                                                       V4L2_STD_SECAM;
-               else
-                       inp->std = 0;
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *input = arg;
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *inp)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
 
-               *input = go->input;
-               return 0;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               int *input = arg;
+       if (inp->index >= go->board_info->num_inputs)
+               return -EINVAL;
 
-               if (*input >= go->board_info->num_inputs)
-                       return -EINVAL;
-               if (go->streaming)
-                       return -EBUSY;
-               go->input = *input;
-               if (go->i2c_adapter_online) {
-                       i2c_clients_command(&go->i2c_adapter, VIDIOC_S_INPUT,
-                               &go->board_info->inputs[*input].video_input);
-                       i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO,
-                               &go->board_info->inputs[*input].audio_input);
-               }
-               return 0;
-       }
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       strncpy(inp->name, go->board_info->inputs[inp->index].name,
+                       sizeof(inp->name));
 
-               if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
-                       return -EINVAL;
-               if (t->index != 0)
-                       return -EINVAL;
-               if (!go->i2c_adapter_online)
-                       return -EIO;
-               i2c_clients_command(&go->i2c_adapter, VIDIOC_G_TUNER, arg);
-               t->index = 0;
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
+       /* If this board has a tuner, it will be the last input */
+       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+                       inp->index == go->board_info->num_inputs - 1)
+               inp->type = V4L2_INPUT_TYPE_TUNER;
+       else
+               inp->type = V4L2_INPUT_TYPE_CAMERA;
 
-               if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
-                       return -EINVAL;
-               if (t->index != 0)
-                       return -EINVAL;
-               if (!go->i2c_adapter_online)
-                       return -EIO;
-               switch (go->board_id) {
-               case GO7007_BOARDID_PX_TV402U_NA:
-               case GO7007_BOARDID_PX_TV402U_JP:
-                       /* No selectable options currently */
-                       if (t->audmode != V4L2_TUNER_MODE_STEREO)
-                               return -EINVAL;
-                       break;
-               }
-               i2c_clients_command(&go->i2c_adapter, VIDIOC_S_TUNER, arg);
-               return 0;
-       }
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
+       inp->audioset = 0;
+       inp->tuner = 0;
+       if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
+               inp->std = V4L2_STD_NTSC | V4L2_STD_PAL |
+                                               V4L2_STD_SECAM;
+       else
+               inp->std = 0;
 
-               if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
-                       return -EINVAL;
-               if (!go->i2c_adapter_online)
-                       return -EIO;
-               memset(f, 0, sizeof(*f));
-               f->type = V4L2_TUNER_ANALOG_TV;
-               i2c_clients_command(&go->i2c_adapter, VIDIOC_G_FREQUENCY, arg);
-               return 0;
-       }
-       case VIDIOC_S_FREQUENCY:
-       {
-               if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
-                       return -EINVAL;
-               if (!go->i2c_adapter_online)
-                       return -EIO;
-               i2c_clients_command(&go->i2c_adapter, VIDIOC_S_FREQUENCY, arg);
-               return 0;
-       }
-       case VIDIOC_CROPCAP:
-       {
-               struct v4l2_cropcap *cropcap = arg;
+       return 0;
+}
 
-               if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               memset(cropcap, 0, sizeof(*cropcap));
-               cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               /* These specify the raw input of the sensor */
-               switch (go->standard) {
-               case GO7007_STD_NTSC:
-                       cropcap->bounds.top = 0;
-                       cropcap->bounds.left = 0;
-                       cropcap->bounds.width = 720;
-                       cropcap->bounds.height = 480;
-                       cropcap->defrect.top = 0;
-                       cropcap->defrect.left = 0;
-                       cropcap->defrect.width = 720;
-                       cropcap->defrect.height = 480;
-                       break;
-               case GO7007_STD_PAL:
-                       cropcap->bounds.top = 0;
-                       cropcap->bounds.left = 0;
-                       cropcap->bounds.width = 720;
-                       cropcap->bounds.height = 576;
-                       cropcap->defrect.top = 0;
-                       cropcap->defrect.left = 0;
-                       cropcap->defrect.width = 720;
-                       cropcap->defrect.height = 576;
-                       break;
-               case GO7007_STD_OTHER:
-                       cropcap->bounds.top = 0;
-                       cropcap->bounds.left = 0;
-                       cropcap->bounds.width = go->board_info->sensor_width;
-                       cropcap->bounds.height = go->board_info->sensor_height;
-                       cropcap->defrect.top = 0;
-                       cropcap->defrect.left = 0;
-                       cropcap->defrect.width = go->board_info->sensor_width;
-                       cropcap->defrect.height = go->board_info->sensor_height;
-                       break;
-               }
 
-               return 0;
-       }
-       case VIDIOC_G_CROP:
-       {
-               struct v4l2_crop *crop = arg;
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
 
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               memset(crop, 0, sizeof(*crop));
-               crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               /* These specify the raw input of the sensor */
-               switch (go->standard) {
-               case GO7007_STD_NTSC:
-                       crop->c.top = 0;
-                       crop->c.left = 0;
-                       crop->c.width = 720;
-                       crop->c.height = 480;
-                       break;
-               case GO7007_STD_PAL:
-                       crop->c.top = 0;
-                       crop->c.left = 0;
-                       crop->c.width = 720;
-                       crop->c.height = 576;
-                       break;
-               case GO7007_STD_OTHER:
-                       crop->c.top = 0;
-                       crop->c.left = 0;
-                       crop->c.width = go->board_info->sensor_width;
-                       crop->c.height = go->board_info->sensor_height;
-                       break;
-               }
+       *input = go->input;
 
-               return 0;
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (input >= go->board_info->num_inputs)
+               return -EINVAL;
+       if (go->streaming)
+               return -EBUSY;
+
+       go->input = input;
+       if (go->i2c_adapter_online) {
+               i2c_clients_command(&go->i2c_adapter, VIDIOC_S_INPUT,
+                       &go->board_info->inputs[input].video_input);
+               i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO,
+                       &go->board_info->inputs[input].audio_input);
        }
-       case VIDIOC_S_CROP:
-       {
-               struct v4l2_crop *crop = arg;
 
-               if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+               return -EINVAL;
+       if (t->index != 0)
+               return -EINVAL;
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       i2c_clients_command(&go->i2c_adapter, VIDIOC_G_TUNER, t);
+
+       t->index = 0;
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+               return -EINVAL;
+       if (t->index != 0)
+               return -EINVAL;
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       switch (go->board_id) {
+       case GO7007_BOARDID_PX_TV402U_NA:
+       case GO7007_BOARDID_PX_TV402U_JP:
+               /* No selectable options currently */
+               if (t->audmode != V4L2_TUNER_MODE_STEREO)
                        return -EINVAL;
-               return 0;
+               break;
        }
-       case VIDIOC_G_JPEGCOMP:
-       {
-               struct v4l2_jpegcompression *params = arg;
 
-               memset(params, 0, sizeof(*params));
-               params->quality = 50; /* ?? */
-               params->jpeg_markers = V4L2_JPEG_MARKER_DHT |
-                                       V4L2_JPEG_MARKER_DQT;
+       i2c_clients_command(&go->i2c_adapter, VIDIOC_S_TUNER, t);
 
-               return 0;
+       return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+               return -EINVAL;
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       f->type = V4L2_TUNER_ANALOG_TV;
+       i2c_clients_command(&go->i2c_adapter, VIDIOC_G_FREQUENCY, f);
+       return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+               return -EINVAL;
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       i2c_clients_command(&go->i2c_adapter, VIDIOC_S_FREQUENCY, f);
+
+       return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+                                       struct v4l2_cropcap *cropcap)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       /* These specify the raw input of the sensor */
+       switch (go->standard) {
+       case GO7007_STD_NTSC:
+               cropcap->bounds.top = 0;
+               cropcap->bounds.left = 0;
+               cropcap->bounds.width = 720;
+               cropcap->bounds.height = 480;
+               cropcap->defrect.top = 0;
+               cropcap->defrect.left = 0;
+               cropcap->defrect.width = 720;
+               cropcap->defrect.height = 480;
+               break;
+       case GO7007_STD_PAL:
+               cropcap->bounds.top = 0;
+               cropcap->bounds.left = 0;
+               cropcap->bounds.width = 720;
+               cropcap->bounds.height = 576;
+               cropcap->defrect.top = 0;
+               cropcap->defrect.left = 0;
+               cropcap->defrect.width = 720;
+               cropcap->defrect.height = 576;
+               break;
+       case GO7007_STD_OTHER:
+               cropcap->bounds.top = 0;
+               cropcap->bounds.left = 0;
+               cropcap->bounds.width = go->board_info->sensor_width;
+               cropcap->bounds.height = go->board_info->sensor_height;
+               cropcap->defrect.top = 0;
+               cropcap->defrect.left = 0;
+               cropcap->defrect.width = go->board_info->sensor_width;
+               cropcap->defrect.height = go->board_info->sensor_height;
+               break;
        }
-       case VIDIOC_S_JPEGCOMP:
-       {
-               struct v4l2_jpegcompression *params = arg;
 
-               if (params->quality != 50 ||
-                               params->jpeg_markers != (V4L2_JPEG_MARKER_DHT |
-                                                       V4L2_JPEG_MARKER_DQT))
-                       return -EINVAL;
-               return 0;
+       return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       /* These specify the raw input of the sensor */
+       switch (go->standard) {
+       case GO7007_STD_NTSC:
+               crop->c.top = 0;
+               crop->c.left = 0;
+               crop->c.width = 720;
+               crop->c.height = 480;
+               break;
+       case GO7007_STD_PAL:
+               crop->c.top = 0;
+               crop->c.left = 0;
+               crop->c.width = 720;
+               crop->c.height = 576;
+               break;
+       case GO7007_STD_OTHER:
+               crop->c.top = 0;
+               crop->c.left = 0;
+               crop->c.width = go->board_info->sensor_width;
+               crop->c.height = go->board_info->sensor_height;
+               break;
        }
+
+       return 0;
+}
+
+/* FIXME: vidioc_s_crop is not really implemented!!!
+ */
+static int vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+                        struct v4l2_jpegcompression *params)
+{
+       memset(params, 0, sizeof(*params));
+       params->quality = 50; /* ?? */
+       params->jpeg_markers = V4L2_JPEG_MARKER_DHT |
+                               V4L2_JPEG_MARKER_DQT;
+
+       return 0;
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+                        struct v4l2_jpegcompression *params)
+{
+       if (params->quality != 50 ||
+                       params->jpeg_markers != (V4L2_JPEG_MARKER_DHT |
+                                               V4L2_JPEG_MARKER_DQT))
+               return -EINVAL;
+
+       return 0;
+}
+
+/* FIXME:
+       Those ioctls are private, and not needed, since several standard
+       extended controls already provide streaming control.
+       So, those ioctls should be converted into vidioc_g_ext_ctrls()
+       and vidioc_s_ext_ctrls()
+ */
+
+#if 0
        /* Temporary ioctls for controlling compression characteristics */
        case GO7007IOC_S_BITRATE:
        {
@@ -1568,26 +1676,7 @@ static long go7007_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        return -EINVAL;
                return clip_to_modet_map(go, region->region, region->clips);
        }
-       default:
-               printk(KERN_INFO "go7007-v4l2: unsupported ioctl %d\n", cmd);
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-
-unlock_and_return:
-       up(&gofh->lock);
-       return retval;
-}
-
-static long go7007_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct go7007_file *gofh = file->private_data;
-
-       if (gofh->go->status != STATUS_ONLINE)
-               return -EIO;
-
-       return video_usercopy(file, cmd, arg, go7007_do_ioctl);
-}
+#endif
 
 static ssize_t go7007_read(struct file *file, char __user *data,
                size_t count, loff_t *ppos)
@@ -1696,18 +1785,57 @@ static struct v4l2_file_operations go7007_fops = {
        .owner          = THIS_MODULE,
        .open           = go7007_open,
        .release        = go7007_release,
-       .ioctl          = go7007_ioctl,
+       .ioctl          = video_ioctl2,
        .read           = go7007_read,
        .mmap           = go7007_mmap,
        .poll           = go7007_poll,
 };
 
+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,
+       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+       .vidioc_reqbufs           = vidioc_reqbufs,
+       .vidioc_querybuf          = vidioc_querybuf,
+       .vidioc_qbuf              = vidioc_qbuf,
+       .vidioc_dqbuf             = vidioc_dqbuf,
+       .vidioc_s_std             = vidioc_s_std,
+       .vidioc_enum_input        = vidioc_enum_input,
+       .vidioc_g_input           = vidioc_g_input,
+       .vidioc_s_input           = vidioc_s_input,
+       .vidioc_queryctrl         = vidioc_queryctrl,
+       .vidioc_g_ctrl            = vidioc_g_ctrl,
+       .vidioc_s_ctrl            = vidioc_s_ctrl,
+       .vidioc_streamon          = vidioc_streamon,
+       .vidioc_streamoff         = vidioc_streamoff,
+       .vidioc_g_tuner           = vidioc_g_tuner,
+       .vidioc_s_tuner           = vidioc_s_tuner,
+       .vidioc_g_frequency       = vidioc_g_frequency,
+       .vidioc_s_frequency       = vidioc_s_frequency,
+       .vidioc_g_parm            = vidioc_g_parm,
+       .vidioc_s_parm            = vidioc_s_parm,
+#if 0  /* FIXME take out after 2.6.29-rc1 merge happens */
+       .vidioc_enum_framesizes   = vidioc_enum_framesizes,
+       .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+#endif
+       .vidioc_cropcap           = vidioc_cropcap,
+       .vidioc_g_crop            = vidioc_g_crop,
+       .vidioc_s_crop            = vidioc_s_crop,
+       .vidioc_g_jpegcomp        = vidioc_g_jpegcomp,
+       .vidioc_s_jpegcomp        = vidioc_s_jpegcomp,
+};
+
 static struct video_device go7007_template = {
        .name           = "go7007",
        .vfl_type       = VID_TYPE_CAPTURE,
        .fops           = &go7007_fops,
        .minor          = -1,
        .release        = go7007_vfl_release,
+       .ioctl_ops      = &video_ioctl_ops,
+       .tvnorms        = V4L2_STD_ALL,
+       .current_norm   = V4L2_STD_NTSC,
 };
 
 int go7007_v4l2_init(struct go7007 *go)