cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cx25821-video.c (21348B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Driver for the Conexant CX25821 PCIe bridge
      4 *
      5 *  Copyright (C) 2009 Conexant Systems Inc.
      6 *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
      7 *  Based on Steven Toth <stoth@linuxtv.org> cx25821 driver
      8 *  Parts adapted/taken from Eduardo Moscoso Rubino
      9 *  Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.com>
     10 */
     11
     12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     13
     14#include "cx25821-video.h"
     15
     16MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
     17MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
     18MODULE_LICENSE("GPL");
     19
     20static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
     21
     22module_param_array(video_nr, int, NULL, 0444);
     23
     24MODULE_PARM_DESC(video_nr, "video device numbers");
     25
     26static unsigned int video_debug = VIDEO_DEBUG;
     27module_param(video_debug, int, 0644);
     28MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
     29
     30static unsigned int irq_debug;
     31module_param(irq_debug, int, 0644);
     32MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
     33
     34#define FORMAT_FLAGS_PACKED       0x01
     35
     36static const struct cx25821_fmt formats[] = {
     37	{
     38		.fourcc = V4L2_PIX_FMT_Y41P,
     39		.depth = 12,
     40		.flags = FORMAT_FLAGS_PACKED,
     41	}, {
     42		.fourcc = V4L2_PIX_FMT_YUYV,
     43		.depth = 16,
     44		.flags = FORMAT_FLAGS_PACKED,
     45	},
     46};
     47
     48static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
     49{
     50	unsigned int i;
     51
     52	for (i = 0; i < ARRAY_SIZE(formats); i++)
     53		if (formats[i].fourcc == fourcc)
     54			return formats + i;
     55	return NULL;
     56}
     57
     58int cx25821_start_video_dma(struct cx25821_dev *dev,
     59			    struct cx25821_dmaqueue *q,
     60			    struct cx25821_buffer *buf,
     61			    const struct sram_channel *channel)
     62{
     63	int tmp = 0;
     64
     65	/* setup fifo + format */
     66	cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma);
     67
     68	/* reset counter */
     69	cx_write(channel->gpcnt_ctl, 3);
     70
     71	/* enable irq */
     72	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i));
     73	cx_set(channel->int_msk, 0x11);
     74
     75	/* start dma */
     76	cx_write(channel->dma_ctl, 0x11);	/* FIFO and RISC enable */
     77
     78	/* make sure upstream setting if any is reversed */
     79	tmp = cx_read(VID_CH_MODE_SEL);
     80	cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
     81
     82	return 0;
     83}
     84
     85int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
     86{
     87	int handled = 0;
     88	u32 mask;
     89	const struct sram_channel *channel = dev->channels[chan_num].sram_channels;
     90
     91	mask = cx_read(channel->int_msk);
     92	if (0 == (status & mask))
     93		return handled;
     94
     95	cx_write(channel->int_stat, status);
     96
     97	/* risc op code error */
     98	if (status & (1 << 16)) {
     99		pr_warn("%s, %s: video risc op code error\n",
    100			dev->name, channel->name);
    101		cx_clear(channel->dma_ctl, 0x11);
    102		cx25821_sram_channel_dump(dev, channel);
    103	}
    104
    105	/* risc1 y */
    106	if (status & FLD_VID_DST_RISC1) {
    107		struct cx25821_dmaqueue *dmaq =
    108			&dev->channels[channel->i].dma_vidq;
    109		struct cx25821_buffer *buf;
    110
    111		spin_lock(&dev->slock);
    112		if (!list_empty(&dmaq->active)) {
    113			buf = list_entry(dmaq->active.next,
    114					 struct cx25821_buffer, queue);
    115
    116			buf->vb.vb2_buf.timestamp = ktime_get_ns();
    117			buf->vb.sequence = dmaq->count++;
    118			list_del(&buf->queue);
    119			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
    120		}
    121		spin_unlock(&dev->slock);
    122		handled++;
    123	}
    124	return handled;
    125}
    126
    127static int cx25821_queue_setup(struct vb2_queue *q,
    128			   unsigned int *num_buffers, unsigned int *num_planes,
    129			   unsigned int sizes[], struct device *alloc_devs[])
    130{
    131	struct cx25821_channel *chan = q->drv_priv;
    132	unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3;
    133
    134	if (*num_planes)
    135		return sizes[0] < size ? -EINVAL : 0;
    136
    137	*num_planes = 1;
    138	sizes[0] = size;
    139	return 0;
    140}
    141
    142static int cx25821_buffer_prepare(struct vb2_buffer *vb)
    143{
    144	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
    145	struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
    146	struct cx25821_dev *dev = chan->dev;
    147	struct cx25821_buffer *buf =
    148		container_of(vbuf, struct cx25821_buffer, vb);
    149	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
    150	u32 line0_offset;
    151	int bpl_local = LINE_SIZE_D1;
    152	int ret;
    153
    154	if (chan->pixel_formats == PIXEL_FRMT_411)
    155		buf->bpl = (chan->fmt->depth * chan->width) >> 3;
    156	else
    157		buf->bpl = (chan->fmt->depth >> 3) * chan->width;
    158
    159	if (vb2_plane_size(vb, 0) < chan->height * buf->bpl)
    160		return -EINVAL;
    161	vb2_set_plane_payload(vb, 0, chan->height * buf->bpl);
    162	buf->vb.field = chan->field;
    163
    164	if (chan->pixel_formats == PIXEL_FRMT_411) {
    165		bpl_local = buf->bpl;
    166	} else {
    167		bpl_local = buf->bpl;   /* Default */
    168
    169		if (chan->use_cif_resolution) {
    170			if (dev->tvnorm & V4L2_STD_625_50)
    171				bpl_local = 352 << 1;
    172			else
    173				bpl_local = chan->cif_width << 1;
    174		}
    175	}
    176
    177	switch (chan->field) {
    178	case V4L2_FIELD_TOP:
    179		ret = cx25821_risc_buffer(dev->pci, &buf->risc,
    180				sgt->sgl, 0, UNSET,
    181				buf->bpl, 0, chan->height);
    182		break;
    183	case V4L2_FIELD_BOTTOM:
    184		ret = cx25821_risc_buffer(dev->pci, &buf->risc,
    185				sgt->sgl, UNSET, 0,
    186				buf->bpl, 0, chan->height);
    187		break;
    188	case V4L2_FIELD_INTERLACED:
    189		/* All other formats are top field first */
    190		line0_offset = 0;
    191		dprintk(1, "top field first\n");
    192
    193		ret = cx25821_risc_buffer(dev->pci, &buf->risc,
    194				sgt->sgl, line0_offset,
    195				bpl_local, bpl_local, bpl_local,
    196				chan->height >> 1);
    197		break;
    198	case V4L2_FIELD_SEQ_TB:
    199		ret = cx25821_risc_buffer(dev->pci, &buf->risc,
    200				sgt->sgl,
    201				0, buf->bpl * (chan->height >> 1),
    202				buf->bpl, 0, chan->height >> 1);
    203		break;
    204	case V4L2_FIELD_SEQ_BT:
    205		ret = cx25821_risc_buffer(dev->pci, &buf->risc,
    206				sgt->sgl,
    207				buf->bpl * (chan->height >> 1), 0,
    208				buf->bpl, 0, chan->height >> 1);
    209		break;
    210	default:
    211		WARN_ON(1);
    212		ret = -EINVAL;
    213		break;
    214	}
    215
    216	dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp 0x%08x - dma=0x%08lx\n",
    217		buf, buf->vb.vb2_buf.index, chan->width, chan->height,
    218		chan->fmt->depth, chan->fmt->fourcc,
    219		(unsigned long)buf->risc.dma);
    220
    221	return ret;
    222}
    223
    224static void cx25821_buffer_finish(struct vb2_buffer *vb)
    225{
    226	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
    227	struct cx25821_buffer *buf =
    228		container_of(vbuf, struct cx25821_buffer, vb);
    229	struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
    230	struct cx25821_dev *dev = chan->dev;
    231
    232	cx25821_free_buffer(dev, buf);
    233}
    234
    235static void cx25821_buffer_queue(struct vb2_buffer *vb)
    236{
    237	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
    238	struct cx25821_buffer *buf =
    239		container_of(vbuf, struct cx25821_buffer, vb);
    240	struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
    241	struct cx25821_dev *dev = chan->dev;
    242	struct cx25821_buffer *prev;
    243	struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq;
    244
    245	buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
    246	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
    247	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
    248	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
    249
    250	if (list_empty(&q->active)) {
    251		list_add_tail(&buf->queue, &q->active);
    252	} else {
    253		buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
    254		prev = list_entry(q->active.prev, struct cx25821_buffer,
    255				queue);
    256		list_add_tail(&buf->queue, &q->active);
    257		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
    258	}
    259}
    260
    261static int cx25821_start_streaming(struct vb2_queue *q, unsigned int count)
    262{
    263	struct cx25821_channel *chan = q->drv_priv;
    264	struct cx25821_dev *dev = chan->dev;
    265	struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq;
    266	struct cx25821_buffer *buf = list_entry(dmaq->active.next,
    267			struct cx25821_buffer, queue);
    268
    269	dmaq->count = 0;
    270	cx25821_start_video_dma(dev, dmaq, buf, chan->sram_channels);
    271	return 0;
    272}
    273
    274static void cx25821_stop_streaming(struct vb2_queue *q)
    275{
    276	struct cx25821_channel *chan = q->drv_priv;
    277	struct cx25821_dev *dev = chan->dev;
    278	struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq;
    279	unsigned long flags;
    280
    281	cx_write(chan->sram_channels->dma_ctl, 0); /* FIFO and RISC disable */
    282	spin_lock_irqsave(&dev->slock, flags);
    283	while (!list_empty(&dmaq->active)) {
    284		struct cx25821_buffer *buf = list_entry(dmaq->active.next,
    285			struct cx25821_buffer, queue);
    286
    287		list_del(&buf->queue);
    288		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
    289	}
    290	spin_unlock_irqrestore(&dev->slock, flags);
    291}
    292
    293static const struct vb2_ops cx25821_video_qops = {
    294	.queue_setup    = cx25821_queue_setup,
    295	.buf_prepare  = cx25821_buffer_prepare,
    296	.buf_finish = cx25821_buffer_finish,
    297	.buf_queue    = cx25821_buffer_queue,
    298	.wait_prepare = vb2_ops_wait_prepare,
    299	.wait_finish = vb2_ops_wait_finish,
    300	.start_streaming = cx25821_start_streaming,
    301	.stop_streaming = cx25821_stop_streaming,
    302};
    303
    304/* VIDEO IOCTLS */
    305
    306static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
    307			    struct v4l2_fmtdesc *f)
    308{
    309	if (unlikely(f->index >= ARRAY_SIZE(formats)))
    310		return -EINVAL;
    311
    312	f->pixelformat = formats[f->index].fourcc;
    313
    314	return 0;
    315}
    316
    317static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
    318				 struct v4l2_format *f)
    319{
    320	struct cx25821_channel *chan = video_drvdata(file);
    321
    322	f->fmt.pix.width = chan->width;
    323	f->fmt.pix.height = chan->height;
    324	f->fmt.pix.field = chan->field;
    325	f->fmt.pix.pixelformat = chan->fmt->fourcc;
    326	f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3;
    327	f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline;
    328	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
    329
    330	return 0;
    331}
    332
    333static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
    334				   struct v4l2_format *f)
    335{
    336	struct cx25821_channel *chan = video_drvdata(file);
    337	struct cx25821_dev *dev = chan->dev;
    338	const struct cx25821_fmt *fmt;
    339	enum v4l2_field field = f->fmt.pix.field;
    340	unsigned int maxh;
    341	unsigned w;
    342
    343	fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
    344	if (NULL == fmt)
    345		return -EINVAL;
    346	maxh = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
    347
    348	w = f->fmt.pix.width;
    349	if (field != V4L2_FIELD_BOTTOM)
    350		field = V4L2_FIELD_TOP;
    351	if (w < 352) {
    352		w = 176;
    353		f->fmt.pix.height = maxh / 4;
    354	} else if (w < 720) {
    355		w = 352;
    356		f->fmt.pix.height = maxh / 2;
    357	} else {
    358		w = 720;
    359		f->fmt.pix.height = maxh;
    360		field = V4L2_FIELD_INTERLACED;
    361	}
    362	f->fmt.pix.field = field;
    363	f->fmt.pix.width = w;
    364	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
    365	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
    366	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
    367
    368	return 0;
    369}
    370
    371static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
    372				struct v4l2_format *f)
    373{
    374	struct cx25821_channel *chan = video_drvdata(file);
    375	struct cx25821_dev *dev = chan->dev;
    376	int pix_format = PIXEL_FRMT_422;
    377	int err;
    378
    379	err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
    380
    381	if (0 != err)
    382		return err;
    383
    384	chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
    385	chan->field = f->fmt.pix.field;
    386	chan->width = f->fmt.pix.width;
    387	chan->height = f->fmt.pix.height;
    388
    389	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
    390		pix_format = PIXEL_FRMT_411;
    391	else
    392		pix_format = PIXEL_FRMT_422;
    393
    394	cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
    395
    396	/* check if cif resolution */
    397	if (chan->width == 320 || chan->width == 352)
    398		chan->use_cif_resolution = 1;
    399	else
    400		chan->use_cif_resolution = 0;
    401
    402	chan->cif_width = chan->width;
    403	medusa_set_resolution(dev, chan->width, SRAM_CH00);
    404	return 0;
    405}
    406
    407static int vidioc_log_status(struct file *file, void *priv)
    408{
    409	struct cx25821_channel *chan = video_drvdata(file);
    410	struct cx25821_dev *dev = chan->dev;
    411	const struct sram_channel *sram_ch = chan->sram_channels;
    412	u32 tmp = 0;
    413
    414	tmp = cx_read(sram_ch->dma_ctl);
    415	pr_info("Video input 0 is %s\n",
    416		(tmp & 0x11) ? "streaming" : "stopped");
    417	return 0;
    418}
    419
    420
    421static int cx25821_vidioc_querycap(struct file *file, void *priv,
    422			    struct v4l2_capability *cap)
    423{
    424	struct cx25821_channel *chan = video_drvdata(file);
    425	struct cx25821_dev *dev = chan->dev;
    426
    427	strscpy(cap->driver, "cx25821", sizeof(cap->driver));
    428	strscpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
    429	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
    430	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
    431			    V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
    432			    V4L2_CAP_DEVICE_CAPS;
    433	return 0;
    434}
    435
    436static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
    437{
    438	struct cx25821_channel *chan = video_drvdata(file);
    439
    440	*tvnorms = chan->dev->tvnorm;
    441	return 0;
    442}
    443
    444static int cx25821_vidioc_s_std(struct file *file, void *priv,
    445				v4l2_std_id tvnorms)
    446{
    447	struct cx25821_channel *chan = video_drvdata(file);
    448	struct cx25821_dev *dev = chan->dev;
    449
    450	if (dev->tvnorm == tvnorms)
    451		return 0;
    452
    453	dev->tvnorm = tvnorms;
    454	chan->width = 720;
    455	chan->height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
    456
    457	medusa_set_videostandard(dev);
    458
    459	return 0;
    460}
    461
    462static int cx25821_vidioc_enum_input(struct file *file, void *priv,
    463			      struct v4l2_input *i)
    464{
    465	if (i->index)
    466		return -EINVAL;
    467
    468	i->type = V4L2_INPUT_TYPE_CAMERA;
    469	i->std = CX25821_NORMS;
    470	strscpy(i->name, "Composite", sizeof(i->name));
    471	return 0;
    472}
    473
    474static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
    475{
    476	*i = 0;
    477	return 0;
    478}
    479
    480static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
    481{
    482	return i ? -EINVAL : 0;
    483}
    484
    485static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
    486{
    487	struct cx25821_channel *chan =
    488		container_of(ctrl->handler, struct cx25821_channel, hdl);
    489	struct cx25821_dev *dev = chan->dev;
    490
    491	switch (ctrl->id) {
    492	case V4L2_CID_BRIGHTNESS:
    493		medusa_set_brightness(dev, ctrl->val, chan->id);
    494		break;
    495	case V4L2_CID_HUE:
    496		medusa_set_hue(dev, ctrl->val, chan->id);
    497		break;
    498	case V4L2_CID_CONTRAST:
    499		medusa_set_contrast(dev, ctrl->val, chan->id);
    500		break;
    501	case V4L2_CID_SATURATION:
    502		medusa_set_saturation(dev, ctrl->val, chan->id);
    503		break;
    504	default:
    505		return -EINVAL;
    506	}
    507	return 0;
    508}
    509
    510static int cx25821_vidioc_enum_output(struct file *file, void *priv,
    511			      struct v4l2_output *o)
    512{
    513	if (o->index)
    514		return -EINVAL;
    515
    516	o->type = V4L2_INPUT_TYPE_CAMERA;
    517	o->std = CX25821_NORMS;
    518	strscpy(o->name, "Composite", sizeof(o->name));
    519	return 0;
    520}
    521
    522static int cx25821_vidioc_g_output(struct file *file, void *priv, unsigned int *o)
    523{
    524	*o = 0;
    525	return 0;
    526}
    527
    528static int cx25821_vidioc_s_output(struct file *file, void *priv, unsigned int o)
    529{
    530	return o ? -EINVAL : 0;
    531}
    532
    533static int cx25821_vidioc_try_fmt_vid_out(struct file *file, void *priv,
    534				   struct v4l2_format *f)
    535{
    536	struct cx25821_channel *chan = video_drvdata(file);
    537	struct cx25821_dev *dev = chan->dev;
    538	const struct cx25821_fmt *fmt;
    539
    540	fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
    541	if (NULL == fmt)
    542		return -EINVAL;
    543	f->fmt.pix.width = 720;
    544	f->fmt.pix.height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
    545	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
    546	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
    547	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
    548	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
    549	return 0;
    550}
    551
    552static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
    553				struct v4l2_format *f)
    554{
    555	struct cx25821_channel *chan = video_drvdata(file);
    556	int err;
    557
    558	err = cx25821_vidioc_try_fmt_vid_out(file, priv, f);
    559
    560	if (0 != err)
    561		return err;
    562
    563	chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
    564	chan->field = f->fmt.pix.field;
    565	chan->width = f->fmt.pix.width;
    566	chan->height = f->fmt.pix.height;
    567	if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
    568		chan->pixel_formats = PIXEL_FRMT_411;
    569	else
    570		chan->pixel_formats = PIXEL_FRMT_422;
    571	return 0;
    572}
    573
    574static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
    575	.s_ctrl = cx25821_s_ctrl,
    576};
    577
    578static const struct v4l2_file_operations video_fops = {
    579	.owner = THIS_MODULE,
    580	.open = v4l2_fh_open,
    581	.release        = vb2_fop_release,
    582	.read           = vb2_fop_read,
    583	.poll		= vb2_fop_poll,
    584	.unlocked_ioctl = video_ioctl2,
    585	.mmap           = vb2_fop_mmap,
    586};
    587
    588static const struct v4l2_ioctl_ops video_ioctl_ops = {
    589	.vidioc_querycap = cx25821_vidioc_querycap,
    590	.vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
    591	.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
    592	.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
    593	.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
    594	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
    595	.vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
    596	.vidioc_create_bufs   = vb2_ioctl_create_bufs,
    597	.vidioc_querybuf      = vb2_ioctl_querybuf,
    598	.vidioc_qbuf          = vb2_ioctl_qbuf,
    599	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
    600	.vidioc_streamon      = vb2_ioctl_streamon,
    601	.vidioc_streamoff     = vb2_ioctl_streamoff,
    602	.vidioc_g_std = cx25821_vidioc_g_std,
    603	.vidioc_s_std = cx25821_vidioc_s_std,
    604	.vidioc_enum_input = cx25821_vidioc_enum_input,
    605	.vidioc_g_input = cx25821_vidioc_g_input,
    606	.vidioc_s_input = cx25821_vidioc_s_input,
    607	.vidioc_log_status = vidioc_log_status,
    608	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
    609	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
    610};
    611
    612static const struct video_device cx25821_video_device = {
    613	.name = "cx25821-video",
    614	.fops = &video_fops,
    615	.release = video_device_release_empty,
    616	.minor = -1,
    617	.ioctl_ops = &video_ioctl_ops,
    618	.tvnorms = CX25821_NORMS,
    619	.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
    620		       V4L2_CAP_STREAMING,
    621};
    622
    623static const struct v4l2_file_operations video_out_fops = {
    624	.owner = THIS_MODULE,
    625	.open = v4l2_fh_open,
    626	.release        = vb2_fop_release,
    627	.write          = vb2_fop_write,
    628	.poll		= vb2_fop_poll,
    629	.unlocked_ioctl = video_ioctl2,
    630	.mmap           = vb2_fop_mmap,
    631};
    632
    633static const struct v4l2_ioctl_ops video_out_ioctl_ops = {
    634	.vidioc_querycap = cx25821_vidioc_querycap,
    635	.vidioc_enum_fmt_vid_out = cx25821_vidioc_enum_fmt_vid_cap,
    636	.vidioc_g_fmt_vid_out = cx25821_vidioc_g_fmt_vid_cap,
    637	.vidioc_try_fmt_vid_out = cx25821_vidioc_try_fmt_vid_out,
    638	.vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
    639	.vidioc_g_std = cx25821_vidioc_g_std,
    640	.vidioc_s_std = cx25821_vidioc_s_std,
    641	.vidioc_enum_output = cx25821_vidioc_enum_output,
    642	.vidioc_g_output = cx25821_vidioc_g_output,
    643	.vidioc_s_output = cx25821_vidioc_s_output,
    644	.vidioc_log_status = vidioc_log_status,
    645};
    646
    647static const struct video_device cx25821_video_out_device = {
    648	.name = "cx25821-video",
    649	.fops = &video_out_fops,
    650	.release = video_device_release_empty,
    651	.minor = -1,
    652	.ioctl_ops = &video_out_ioctl_ops,
    653	.tvnorms = CX25821_NORMS,
    654	.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE,
    655};
    656
    657void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
    658{
    659	cx_clear(PCI_INT_MSK, 1);
    660
    661	if (video_is_registered(&dev->channels[chan_num].vdev)) {
    662		video_unregister_device(&dev->channels[chan_num].vdev);
    663		v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
    664	}
    665}
    666
    667int cx25821_video_register(struct cx25821_dev *dev)
    668{
    669	int err;
    670	int i;
    671
    672	/* initial device configuration */
    673	dev->tvnorm = V4L2_STD_NTSC_M;
    674
    675	spin_lock_init(&dev->slock);
    676
    677	for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; ++i) {
    678		struct cx25821_channel *chan = &dev->channels[i];
    679		struct video_device *vdev = &chan->vdev;
    680		struct v4l2_ctrl_handler *hdl = &chan->hdl;
    681		struct vb2_queue *q;
    682		bool is_output = i > SRAM_CH08;
    683
    684		if (i == SRAM_CH08) /* audio channel */
    685			continue;
    686
    687		if (!is_output) {
    688			v4l2_ctrl_handler_init(hdl, 4);
    689			v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
    690					V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
    691			v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
    692					V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
    693			v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
    694					V4L2_CID_SATURATION, 0, 10000, 1, 5000);
    695			v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
    696					V4L2_CID_HUE, 0, 10000, 1, 5000);
    697			if (hdl->error) {
    698				err = hdl->error;
    699				goto fail_unreg;
    700			}
    701			err = v4l2_ctrl_handler_setup(hdl);
    702			if (err)
    703				goto fail_unreg;
    704		} else {
    705			chan->out = &dev->vid_out_data[i - SRAM_CH09];
    706			chan->out->chan = chan;
    707		}
    708
    709		chan->sram_channels = &cx25821_sram_channels[i];
    710		chan->width = 720;
    711		chan->field = V4L2_FIELD_INTERLACED;
    712		if (dev->tvnorm & V4L2_STD_625_50)
    713			chan->height = 576;
    714		else
    715			chan->height = 480;
    716
    717		if (chan->pixel_formats == PIXEL_FRMT_411)
    718			chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_Y41P);
    719		else
    720			chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_YUYV);
    721
    722		cx_write(chan->sram_channels->int_stat, 0xffffffff);
    723
    724		INIT_LIST_HEAD(&chan->dma_vidq.active);
    725
    726		q = &chan->vidq;
    727
    728		q->type = is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT :
    729				      V4L2_BUF_TYPE_VIDEO_CAPTURE;
    730		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
    731		q->io_modes |= is_output ? VB2_WRITE : VB2_READ;
    732		q->gfp_flags = GFP_DMA32;
    733		q->min_buffers_needed = 2;
    734		q->drv_priv = chan;
    735		q->buf_struct_size = sizeof(struct cx25821_buffer);
    736		q->ops = &cx25821_video_qops;
    737		q->mem_ops = &vb2_dma_sg_memops;
    738		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
    739		q->lock = &dev->lock;
    740		q->dev = &dev->pci->dev;
    741
    742		if (!is_output) {
    743			err = vb2_queue_init(q);
    744			if (err < 0)
    745				goto fail_unreg;
    746		}
    747
    748		/* register v4l devices */
    749		*vdev = is_output ? cx25821_video_out_device : cx25821_video_device;
    750		vdev->v4l2_dev = &dev->v4l2_dev;
    751		if (!is_output)
    752			vdev->ctrl_handler = hdl;
    753		else
    754			vdev->vfl_dir = VFL_DIR_TX;
    755		vdev->lock = &dev->lock;
    756		vdev->queue = q;
    757		snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
    758		video_set_drvdata(vdev, chan);
    759
    760		err = video_register_device(vdev, VFL_TYPE_VIDEO,
    761					    video_nr[dev->nr]);
    762
    763		if (err < 0)
    764			goto fail_unreg;
    765	}
    766
    767	/* set PCI interrupt */
    768	cx_set(PCI_INT_MSK, 0xff);
    769
    770	return 0;
    771
    772fail_unreg:
    773	while (i >= 0)
    774		cx25821_video_unregister(dev, i--);
    775	return err;
    776}