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