Merge tag 'media/v4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[cascardo/linux.git] / drivers / staging / media / tw686x-kh / tw686x-kh-video.c
diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-video.c b/drivers/staging/media/tw686x-kh/tw686x-kh-video.c
deleted file mode 100644 (file)
index 9bf32ae..0000000
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
- * Copyright (C) 2015 Industrial Research Institute for Automation
- * and Measurements PIAP
- *
- * Written by Krzysztof Ha?asa.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License
- * as published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-event.h>
-#include "tw686x-kh.h"
-#include "tw686x-kh-regs.h"
-
-#define MAX_SG_ENTRY_SIZE (/* 8192 - 128 */ 4096)
-#define MAX_SG_DESC_COUNT 256 /* PAL 704x576 needs up to 198 4-KB pages */
-
-static const struct tw686x_format formats[] = {
-       {
-               .name = "4:2:2 packed, UYVY", /* aka Y422 */
-               .fourcc = V4L2_PIX_FMT_UYVY,
-               .mode = 0,
-               .depth = 16,
-       }, {
-#if 0
-               .name = "4:2:0 packed, YUV",
-               .mode = 1,      /* non-standard */
-               .depth = 12,
-       }, {
-               .name = "4:1:1 packed, YUV",
-               .mode = 2,      /* non-standard */
-               .depth = 12,
-       }, {
-#endif
-               .name = "4:1:1 packed, YUV",
-               .fourcc = V4L2_PIX_FMT_Y41P,
-               .mode = 3,
-               .depth = 12,
-       }, {
-               .name = "15 bpp RGB",
-               .fourcc = V4L2_PIX_FMT_RGB555,
-               .mode = 4,
-               .depth = 16,
-       }, {
-               .name = "16 bpp RGB",
-               .fourcc = V4L2_PIX_FMT_RGB565,
-               .mode = 5,
-               .depth = 16,
-       }, {
-               .name = "4:2:2 packed, YUYV",
-               .fourcc = V4L2_PIX_FMT_YUYV,
-               .mode = 6,
-               .depth = 16,
-       }
-       /* mode 7 is "reserved" */
-};
-
-static const v4l2_std_id video_standards[7] = {
-       V4L2_STD_NTSC,
-       V4L2_STD_PAL,
-       V4L2_STD_SECAM,
-       V4L2_STD_NTSC_443,
-       V4L2_STD_PAL_M,
-       V4L2_STD_PAL_N,
-       V4L2_STD_PAL_60,
-};
-
-static const struct tw686x_format *format_by_fourcc(unsigned int fourcc)
-{
-       unsigned int cnt;
-
-       for (cnt = 0; cnt < ARRAY_SIZE(formats); cnt++)
-               if (formats[cnt].fourcc == fourcc)
-                       return &formats[cnt];
-       return NULL;
-}
-
-static void tw686x_get_format(struct tw686x_video_channel *vc,
-                             struct v4l2_format *f)
-{
-       const struct tw686x_format *format;
-       unsigned int width, height, height_div = 1;
-
-       format = format_by_fourcc(f->fmt.pix.pixelformat);
-       if (!format) {
-               format = &formats[0];
-               f->fmt.pix.pixelformat = format->fourcc;
-       }
-
-       width = 704;
-       if (f->fmt.pix.width < width * 3 / 4 /* halfway */)
-               width /= 2;
-
-       height = (vc->video_standard & V4L2_STD_625_50) ? 576 : 480;
-       if (f->fmt.pix.height < height * 3 / 4 /* halfway */)
-               height_div = 2;
-
-       switch (f->fmt.pix.field) {
-       case V4L2_FIELD_TOP:
-       case V4L2_FIELD_BOTTOM:
-               height_div = 2;
-               break;
-       case V4L2_FIELD_SEQ_BT:
-               if (height_div > 1)
-                       f->fmt.pix.field = V4L2_FIELD_BOTTOM;
-               break;
-       default:
-               if (height_div > 1)
-                       f->fmt.pix.field = V4L2_FIELD_TOP;
-               else
-                       f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
-       }
-       height /= height_div;
-
-       f->fmt.pix.width = width;
-       f->fmt.pix.height = height;
-       f->fmt.pix.bytesperline = f->fmt.pix.width * format->depth / 8;
-       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
-       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-}
-
-/* video queue operations */
-
-static int tw686x_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
-                             unsigned int *nplanes, unsigned int sizes[],
-                             struct device *alloc_devs[])
-{
-       struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
-       unsigned int size = vc->width * vc->height * vc->format->depth / 8;
-
-       if (*nbuffers < 2)
-               *nbuffers = 2;
-
-       if (*nplanes)
-               return sizes[0] < size ? -EINVAL : 0;
-
-       sizes[0] = size;
-       *nplanes = 1;           /* packed formats only */
-       return 0;
-}
-
-static void tw686x_buf_queue(struct vb2_buffer *vb)
-{
-       struct tw686x_video_channel *vc = vb2_get_drv_priv(vb->vb2_queue);
-       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-       struct tw686x_vb2_buf *buf;
-
-       buf = container_of(vbuf, struct tw686x_vb2_buf, vb);
-
-       spin_lock(&vc->qlock);
-       list_add_tail(&buf->list, &vc->vidq_queued);
-       spin_unlock(&vc->qlock);
-}
-
-static void setup_descs(struct tw686x_video_channel *vc, unsigned int n)
-{
-loop:
-       while (!list_empty(&vc->vidq_queued)) {
-               struct vdma_desc *descs = vc->sg_descs[n];
-               struct tw686x_vb2_buf *buf;
-               struct sg_table *vbuf;
-               struct scatterlist *sg;
-               unsigned int buf_len, count = 0;
-               int i;
-
-               buf = list_first_entry(&vc->vidq_queued, struct tw686x_vb2_buf,
-                                      list);
-               list_del(&buf->list);
-
-               buf_len = vc->width * vc->height * vc->format->depth / 8;
-               if (vb2_plane_size(&buf->vb.vb2_buf, 0) < buf_len) {
-                       pr_err("Video buffer size too small\n");
-                       vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-                       goto loop; /* try another */
-               }
-
-               vbuf = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0);
-               for_each_sg(vbuf->sgl, sg, vbuf->nents, i) {
-                       dma_addr_t phys = sg_dma_address(sg);
-                       unsigned int len = sg_dma_len(sg);
-
-                       while (len && buf_len) {
-                               unsigned int entry_len = min_t(unsigned int, len,
-                                                          MAX_SG_ENTRY_SIZE);
-                               entry_len = min(entry_len, buf_len);
-                               if (count == MAX_SG_DESC_COUNT) {
-                                       pr_err("Video buffer size too fragmented\n");
-                                       vb2_buffer_done(&buf->vb.vb2_buf,
-                                                       VB2_BUF_STATE_ERROR);
-                                       goto loop;
-                               }
-                               descs[count].phys = cpu_to_le32(phys);
-                               descs[count++].flags_length =
-                                       cpu_to_le32(0x40000000 /* available */ |
-                                                   entry_len);
-                               phys += entry_len;
-                               len -= entry_len;
-                               buf_len -= entry_len;
-                       }
-                       if (!buf_len)
-                               break;
-               }
-
-               /* clear the remaining entries */
-               while (count < MAX_SG_DESC_COUNT) {
-                       descs[count].phys = 0;
-                       descs[count++].flags_length = 0; /* unavailable */
-               }
-
-               buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
-               vc->curr_bufs[n] = buf;
-               return;
-       }
-       vc->curr_bufs[n] = NULL;
-}
-
-/* On TW6864 and TW6868, all channels share the pair of video DMA SG tables,
-   with 10-bit start_idx and end_idx determining start and end of frame buffer
-   for particular channel.
-   TW6868 with all its 8 channels would be problematic (only 127 SG entries per
-   channel) but we support only 4 channels on this chip anyway (the first
-   4 channels are driven with internal video decoder, the other 4 would require
-   an external TW286x part).
-
-   On TW6865 and TW6869, each channel has its own DMA SG table, with indexes
-   starting with 0. Both chips have complete sets of internal video decoders
-   (respectively 4 or 8-channel).
-
-   All chips have separate SG tables for two video frames. */
-
-static void setup_dma_cfg(struct tw686x_video_channel *vc)
-{
-       unsigned int field_width = 704;
-       unsigned int field_height = (vc->video_standard & V4L2_STD_625_50) ?
-               288 : 240;
-       unsigned int start_idx = is_second_gen(vc->dev) ? 0 :
-               vc->ch * MAX_SG_DESC_COUNT;
-       unsigned int end_idx = start_idx + MAX_SG_DESC_COUNT - 1;
-       u32 dma_cfg = (0 << 30) /* input selection */ |
-               (1 << 29) /* field2 dropped (if any) */ |
-               ((vc->height < 300) << 28) /* field dropping */ |
-               (1 << 27) /* master */ |
-               (0 << 25) /* master channel (for slave only) */ |
-               (0 << 24) /* (no) vertical (line) decimation */ |
-               ((vc->width < 400) << 23) /* horizontal decimation */ |
-               (vc->format->mode << 20) /* output video format */ |
-               (end_idx << 10) /* DMA end index */ |
-               start_idx /* DMA start index */;
-       u32 reg;
-
-       reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], dma_cfg);
-       reg_write(vc->dev, VIDEO_SIZE[vc->ch], (1 << 31) | (field_height << 16)
-                 | field_width);
-       reg = reg_read(vc->dev, VIDEO_CONTROL1);
-       if (vc->video_standard & V4L2_STD_625_50)
-               reg |= 1 << (vc->ch + 13);
-       else
-               reg &= ~(1 << (vc->ch + 13));
-       reg_write(vc->dev, VIDEO_CONTROL1, reg);
-}
-
-static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count)
-{
-       struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
-       struct tw686x_dev *dev = vc->dev;
-       u32 dma_ch_mask;
-       unsigned int n;
-
-       setup_dma_cfg(vc);
-
-       /* queue video buffers if available */
-       spin_lock(&vc->qlock);
-       for (n = 0; n < 2; n++)
-               setup_descs(vc, n);
-       spin_unlock(&vc->qlock);
-
-       dev->video_active |= 1 << vc->ch;
-       vc->seq = 0;
-       dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE) | (1 << vc->ch);
-       reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask);
-       reg_write(dev, DMA_CMD, (1 << 31) | dma_ch_mask);
-       return 0;
-}
-
-static void tw686x_stop_streaming(struct vb2_queue *vq)
-{
-       struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
-       struct tw686x_dev *dev = vc->dev;
-       u32 dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE);
-       u32 dma_cmd = reg_read(dev, DMA_CMD);
-       unsigned int n;
-
-       dma_ch_mask &= ~(1 << vc->ch);
-       reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask);
-
-       dev->video_active &= ~(1 << vc->ch);
-
-       dma_cmd &= ~(1 << vc->ch);
-       reg_write(dev, DMA_CMD, dma_cmd);
-
-       if (!dev->video_active) {
-               reg_write(dev, DMA_CMD, 0);
-               reg_write(dev, DMA_CHANNEL_ENABLE, 0);
-       }
-
-       spin_lock(&vc->qlock);
-       while (!list_empty(&vc->vidq_queued)) {
-               struct tw686x_vb2_buf *buf;
-
-               buf = list_entry(vc->vidq_queued.next, struct tw686x_vb2_buf,
-                                list);
-               list_del(&buf->list);
-               vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-       }
-
-       for (n = 0; n < 2; n++)
-               if (vc->curr_bufs[n])
-                       vb2_buffer_done(&vc->curr_bufs[n]->vb.vb2_buf,
-                                       VB2_BUF_STATE_ERROR);
-
-       spin_unlock(&vc->qlock);
-}
-
-static struct vb2_ops tw686x_video_qops = {
-       .queue_setup            = tw686x_queue_setup,
-       .buf_queue              = tw686x_buf_queue,
-       .start_streaming        = tw686x_start_streaming,
-       .stop_streaming         = tw686x_stop_streaming,
-       .wait_prepare           = vb2_ops_wait_prepare,
-       .wait_finish            = vb2_ops_wait_finish,
-};
-
-static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct tw686x_video_channel *vc;
-       struct tw686x_dev *dev;
-       unsigned int ch;
-
-       vc = container_of(ctrl->handler, struct tw686x_video_channel,
-                         ctrl_handler);
-       dev = vc->dev;
-       ch = vc->ch;
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               reg_write(dev, BRIGHT[ch], ctrl->val & 0xFF);
-               return 0;
-
-       case V4L2_CID_CONTRAST:
-               reg_write(dev, CONTRAST[ch], ctrl->val);
-               return 0;
-
-       case V4L2_CID_SATURATION:
-               reg_write(dev, SAT_U[ch], ctrl->val);
-               reg_write(dev, SAT_V[ch], ctrl->val);
-               return 0;
-
-       case V4L2_CID_HUE:
-               reg_write(dev, HUE[ch], ctrl->val & 0xFF);
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
-       .s_ctrl = tw686x_s_ctrl,
-};
-
-static int tw686x_g_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct tw686x_video_channel *vc = video_drvdata(file);
-
-       f->fmt.pix.width = vc->width;
-       f->fmt.pix.height = vc->height;
-       f->fmt.pix.field = vc->field;
-       f->fmt.pix.pixelformat = vc->format->fourcc;
-       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-       f->fmt.pix.bytesperline = f->fmt.pix.width * vc->format->depth / 8;
-       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
-       return 0;
-}
-
-static int tw686x_try_fmt_vid_cap(struct file *file, void *priv,
-                                 struct v4l2_format *f)
-{
-       tw686x_get_format(video_drvdata(file), f);
-       return 0;
-}
-
-static int tw686x_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct tw686x_video_channel *vc = video_drvdata(file);
-
-       tw686x_get_format(vc, f);
-       vc->format = format_by_fourcc(f->fmt.pix.pixelformat);
-       vc->field = f->fmt.pix.field;
-       vc->width = f->fmt.pix.width;
-       vc->height = f->fmt.pix.height;
-       return 0;
-}
-
-static int tw686x_querycap(struct file *file, void *priv,
-                          struct v4l2_capability *cap)
-{
-       struct tw686x_video_channel *vc = video_drvdata(file);
-       struct tw686x_dev *dev = vc->dev;
-
-       strcpy(cap->driver, "tw686x-kh");
-       strcpy(cap->card, dev->name);
-       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci_dev));
-       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
-       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-       return 0;
-}
-
-static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)
-{
-       struct tw686x_video_channel *vc = video_drvdata(file);
-       unsigned int cnt;
-       u32 sdt = 0; /* default */
-
-       for (cnt = 0; cnt < ARRAY_SIZE(video_standards); cnt++)
-               if (id & video_standards[cnt]) {
-                       sdt = cnt;
-                       break;
-               }
-
-       reg_write(vc->dev, SDT[vc->ch], sdt);
-       vc->video_standard = video_standards[sdt];
-       return 0;
-}
-
-static int tw686x_g_std(struct file *file, void *priv, v4l2_std_id *id)
-{
-       struct tw686x_video_channel *vc = video_drvdata(file);
-
-       *id = vc->video_standard;
-       return 0;
-}
-
-static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv,
-                                  struct v4l2_fmtdesc *f)
-{
-       if (f->index >= ARRAY_SIZE(formats))
-               return -EINVAL;
-
-       strlcpy(f->description, formats[f->index].name, sizeof(f->description));
-       f->pixelformat = formats[f->index].fourcc;
-       return 0;
-}
-
-static int tw686x_g_parm(struct file *file, void *priv,
-                        struct v4l2_streamparm *sp)
-{
-       struct tw686x_video_channel *vc = video_drvdata(file);
-
-       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       memset(&sp->parm.capture, 0, sizeof(sp->parm.capture));
-       sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-       v4l2_video_std_frame_period(vc->video_standard,
-                                   &sp->parm.capture.timeperframe);
-
-       return 0;
-}
-
-static int tw686x_enum_input(struct file *file, void *priv,
-                            struct v4l2_input *inp)
-{
-       /* the chip has internal multiplexer, support can be added
-          if the actual hw uses it */
-       if (inp->index)
-               return -EINVAL;
-
-       snprintf(inp->name, sizeof(inp->name), "Composite");
-       inp->type = V4L2_INPUT_TYPE_CAMERA;
-       inp->std = V4L2_STD_ALL;
-       inp->capabilities = V4L2_IN_CAP_STD;
-       return 0;
-}
-
-static int tw686x_g_input(struct file *file, void *priv, unsigned int *v)
-{
-       *v = 0;
-       return 0;
-}
-
-static int tw686x_s_input(struct file *file, void *priv, unsigned int v)
-{
-       if (v)
-               return -EINVAL;
-       return 0;
-}
-
-static const struct v4l2_file_operations tw686x_video_fops = {
-       .owner          = THIS_MODULE,
-       .open           = v4l2_fh_open,
-       .unlocked_ioctl = video_ioctl2,
-       .release        = vb2_fop_release,
-       .poll           = vb2_fop_poll,
-       .read           = vb2_fop_read,
-       .mmap           = vb2_fop_mmap,
-};
-
-static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = {
-       .vidioc_querycap                = tw686x_querycap,
-       .vidioc_enum_fmt_vid_cap        = tw686x_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap           = tw686x_g_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap           = tw686x_s_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap         = tw686x_try_fmt_vid_cap,
-       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
-       .vidioc_querybuf                = vb2_ioctl_querybuf,
-       .vidioc_qbuf                    = vb2_ioctl_qbuf,
-       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
-       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
-       .vidioc_streamon                = vb2_ioctl_streamon,
-       .vidioc_streamoff               = vb2_ioctl_streamoff,
-       .vidioc_g_std                   = tw686x_g_std,
-       .vidioc_s_std                   = tw686x_s_std,
-       .vidioc_g_parm                  = tw686x_g_parm,
-       .vidioc_enum_input              = tw686x_enum_input,
-       .vidioc_g_input                 = tw686x_g_input,
-       .vidioc_s_input                 = tw686x_s_input,
-       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
-       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
-};
-
-static int video_thread(void *arg)
-{
-       struct tw686x_dev *dev = arg;
-       DECLARE_WAITQUEUE(wait, current);
-
-       set_freezable();
-       add_wait_queue(&dev->video_thread_wait, &wait);
-
-       while (1) {
-               long timeout = schedule_timeout_interruptible(HZ);
-               unsigned int ch;
-
-               if (timeout == -ERESTARTSYS || kthread_should_stop())
-                       break;
-
-               for (ch = 0; ch < max_channels(dev); ch++) {
-                       struct tw686x_video_channel *vc;
-                       unsigned long flags;
-                       u32 request, n, stat = VB2_BUF_STATE_DONE;
-
-                       vc = &dev->video_channels[ch];
-                       if (!(dev->video_active & (1 << ch)))
-                               continue;
-
-                       spin_lock_irq(&dev->irq_lock);
-                       request = dev->dma_requests & (0x01000001 << ch);
-                       if (request)
-                               dev->dma_requests &= ~request;
-                       spin_unlock_irq(&dev->irq_lock);
-
-                       if (!request)
-                               continue;
-
-                       request >>= ch;
-
-                       /* handle channel events */
-                       if ((request & 0x01000000) |
-                           (reg_read(dev, VIDEO_FIFO_STATUS) & (0x01010001 << ch)) |
-                           (reg_read(dev, VIDEO_PARSER_STATUS) & (0x00000101 << ch))) {
-                               /* DMA Errors - reset channel */
-                               u32 reg;
-
-                               spin_lock_irqsave(&dev->irq_lock, flags);
-                               reg = reg_read(dev, DMA_CMD);
-                               /* Reset DMA channel */
-                               reg_write(dev, DMA_CMD, reg & ~(1 << ch));
-                               reg_write(dev, DMA_CMD, reg);
-                               spin_unlock_irqrestore(&dev->irq_lock, flags);
-                               stat = VB2_BUF_STATE_ERROR;
-                       }
-
-                       /* handle video stream */
-                       mutex_lock(&vc->vb_mutex);
-                       spin_lock(&vc->qlock);
-                       n = !!(reg_read(dev, PB_STATUS) & (1 << ch));
-                       if (vc->curr_bufs[n]) {
-                               struct vb2_v4l2_buffer *vb;
-
-                               vb = &vc->curr_bufs[n]->vb;
-                               vb->vb2_buf.timestamp = ktime_get_ns();
-                               vb->field = vc->field;
-                               if (V4L2_FIELD_HAS_BOTH(vc->field))
-                                       vb->sequence = vc->seq++;
-                               else
-                                       vb->sequence = (vc->seq++) / 2;
-                               vb2_set_plane_payload(&vb->vb2_buf, 0,
-                                     vc->width * vc->height * vc->format->depth / 8);
-                               vb2_buffer_done(&vb->vb2_buf, stat);
-                       }
-                       setup_descs(vc, n);
-                       spin_unlock(&vc->qlock);
-                       mutex_unlock(&vc->vb_mutex);
-               }
-               try_to_freeze();
-       }
-
-       remove_wait_queue(&dev->video_thread_wait, &wait);
-       return 0;
-}
-
-int tw686x_kh_video_irq(struct tw686x_dev *dev)
-{
-       unsigned long flags, handled = 0;
-       u32 requests;
-
-       spin_lock_irqsave(&dev->irq_lock, flags);
-       requests = dev->dma_requests;
-       spin_unlock_irqrestore(&dev->irq_lock, flags);
-
-       if (requests & dev->video_active) {
-               wake_up_interruptible_all(&dev->video_thread_wait);
-               handled = 1;
-       }
-       return handled;
-}
-
-void tw686x_kh_video_free(struct tw686x_dev *dev)
-{
-       unsigned int ch, n;
-
-       if (dev->video_thread)
-               kthread_stop(dev->video_thread);
-
-       for (ch = 0; ch < max_channels(dev); ch++) {
-               struct tw686x_video_channel *vc = &dev->video_channels[ch];
-
-               v4l2_ctrl_handler_free(&vc->ctrl_handler);
-               if (vc->device)
-                       video_unregister_device(vc->device);
-               for (n = 0; n < 2; n++) {
-                       struct dma_desc *descs = &vc->sg_tables[n];
-
-                       if (descs->virt)
-                               pci_free_consistent(dev->pci_dev, descs->size,
-                                                   descs->virt, descs->phys);
-               }
-       }
-
-       v4l2_device_unregister(&dev->v4l2_dev);
-}
-
-#define SG_TABLE_SIZE (MAX_SG_DESC_COUNT * sizeof(struct vdma_desc))
-
-int tw686x_kh_video_init(struct tw686x_dev *dev)
-{
-       unsigned int ch, n;
-       int err;
-
-       init_waitqueue_head(&dev->video_thread_wait);
-
-       err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev);
-       if (err)
-               return err;
-
-       reg_write(dev, VIDEO_CONTROL1, 0); /* NTSC, disable scaler */
-       reg_write(dev, PHASE_REF, 0x00001518); /* Scatter-gather DMA mode */
-
-       /* setup required SG table sizes */
-       for (n = 0; n < 2; n++)
-               if (is_second_gen(dev)) {
-                       /* TW 6865, TW6869 - each channel needs a pair of
-                          descriptor tables */
-                       for (ch = 0; ch < max_channels(dev); ch++)
-                               dev->video_channels[ch].sg_tables[n].size =
-                                       SG_TABLE_SIZE;
-
-               } else
-                       /* TW 6864, TW6868 - we need to allocate a pair of
-                          descriptor tables, common for all channels.
-                          Each table will be bigger than 4 KB. */
-                       dev->video_channels[0].sg_tables[n].size =
-                               max_channels(dev) * SG_TABLE_SIZE;
-
-       /* allocate SG tables and initialize video channels */
-       for (ch = 0; ch < max_channels(dev); ch++) {
-               struct tw686x_video_channel *vc = &dev->video_channels[ch];
-               struct video_device *vdev;
-
-               mutex_init(&vc->vb_mutex);
-               spin_lock_init(&vc->qlock);
-               INIT_LIST_HEAD(&vc->vidq_queued);
-
-               vc->dev = dev;
-               vc->ch = ch;
-
-               /* default settings: NTSC */
-               vc->format = &formats[0];
-               vc->video_standard = V4L2_STD_NTSC;
-               reg_write(vc->dev, SDT[vc->ch], 0);
-               vc->field = V4L2_FIELD_SEQ_BT;
-               vc->width = 704;
-               vc->height = 480;
-
-               for (n = 0; n < 2; n++) {
-                       void *cpu;
-
-                       if (vc->sg_tables[n].size) {
-                               unsigned int reg = n ? DMA_PAGE_TABLE1_ADDR[ch] :
-                                       DMA_PAGE_TABLE0_ADDR[ch];
-
-                               cpu = pci_alloc_consistent(dev->pci_dev,
-                                                          vc->sg_tables[n].size,
-                                                          &vc->sg_tables[n].phys);
-                               if (!cpu) {
-                                       pr_err("Error allocating video DMA scatter-gather tables\n");
-                                       err = -ENOMEM;
-                                       goto error;
-                               }
-                               vc->sg_tables[n].virt = cpu;
-                               reg_write(dev, reg, vc->sg_tables[n].phys);
-                       } else
-                               cpu = dev->video_channels[0].sg_tables[n].virt +
-                                       ch * SG_TABLE_SIZE;
-
-                       vc->sg_descs[n] = cpu;
-               }
-
-               reg_write(dev, VCTRL1[0], 0x24);
-               reg_write(dev, LOOP[0], 0xA5);
-               if (max_channels(dev) > 4) {
-                       reg_write(dev, VCTRL1[1], 0x24);
-                       reg_write(dev, LOOP[1], 0xA5);
-               }
-               reg_write(dev, VIDEO_FIELD_CTRL[ch], 0);
-               reg_write(dev, VDELAY_LO[ch], 0x14);
-
-               vdev = video_device_alloc();
-               if (!vdev) {
-                       pr_warn("Unable to allocate video device\n");
-                       err = -ENOMEM;
-                       goto error;
-               }
-
-               vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               vc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
-               vc->vidq.drv_priv = vc;
-               vc->vidq.buf_struct_size = sizeof(struct tw686x_vb2_buf);
-               vc->vidq.ops = &tw686x_video_qops;
-               vc->vidq.mem_ops = &vb2_dma_sg_memops;
-               vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-               vc->vidq.min_buffers_needed = 2;
-               vc->vidq.lock = &vc->vb_mutex;
-               vc->vidq.dev = &dev->pci_dev->dev;
-               vc->vidq.gfp_flags = GFP_DMA32;
-
-               err = vb2_queue_init(&vc->vidq);
-               if (err)
-                       goto error;
-
-               strcpy(vdev->name, "TW686x-video");
-               snprintf(vdev->name, sizeof(vdev->name), "%s video", dev->name);
-               vdev->fops = &tw686x_video_fops;
-               vdev->ioctl_ops = &tw686x_video_ioctl_ops;
-               vdev->release = video_device_release;
-               vdev->v4l2_dev = &dev->v4l2_dev;
-               vdev->queue = &vc->vidq;
-               vdev->tvnorms = V4L2_STD_ALL;
-               vdev->minor = -1;
-               vdev->lock = &vc->vb_mutex;
-
-               dev->video_channels[ch].device = vdev;
-               video_set_drvdata(vdev, vc);
-               err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
-               if (err < 0)
-                       goto error;
-
-               v4l2_ctrl_handler_init(&vc->ctrl_handler,
-                                      4 /* number of controls */);
-               vdev->ctrl_handler = &vc->ctrl_handler;
-               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
-                                 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
-               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
-                                 V4L2_CID_CONTRAST, 0, 255, 1, 64);
-               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
-                                 V4L2_CID_SATURATION, 0, 255, 1, 128);
-               v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, V4L2_CID_HUE,
-                                 -124, 127, 1, 0);
-               err = vc->ctrl_handler.error;
-               if (err)
-                       goto error;
-
-               v4l2_ctrl_handler_setup(&vc->ctrl_handler);
-       }
-
-       dev->video_thread = kthread_run(video_thread, dev, "tw686x_video");
-       if (IS_ERR(dev->video_thread)) {
-               err = PTR_ERR(dev->video_thread);
-               goto error;
-       }
-
-       return 0;
-
-error:
-       tw686x_kh_video_free(dev);
-       return err;
-}