return 0;
 }
 
-static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
-                                unsigned long arg)
+static int cx25821_vidioc_enum_output(struct file *file, void *priv,
+                             struct v4l2_output *o)
 {
-       struct cx25821_channel *chan = video_drvdata(file);
-       struct cx25821_dev *dev = chan->dev;
-       int command = 0;
-       struct upstream_user_struct *data_from_user;
-
-       data_from_user = (struct upstream_user_struct *)arg;
-
-       if (!data_from_user) {
-               pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
-               return 0;
-       }
-
-       command = data_from_user->command;
-
-       if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
-               return 0;
-
-       dev->input_filename = data_from_user->input_filename;
-       dev->input_audiofilename = data_from_user->input_filename;
-       dev->vid_stdname = data_from_user->vid_stdname;
-       dev->pixel_format = data_from_user->pixel_format;
-       dev->channel_select = data_from_user->channel_select;
-       dev->command = data_from_user->command;
-
-       switch (command) {
-       case UPSTREAM_START_VIDEO:
-               cx25821_start_upstream_video_ch1(dev, data_from_user);
-               break;
-
-       case UPSTREAM_STOP_VIDEO:
-               cx25821_stop_upstream_video_ch1(dev);
-               break;
-       }
+       if (o->index)
+               return -EINVAL;
 
+       o->type = V4L2_INPUT_TYPE_CAMERA;
+       o->std = CX25821_NORMS;
+       strcpy(o->name, "Composite");
        return 0;
 }
 
-static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
-                                 unsigned long arg)
+static int cx25821_vidioc_g_output(struct file *file, void *priv, unsigned int *o)
 {
-       struct cx25821_channel *chan = video_drvdata(file);
-       struct cx25821_dev *dev = chan->dev;
-       int command = 0;
-       struct upstream_user_struct *data_from_user;
-
-       data_from_user = (struct upstream_user_struct *)arg;
-
-       if (!data_from_user) {
-               pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
-               return 0;
-       }
-
-       command = data_from_user->command;
-
-       if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
-               return 0;
-
-       dev->input_filename_ch2 = data_from_user->input_filename;
-       dev->input_audiofilename = data_from_user->input_filename;
-       dev->vid_stdname_ch2 = data_from_user->vid_stdname;
-       dev->pixel_format_ch2 = data_from_user->pixel_format;
-       dev->channel_select_ch2 = data_from_user->channel_select;
-       dev->command_ch2 = data_from_user->command;
-
-       switch (command) {
-       case UPSTREAM_START_VIDEO:
-               cx25821_start_upstream_video_ch2(dev, data_from_user);
-               break;
-
-       case UPSTREAM_STOP_VIDEO:
-               cx25821_stop_upstream_video_ch2(dev);
-               break;
-       }
-
+       *o = 0;
        return 0;
 }
 
-static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
-                                 unsigned long arg)
+static int cx25821_vidioc_s_output(struct file *file, void *priv, unsigned int o)
 {
-       struct cx25821_channel *chan = video_drvdata(file);
-       struct cx25821_dev *dev = chan->dev;
-       int command = 0;
-       struct upstream_user_struct *data_from_user;
-
-       data_from_user = (struct upstream_user_struct *)arg;
-
-       if (!data_from_user) {
-               pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
-               return 0;
-       }
-
-       command = data_from_user->command;
-
-       if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO)
-               return 0;
-
-       dev->input_filename = data_from_user->input_filename;
-       dev->input_audiofilename = data_from_user->input_filename;
-       dev->vid_stdname = data_from_user->vid_stdname;
-       dev->pixel_format = data_from_user->pixel_format;
-       dev->channel_select = data_from_user->channel_select;
-       dev->command = data_from_user->command;
-
-       switch (command) {
-       case UPSTREAM_START_AUDIO:
-               cx25821_start_upstream_audio(dev, data_from_user);
-               break;
-
-       case UPSTREAM_STOP_AUDIO:
-               cx25821_stop_upstream_audio(dev);
-               break;
-       }
-
-       return 0;
-}
-
-static long cx25821_video_ioctl(struct file *file,
-                               unsigned int cmd, unsigned long arg)
-{
-       struct cx25821_channel *chan = video_drvdata(file);
-
-       /* check to see if it's the video upstream */
-       if (chan->id == SRAM_CH09)
-               return video_ioctl_upstream9(file, cmd, arg);
-       if (chan->id == SRAM_CH10)
-               return video_ioctl_upstream10(file, cmd, arg);
-       if (chan->id == SRAM_CH11)
-               return video_ioctl_upstream11(file, cmd, arg);
-
-       return video_ioctl2(file, cmd, arg);
+       return o ? -EINVAL : 0;
 }
 
 static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
        .read = video_read,
        .poll = video_poll,
        .mmap = cx25821_video_mmap,
