Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Driver for the Conexant CX25821 PCIe bridge
0004  *
0005  *  Copyright (C) 2009 Conexant Systems Inc.
0006  *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
0007  *  Based on Steven Toth <stoth@linuxtv.org> cx25821 driver
0008  *  Parts adapted/taken from Eduardo Moscoso Rubino
0009  *  Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.com>
0010  */
0011 
0012 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0013 
0014 #include "cx25821-video.h"
0015 
0016 MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
0017 MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
0018 MODULE_LICENSE("GPL");
0019 
0020 static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
0021 
0022 module_param_array(video_nr, int, NULL, 0444);
0023 
0024 MODULE_PARM_DESC(video_nr, "video device numbers");
0025 
0026 static unsigned int video_debug = VIDEO_DEBUG;
0027 module_param(video_debug, int, 0644);
0028 MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
0029 
0030 static unsigned int irq_debug;
0031 module_param(irq_debug, int, 0644);
0032 MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
0033 
0034 #define FORMAT_FLAGS_PACKED       0x01
0035 
0036 static const struct cx25821_fmt formats[] = {
0037     {
0038         .fourcc = V4L2_PIX_FMT_Y41P,
0039         .depth = 12,
0040         .flags = FORMAT_FLAGS_PACKED,
0041     }, {
0042         .fourcc = V4L2_PIX_FMT_YUYV,
0043         .depth = 16,
0044         .flags = FORMAT_FLAGS_PACKED,
0045     },
0046 };
0047 
0048 static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
0049 {
0050     unsigned int i;
0051 
0052     for (i = 0; i < ARRAY_SIZE(formats); i++)
0053         if (formats[i].fourcc == fourcc)
0054             return formats + i;
0055     return NULL;
0056 }
0057 
0058 int cx25821_start_video_dma(struct cx25821_dev *dev,
0059                 struct cx25821_dmaqueue *q,
0060                 struct cx25821_buffer *buf,
0061                 const struct sram_channel *channel)
0062 {
0063     int tmp = 0;
0064 
0065     /* setup fifo + format */
0066     cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma);
0067 
0068     /* reset counter */
0069     cx_write(channel->gpcnt_ctl, 3);
0070 
0071     /* enable irq */
0072     cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i));
0073     cx_set(channel->int_msk, 0x11);
0074 
0075     /* start dma */
0076     cx_write(channel->dma_ctl, 0x11);   /* FIFO and RISC enable */
0077 
0078     /* make sure upstream setting if any is reversed */
0079     tmp = cx_read(VID_CH_MODE_SEL);
0080     cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
0081 
0082     return 0;
0083 }
0084 
0085 int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
0086 {
0087     int handled = 0;
0088     u32 mask;
0089     const struct sram_channel *channel = dev->channels[chan_num].sram_channels;
0090 
0091     mask = cx_read(channel->int_msk);
0092     if (0 == (status & mask))
0093         return handled;
0094 
0095     cx_write(channel->int_stat, status);
0096 
0097     /* risc op code error */
0098     if (status & (1 << 16)) {
0099         pr_warn("%s, %s: video risc op code error\n",
0100             dev->name, channel->name);
0101         cx_clear(channel->dma_ctl, 0x11);
0102         cx25821_sram_channel_dump(dev, channel);
0103     }
0104 
0105     /* risc1 y */
0106     if (status & FLD_VID_DST_RISC1) {
0107         struct cx25821_dmaqueue *dmaq =
0108             &dev->channels[channel->i].dma_vidq;
0109         struct cx25821_buffer *buf;
0110 
0111         spin_lock(&dev->slock);
0112         if (!list_empty(&dmaq->active)) {
0113             buf = list_entry(dmaq->active.next,
0114                      struct cx25821_buffer, queue);
0115 
0116             buf->vb.vb2_buf.timestamp = ktime_get_ns();
0117             buf->vb.sequence = dmaq->count++;
0118             list_del(&buf->queue);
0119             vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
0120         }
0121         spin_unlock(&dev->slock);
0122         handled++;
0123     }
0124     return handled;
0125 }
0126 
0127 static int cx25821_queue_setup(struct vb2_queue *q,
0128                unsigned int *num_buffers, unsigned int *num_planes,
0129                unsigned int sizes[], struct device *alloc_devs[])
0130 {
0131     struct cx25821_channel *chan = q->drv_priv;
0132     unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3;
0133 
0134     if (*num_planes)
0135         return sizes[0] < size ? -EINVAL : 0;
0136 
0137     *num_planes = 1;
0138     sizes[0] = size;
0139     return 0;
0140 }
0141 
0142 static int cx25821_buffer_prepare(struct vb2_buffer *vb)
0143 {
0144     struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
0145     struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
0146     struct cx25821_dev *dev = chan->dev;
0147     struct cx25821_buffer *buf =
0148         container_of(vbuf, struct cx25821_buffer, vb);
0149     struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
0150     u32 line0_offset;
0151     int bpl_local = LINE_SIZE_D1;
0152     int ret;
0153 
0154     if (chan->pixel_formats == PIXEL_FRMT_411)
0155         buf->bpl = (chan->fmt->depth * chan->width) >> 3;
0156     else
0157         buf->bpl = (chan->fmt->depth >> 3) * chan->width;
0158 
0159     if (vb2_plane_size(vb, 0) < chan->height * buf->bpl)
0160         return -EINVAL;
0161     vb2_set_plane_payload(vb, 0, chan->height * buf->bpl);
0162     buf->vb.field = chan->field;
0163 
0164     if (chan->pixel_formats == PIXEL_FRMT_411) {
0165         bpl_local = buf->bpl;
0166     } else {
0167         bpl_local = buf->bpl;   /* Default */
0168 
0169         if (chan->use_cif_resolution) {
0170             if (dev->tvnorm & V4L2_STD_625_50)
0171                 bpl_local = 352 << 1;
0172             else
0173                 bpl_local = chan->cif_width << 1;
0174         }
0175     }
0176 
0177     switch (chan->field) {
0178     case V4L2_FIELD_TOP:
0179         ret = cx25821_risc_buffer(dev->pci, &buf->risc,
0180                 sgt->sgl, 0, UNSET,
0181                 buf->bpl, 0, chan->height);
0182         break;
0183     case V4L2_FIELD_BOTTOM:
0184         ret = cx25821_risc_buffer(dev->pci, &buf->risc,
0185                 sgt->sgl, UNSET, 0,
0186                 buf->bpl, 0, chan->height);
0187         break;
0188     case V4L2_FIELD_INTERLACED:
0189         /* All other formats are top field first */
0190         line0_offset = 0;
0191         dprintk(1, "top field first\n");
0192 
0193         ret = cx25821_risc_buffer(dev->pci, &buf->risc,
0194                 sgt->sgl, line0_offset,
0195                 bpl_local, bpl_local, bpl_local,
0196                 chan->height >> 1);
0197         break;
0198     case V4L2_FIELD_SEQ_TB:
0199         ret = cx25821_risc_buffer(dev->pci, &buf->risc,
0200                 sgt->sgl,
0201                 0, buf->bpl * (chan->height >> 1),
0202                 buf->bpl, 0, chan->height >> 1);
0203         break;
0204     case V4L2_FIELD_SEQ_BT:
0205         ret = cx25821_risc_buffer(dev->pci, &buf->risc,
0206                 sgt->sgl,
0207                 buf->bpl * (chan->height >> 1), 0,
0208                 buf->bpl, 0, chan->height >> 1);
0209         break;
0210     default:
0211         WARN_ON(1);
0212         ret = -EINVAL;
0213         break;
0214     }
0215 
0216     dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp 0x%08x - dma=0x%08lx\n",
0217         buf, buf->vb.vb2_buf.index, chan->width, chan->height,
0218         chan->fmt->depth, chan->fmt->fourcc,
0219         (unsigned long)buf->risc.dma);
0220 
0221     return ret;
0222 }
0223 
0224 static void cx25821_buffer_finish(struct vb2_buffer *vb)
0225 {
0226     struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
0227     struct cx25821_buffer *buf =
0228         container_of(vbuf, struct cx25821_buffer, vb);
0229     struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
0230     struct cx25821_dev *dev = chan->dev;
0231 
0232     cx25821_free_buffer(dev, buf);
0233 }
0234 
0235 static void cx25821_buffer_queue(struct vb2_buffer *vb)
0236 {
0237     struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
0238     struct cx25821_buffer *buf =
0239         container_of(vbuf, struct cx25821_buffer, vb);
0240     struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
0241     struct cx25821_dev *dev = chan->dev;
0242     struct cx25821_buffer *prev;
0243     struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq;
0244 
0245     buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
0246     buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
0247     buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
0248     buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
0249 
0250     if (list_empty(&q->active)) {
0251         list_add_tail(&buf->queue, &q->active);
0252     } else {
0253         buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
0254         prev = list_entry(q->active.prev, struct cx25821_buffer,
0255                 queue);
0256         list_add_tail(&buf->queue, &q->active);
0257         prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
0258     }
0259 }
0260 
0261 static int cx25821_start_streaming(struct vb2_queue *q, unsigned int count)
0262 {
0263     struct cx25821_channel *chan = q->drv_priv;
0264     struct cx25821_dev *dev = chan->dev;
0265     struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq;
0266     struct cx25821_buffer *buf = list_entry(dmaq->active.next,
0267             struct cx25821_buffer, queue);
0268 
0269     dmaq->count = 0;
0270     cx25821_start_video_dma(dev, dmaq, buf, chan->sram_channels);
0271     return 0;
0272 }
0273 
0274 static void cx25821_stop_streaming(struct vb2_queue *q)
0275 {
0276     struct cx25821_channel *chan = q->drv_priv;
0277     struct cx25821_dev *dev = chan->dev;
0278     struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq;
0279     unsigned long flags;
0280 
0281     cx_write(chan->sram_channels->dma_ctl, 0); /* FIFO and RISC disable */
0282     spin_lock_irqsave(&dev->slock, flags);
0283     while (!list_empty(&dmaq->active)) {
0284         struct cx25821_buffer *buf = list_entry(dmaq->active.next,
0285             struct cx25821_buffer, queue);
0286 
0287         list_del(&buf->queue);
0288         vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
0289     }
0290     spin_unlock_irqrestore(&dev->slock, flags);
0291 }
0292 
0293 static const struct vb2_ops cx25821_video_qops = {
0294     .queue_setup    = cx25821_queue_setup,
0295     .buf_prepare  = cx25821_buffer_prepare,
0296     .buf_finish = cx25821_buffer_finish,
0297     .buf_queue    = cx25821_buffer_queue,
0298     .wait_prepare = vb2_ops_wait_prepare,
0299     .wait_finish = vb2_ops_wait_finish,
0300     .start_streaming = cx25821_start_streaming,
0301     .stop_streaming = cx25821_stop_streaming,
0302 };
0303 
0304 /* VIDEO IOCTLS */
0305 
0306 static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
0307                 struct v4l2_fmtdesc *f)
0308 {
0309     if (unlikely(f->index >= ARRAY_SIZE(formats)))
0310         return -EINVAL;
0311 
0312     f->pixelformat = formats[f->index].fourcc;
0313 
0314     return 0;
0315 }
0316 
0317 static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
0318                  struct v4l2_format *f)
0319 {
0320     struct cx25821_channel *chan = video_drvdata(file);
0321 
0322     f->fmt.pix.width = chan->width;
0323     f->fmt.pix.height = chan->height;
0324     f->fmt.pix.field = chan->field;
0325     f->fmt.pix.pixelformat = chan->fmt->fourcc;
0326     f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3;
0327     f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline;
0328     f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
0329 
0330     return 0;
0331 }
0332 
0333 static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
0334                    struct v4l2_format *f)
0335 {
0336     struct cx25821_channel *chan = video_drvdata(file);
0337     struct cx25821_dev *dev = chan->dev;
0338     const struct cx25821_fmt *fmt;
0339     enum v4l2_field field = f->fmt.pix.field;
0340     unsigned int maxh;
0341     unsigned w;
0342 
0343     fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
0344     if (NULL == fmt)
0345         return -EINVAL;
0346     maxh = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
0347 
0348     w = f->fmt.pix.width;
0349     if (field != V4L2_FIELD_BOTTOM)
0350         field = V4L2_FIELD_TOP;
0351     if (w < 352) {
0352         w = 176;
0353         f->fmt.pix.height = maxh / 4;
0354     } else if (w < 720) {
0355         w = 352;
0356         f->fmt.pix.height = maxh / 2;
0357     } else {
0358         w = 720;
0359         f->fmt.pix.height = maxh;
0360         field = V4L2_FIELD_INTERLACED;
0361     }
0362     f->fmt.pix.field = field;
0363     f->fmt.pix.width = w;
0364     f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
0365     f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
0366     f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
0367 
0368     return 0;
0369 }
0370 
0371 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
0372                 struct v4l2_format *f)
0373 {
0374     struct cx25821_channel *chan = video_drvdata(file);
0375     struct cx25821_dev *dev = chan->dev;
0376     int pix_format = PIXEL_FRMT_422;
0377     int err;
0378 
0379     err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
0380 
0381     if (0 != err)
0382         return err;
0383 
0384     chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
0385     chan->field = f->fmt.pix.field;
0386     chan->width = f->fmt.pix.width;
0387     chan->height = f->fmt.pix.height;
0388 
0389     if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
0390         pix_format = PIXEL_FRMT_411;
0391     else
0392         pix_format = PIXEL_FRMT_422;
0393 
0394     cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
0395 
0396     /* check if cif resolution */
0397     if (chan->width == 320 || chan->width == 352)
0398         chan->use_cif_resolution = 1;
0399     else
0400         chan->use_cif_resolution = 0;
0401 
0402     chan->cif_width = chan->width;
0403     medusa_set_resolution(dev, chan->width, SRAM_CH00);
0404     return 0;
0405 }
0406 
0407 static int vidioc_log_status(struct file *file, void *priv)
0408 {
0409     struct cx25821_channel *chan = video_drvdata(file);
0410     struct cx25821_dev *dev = chan->dev;
0411     const struct sram_channel *sram_ch = chan->sram_channels;
0412     u32 tmp = 0;
0413 
0414     tmp = cx_read(sram_ch->dma_ctl);
0415     pr_info("Video input 0 is %s\n",
0416         (tmp & 0x11) ? "streaming" : "stopped");
0417     return 0;
0418 }
0419 
0420 
0421 static int cx25821_vidioc_querycap(struct file *file, void *priv,
0422                 struct v4l2_capability *cap)
0423 {
0424     struct cx25821_channel *chan = video_drvdata(file);
0425     struct cx25821_dev *dev = chan->dev;
0426 
0427     strscpy(cap->driver, "cx25821", sizeof(cap->driver));
0428     strscpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
0429     sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
0430     cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
0431                 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
0432                 V4L2_CAP_DEVICE_CAPS;
0433     return 0;
0434 }
0435 
0436 static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
0437 {
0438     struct cx25821_channel *chan = video_drvdata(file);
0439 
0440     *tvnorms = chan->dev->tvnorm;
0441     return 0;
0442 }
0443 
0444 static int cx25821_vidioc_s_std(struct file *file, void *priv,
0445                 v4l2_std_id tvnorms)
0446 {
0447     struct cx25821_channel *chan = video_drvdata(file);
0448     struct cx25821_dev *dev = chan->dev;
0449 
0450     if (dev->tvnorm == tvnorms)
0451         return 0;
0452 
0453     dev->tvnorm = tvnorms;
0454     chan->width = 720;
0455     chan->height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
0456 
0457     medusa_set_videostandard(dev);
0458 
0459     return 0;
0460 }
0461 
0462 static int cx25821_vidioc_enum_input(struct file *file, void *priv,
0463                   struct v4l2_input *i)
0464 {
0465     if (i->index)
0466         return -EINVAL;
0467 
0468     i->type = V4L2_INPUT_TYPE_CAMERA;
0469     i->std = CX25821_NORMS;
0470     strscpy(i->name, "Composite", sizeof(i->name));
0471     return 0;
0472 }
0473 
0474 static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
0475 {
0476     *i = 0;
0477     return 0;
0478 }
0479 
0480 static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
0481 {
0482     return i ? -EINVAL : 0;
0483 }
0484 
0485 static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
0486 {
0487     struct cx25821_channel *chan =
0488         container_of(ctrl->handler, struct cx25821_channel, hdl);
0489     struct cx25821_dev *dev = chan->dev;
0490 
0491     switch (ctrl->id) {
0492     case V4L2_CID_BRIGHTNESS:
0493         medusa_set_brightness(dev, ctrl->val, chan->id);
0494         break;
0495     case V4L2_CID_HUE:
0496         medusa_set_hue(dev, ctrl->val, chan->id);
0497         break;
0498     case V4L2_CID_CONTRAST:
0499         medusa_set_contrast(dev, ctrl->val, chan->id);
0500         break;
0501     case V4L2_CID_SATURATION:
0502         medusa_set_saturation(dev, ctrl->val, chan->id);
0503         break;
0504     default:
0505         return -EINVAL;
0506     }
0507     return 0;
0508 }
0509 
0510 static int cx25821_vidioc_enum_output(struct file *file, void *priv,
0511                   struct v4l2_output *o)
0512 {
0513     if (o->index)
0514         return -EINVAL;
0515 
0516     o->type = V4L2_INPUT_TYPE_CAMERA;
0517     o->std = CX25821_NORMS;
0518     strscpy(o->name, "Composite", sizeof(o->name));
0519     return 0;
0520 }
0521 
0522 static int cx25821_vidioc_g_output(struct file *file, void *priv, unsigned int *o)
0523 {
0524     *o = 0;
0525     return 0;
0526 }
0527 
0528 static int cx25821_vidioc_s_output(struct file *file, void *priv, unsigned int o)
0529 {
0530     return o ? -EINVAL : 0;
0531 }
0532 
0533 static int cx25821_vidioc_try_fmt_vid_out(struct file *file, void *priv,
0534                    struct v4l2_format *f)
0535 {
0536     struct cx25821_channel *chan = video_drvdata(file);
0537     struct cx25821_dev *dev = chan->dev;
0538     const struct cx25821_fmt *fmt;
0539 
0540     fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
0541     if (NULL == fmt)
0542         return -EINVAL;
0543     f->fmt.pix.width = 720;
0544     f->fmt.pix.height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
0545     f->fmt.pix.field = V4L2_FIELD_INTERLACED;
0546     f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
0547     f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
0548     f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
0549     return 0;
0550 }
0551 
0552 static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
0553                 struct v4l2_format *f)
0554 {
0555     struct cx25821_channel *chan = video_drvdata(file);
0556     int err;
0557 
0558     err = cx25821_vidioc_try_fmt_vid_out(file, priv, f);
0559 
0560     if (0 != err)
0561         return err;
0562 
0563     chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
0564     chan->field = f->fmt.pix.field;
0565     chan->width = f->fmt.pix.width;
0566     chan->height = f->fmt.pix.height;
0567     if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
0568         chan->pixel_formats = PIXEL_FRMT_411;
0569     else
0570         chan->pixel_formats = PIXEL_FRMT_422;
0571     return 0;
0572 }
0573 
0574 static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
0575     .s_ctrl = cx25821_s_ctrl,
0576 };
0577 
0578 static const struct v4l2_file_operations video_fops = {
0579     .owner = THIS_MODULE,
0580     .open = v4l2_fh_open,
0581     .release        = vb2_fop_release,
0582     .read           = vb2_fop_read,
0583     .poll       = vb2_fop_poll,
0584     .unlocked_ioctl = video_ioctl2,
0585     .mmap           = vb2_fop_mmap,
0586 };
0587 
0588 static const struct v4l2_ioctl_ops video_ioctl_ops = {
0589     .vidioc_querycap = cx25821_vidioc_querycap,
0590     .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
0591     .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
0592     .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
0593     .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
0594     .vidioc_reqbufs       = vb2_ioctl_reqbufs,
0595     .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
0596     .vidioc_create_bufs   = vb2_ioctl_create_bufs,
0597     .vidioc_querybuf      = vb2_ioctl_querybuf,
0598     .vidioc_qbuf          = vb2_ioctl_qbuf,
0599     .vidioc_dqbuf         = vb2_ioctl_dqbuf,
0600     .vidioc_streamon      = vb2_ioctl_streamon,
0601     .vidioc_streamoff     = vb2_ioctl_streamoff,
0602     .vidioc_g_std = cx25821_vidioc_g_std,
0603     .vidioc_s_std = cx25821_vidioc_s_std,
0604     .vidioc_enum_input = cx25821_vidioc_enum_input,
0605     .vidioc_g_input = cx25821_vidioc_g_input,
0606     .vidioc_s_input = cx25821_vidioc_s_input,
0607     .vidioc_log_status = vidioc_log_status,
0608     .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
0609     .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
0610 };
0611 
0612 static const struct video_device cx25821_video_device = {
0613     .name = "cx25821-video",
0614     .fops = &video_fops,
0615     .release = video_device_release_empty,
0616     .minor = -1,
0617     .ioctl_ops = &video_ioctl_ops,
0618     .tvnorms = CX25821_NORMS,
0619     .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
0620                V4L2_CAP_STREAMING,
0621 };
0622 
0623 static const struct v4l2_file_operations video_out_fops = {
0624     .owner = THIS_MODULE,
0625     .open = v4l2_fh_open,
0626     .release        = vb2_fop_release,
0627     .write          = vb2_fop_write,
0628     .poll       = vb2_fop_poll,
0629     .unlocked_ioctl = video_ioctl2,
0630     .mmap           = vb2_fop_mmap,
0631 };
0632 
0633 static const struct v4l2_ioctl_ops video_out_ioctl_ops = {
0634     .vidioc_querycap = cx25821_vidioc_querycap,
0635     .vidioc_enum_fmt_vid_out = cx25821_vidioc_enum_fmt_vid_cap,
0636     .vidioc_g_fmt_vid_out = cx25821_vidioc_g_fmt_vid_cap,
0637     .vidioc_try_fmt_vid_out = cx25821_vidioc_try_fmt_vid_out,
0638     .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
0639     .vidioc_g_std = cx25821_vidioc_g_std,
0640     .vidioc_s_std = cx25821_vidioc_s_std,
0641     .vidioc_enum_output = cx25821_vidioc_enum_output,
0642     .vidioc_g_output = cx25821_vidioc_g_output,
0643     .vidioc_s_output = cx25821_vidioc_s_output,
0644     .vidioc_log_status = vidioc_log_status,
0645 };
0646 
0647 static const struct video_device cx25821_video_out_device = {
0648     .name = "cx25821-video",
0649     .fops = &video_out_fops,
0650     .release = video_device_release_empty,
0651     .minor = -1,
0652     .ioctl_ops = &video_out_ioctl_ops,
0653     .tvnorms = CX25821_NORMS,
0654     .device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE,
0655 };
0656 
0657 void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
0658 {
0659     cx_clear(PCI_INT_MSK, 1);
0660 
0661     if (video_is_registered(&dev->channels[chan_num].vdev)) {
0662         video_unregister_device(&dev->channels[chan_num].vdev);
0663         v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
0664     }
0665 }
0666 
0667 int cx25821_video_register(struct cx25821_dev *dev)
0668 {
0669     int err;
0670     int i;
0671 
0672     /* initial device configuration */
0673     dev->tvnorm = V4L2_STD_NTSC_M;
0674 
0675     spin_lock_init(&dev->slock);
0676 
0677     for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; ++i) {
0678         struct cx25821_channel *chan = &dev->channels[i];
0679         struct video_device *vdev = &chan->vdev;
0680         struct v4l2_ctrl_handler *hdl = &chan->hdl;
0681         struct vb2_queue *q;
0682         bool is_output = i > SRAM_CH08;
0683 
0684         if (i == SRAM_CH08) /* audio channel */
0685             continue;
0686 
0687         if (!is_output) {
0688             v4l2_ctrl_handler_init(hdl, 4);
0689             v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
0690                     V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
0691             v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
0692                     V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
0693             v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
0694                     V4L2_CID_SATURATION, 0, 10000, 1, 5000);
0695             v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
0696                     V4L2_CID_HUE, 0, 10000, 1, 5000);
0697             if (hdl->error) {
0698                 err = hdl->error;
0699                 goto fail_unreg;
0700             }
0701             err = v4l2_ctrl_handler_setup(hdl);
0702             if (err)
0703                 goto fail_unreg;
0704         } else {
0705             chan->out = &dev->vid_out_data[i - SRAM_CH09];
0706             chan->out->chan = chan;
0707         }
0708 
0709         chan->sram_channels = &cx25821_sram_channels[i];
0710         chan->width = 720;
0711         chan->field = V4L2_FIELD_INTERLACED;
0712         if (dev->tvnorm & V4L2_STD_625_50)
0713             chan->height = 576;
0714         else
0715             chan->height = 480;
0716 
0717         if (chan->pixel_formats == PIXEL_FRMT_411)
0718             chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_Y41P);
0719         else
0720             chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_YUYV);
0721 
0722         cx_write(chan->sram_channels->int_stat, 0xffffffff);
0723 
0724         INIT_LIST_HEAD(&chan->dma_vidq.active);
0725 
0726         q = &chan->vidq;
0727 
0728         q->type = is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT :
0729                       V4L2_BUF_TYPE_VIDEO_CAPTURE;
0730         q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
0731         q->io_modes |= is_output ? VB2_WRITE : VB2_READ;
0732         q->gfp_flags = GFP_DMA32;
0733         q->min_buffers_needed = 2;
0734         q->drv_priv = chan;
0735         q->buf_struct_size = sizeof(struct cx25821_buffer);
0736         q->ops = &cx25821_video_qops;
0737         q->mem_ops = &vb2_dma_sg_memops;
0738         q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
0739         q->lock = &dev->lock;
0740         q->dev = &dev->pci->dev;
0741 
0742         if (!is_output) {
0743             err = vb2_queue_init(q);
0744             if (err < 0)
0745                 goto fail_unreg;
0746         }
0747 
0748         /* register v4l devices */
0749         *vdev = is_output ? cx25821_video_out_device : cx25821_video_device;
0750         vdev->v4l2_dev = &dev->v4l2_dev;
0751         if (!is_output)
0752             vdev->ctrl_handler = hdl;
0753         else
0754             vdev->vfl_dir = VFL_DIR_TX;
0755         vdev->lock = &dev->lock;
0756         vdev->queue = q;
0757         snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
0758         video_set_drvdata(vdev, chan);
0759 
0760         err = video_register_device(vdev, VFL_TYPE_VIDEO,
0761                         video_nr[dev->nr]);
0762 
0763         if (err < 0)
0764             goto fail_unreg;
0765     }
0766 
0767     /* set PCI interrupt */
0768     cx_set(PCI_INT_MSK, 0xff);
0769 
0770     return 0;
0771 
0772 fail_unreg:
0773     while (i >= 0)
0774         cx25821_video_unregister(dev, i--);
0775     return err;
0776 }