-       .unlocked_ioctl = cx25821_video_ioctl,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .tvnorms = CX25821_NORMS,
 };
 
+static const struct v4l2_file_operations video_out_fops = {
+       .owner = THIS_MODULE,
+       .open = v4l2_fh_open,
+       .release = v4l2_fh_release,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_out_ioctl_ops = {
+       .vidioc_querycap = cx25821_vidioc_querycap,
+       .vidioc_g_std = cx25821_vidioc_g_std,
+       .vidioc_s_std = cx25821_vidioc_s_std,
+       .vidioc_enum_output = cx25821_vidioc_enum_output,
+       .vidioc_g_output = cx25821_vidioc_g_output,
+       .vidioc_s_output = cx25821_vidioc_s_output,
+       .vidioc_log_status = vidioc_log_status,
+};
+
+static const struct video_device cx25821_video_out_device = {
+       .name = "cx25821-video",
+       .fops = &video_out_fops,
+       .release = video_device_release_empty,
+       .minor = -1,
+       .ioctl_ops = &video_out_ioctl_ops,
+       .tvnorms = CX25821_NORMS,
+};
+
 void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
 {
        cx_clear(PCI_INT_MSK, 1);
 
        spin_lock_init(&dev->slock);
 
-       for (i = 0; i < VID_CHANNEL_NUM; ++i) {
+       for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) {
                struct cx25821_channel *chan = &dev->channels[i];
                struct video_device *vdev = &chan->vdev;
                struct v4l2_ctrl_handler *hdl = &chan->hdl;
+               bool is_output = i > SRAM_CH08;
 
                if (i == SRAM_CH08) /* audio channel */
                        continue;
 
-               v4l2_ctrl_handler_init(hdl, 4);
-               v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
-                       V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
-               v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
-                       V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
-               v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
-                       V4L2_CID_SATURATION, 0, 10000, 1, 5000);
-               v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
-                       V4L2_CID_HUE, 0, 10000, 1, 5000);
-               if (hdl->error) {
-                       err = hdl->error;
-                       goto fail_unreg;
+               if (!is_output) {
+                       v4l2_ctrl_handler_init(hdl, 4);
+                       v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
+                                       V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
+                       v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
+                                       V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
+                       v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
+                                       V4L2_CID_SATURATION, 0, 10000, 1, 5000);
+                       v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
+                                       V4L2_CID_HUE, 0, 10000, 1, 5000);
+                       if (hdl->error) {
+                               err = hdl->error;
+                               goto fail_unreg;
+                       }
+                       err = v4l2_ctrl_handler_setup(hdl);
+                       if (err)
+                               goto fail_unreg;
                }
-               err = v4l2_ctrl_handler_setup(hdl);
-               if (err)
-                       goto fail_unreg;
 
                cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper,
                        chan->sram_channels->dma_ctl, 0x11, 0);
                chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data;
                init_timer(&chan->dma_vidq.timeout);
 
-               videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev,
-                       &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                       V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
-                       chan, &dev->lock);
+               if (!is_output)
+                       videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev,
+                               &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                               V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
+                               chan, &dev->lock);
 
                /* register v4l devices */
-               *vdev = cx25821_video_device;
+               *vdev = is_output ? cx25821_video_out_device : cx25821_video_device;
                vdev->v4l2_dev = &dev->v4l2_dev;
-               vdev->ctrl_handler = hdl;
+               if (!is_output)
+                       vdev->ctrl_handler = hdl;
+               else
+                       vdev->vfl_dir = VFL_DIR_TX;
                vdev->lock = &dev->lock;
                set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
                snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);