blob: aec6fdfe944d5b091f425fa1f0ae2a235dcd1095 [file] [log] [blame]
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001/*
2 * Driver for the Conexant CX25821 PCIe bridge
3 *
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03004 * Copyright (C) 2009 Conexant Systems Inc.
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03005 * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
6 * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03007 * Parts adapted/taken from Eduardo Moscoso Rubino
8 * Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.com>
9 *
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030010 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 *
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
Joe Perches36d89f72010-11-07 17:48:21 -030027#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030029#include "cx25821-video.h"
30
31MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -030032MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030033MODULE_LICENSE("GPL");
34
Mauro Carvalho Chehab53e712d2009-09-13 11:39:12 -030035static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030036
37module_param_array(video_nr, int, NULL, 0444);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030038
39MODULE_PARM_DESC(video_nr, "video device numbers");
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030040
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030041static unsigned int video_debug = VIDEO_DEBUG;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030042module_param(video_debug, int, 0644);
43MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
44
45static unsigned int irq_debug;
46module_param(irq_debug, int, 0644);
47MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
48
Hans Verkuil95c232a2013-04-13 07:41:29 -030049static unsigned int vid_limit = 16;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030050module_param(vid_limit, int, 0644);
51MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
52
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030053#define FORMAT_FLAGS_PACKED 0x01
54
Hans Verkuil95c232a2013-04-13 07:41:29 -030055static const struct cx25821_fmt formats[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030056 {
Mauro Carvalho Chehabd7d93382010-03-24 14:23:25 -030057 .name = "4:1:1, packed, Y41P",
58 .fourcc = V4L2_PIX_FMT_Y41P,
59 .depth = 12,
60 .flags = FORMAT_FLAGS_PACKED,
61 }, {
62 .name = "4:2:2, packed, YUYV",
63 .fourcc = V4L2_PIX_FMT_YUYV,
64 .depth = 16,
65 .flags = FORMAT_FLAGS_PACKED,
Mauro Carvalho Chehabd7d93382010-03-24 14:23:25 -030066 },
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030067};
68
Hans Verkuil95c232a2013-04-13 07:41:29 -030069static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030070{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030071 unsigned int i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030072
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030073 for (i = 0; i < ARRAY_SIZE(formats); i++)
74 if (formats[i].fourcc == fourcc)
75 return formats + i;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030076 return NULL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030077}
78
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030079void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
80 u32 count)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030081{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030082 struct cx25821_buffer *buf;
83 int bc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030084
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030085 for (bc = 0;; bc++) {
86 if (list_empty(&q->active)) {
87 dprintk(1, "bc=%d (=0: active empty)\n", bc);
88 break;
89 }
90
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -030091 buf = list_entry(q->active.next, struct cx25821_buffer,
92 vb.queue);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030093
94 /* count comes from the hw and it is 16bit wide --
95 * this trick handles wrap-arounds correctly for
96 * up to 32767 buffers in flight... */
Leonid V. Fedorenchike313e1f2011-09-16 14:15:13 +080097 if ((s16) (count - buf->count) < 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030098 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030099
Sakari Ailus8e6057b2012-09-15 15:14:42 -0300100 v4l2_get_timestamp(&buf->vb.ts);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300101 buf->vb.state = VIDEOBUF_DONE;
102 list_del(&buf->vb.queue);
103 wake_up(&buf->vb.done);
104 }
105
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300106 if (list_empty(&q->active))
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300107 del_timer(&q->timeout);
108 else
109 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
110 if (bc != 1)
Leonid V. Fedorenchik692cfb92011-09-16 14:14:36 +0800111 pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300112}
113
Hans Verkuil95c232a2013-04-13 07:41:29 -0300114static int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300115{
Joe Perches36d89f72010-11-07 17:48:21 -0300116 dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
117 __func__, (unsigned int)norm, v4l2_norm_to_name(norm));
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300118
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300119 dev->tvnorm = norm;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300120
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300121 /* Tell the internal A/V decoder */
122 cx25821_call_all(dev, core, s_std, norm);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300123
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300124 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300125}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300126
Hans Verkuil95c232a2013-04-13 07:41:29 -0300127static int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300128{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300129 struct v4l2_routing route;
130 memset(&route, 0, sizeof(route));
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300131
Joe Perches36d89f72010-11-07 17:48:21 -0300132 dprintk(1, "%s(): video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300133 __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0,
134 INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3);
135 dev->input = input;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300136
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300137 route.input = INPUT(input)->vmux;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300138
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300139 /* Tell the internal A/V decoder */
140 cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300141
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300142 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300143}
144
145int cx25821_start_video_dma(struct cx25821_dev *dev,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300146 struct cx25821_dmaqueue *q,
147 struct cx25821_buffer *buf,
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300148 const struct sram_channel *channel)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300149{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300150 int tmp = 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300151
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300152 /* setup fifo + format */
153 cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300154
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300155 /* reset counter */
156 cx_write(channel->gpcnt_ctl, 3);
157 q->count = 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300158
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300159 /* enable irq */
160 cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i));
161 cx_set(channel->int_msk, 0x11);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300162
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300163 /* start dma */
164 cx_write(channel->dma_ctl, 0x11); /* FIFO and RISC enable */
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300165
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300166 /* make sure upstream setting if any is reversed */
167 tmp = cx_read(VID_CH_MODE_SEL);
168 cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300169
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300170 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300171}
172
Mauro Carvalho Chehabdafc4562012-10-27 12:42:59 -0300173static int cx25821_restart_video_queue(struct cx25821_dev *dev,
174 struct cx25821_dmaqueue *q,
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300175 const struct sram_channel *channel)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300176{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300177 struct cx25821_buffer *buf, *prev;
178 struct list_head *item;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300179
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300180 if (!list_empty(&q->active)) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300181 buf = list_entry(q->active.next, struct cx25821_buffer,
182 vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300183
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300184 cx25821_start_video_dma(dev, q, buf, channel);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300185
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300186 list_for_each(item, &q->active) {
187 buf = list_entry(item, struct cx25821_buffer, vb.queue);
188 buf->count = q->count++;
189 }
190
191 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
192 return 0;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300193 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300194
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300195 prev = NULL;
196 for (;;) {
197 if (list_empty(&q->queued))
198 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300199
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300200 buf = list_entry(q->queued.next, struct cx25821_buffer,
201 vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300202
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300203 if (NULL == prev) {
204 list_move_tail(&buf->vb.queue, &q->active);
205 cx25821_start_video_dma(dev, q, buf, channel);
206 buf->vb.state = VIDEOBUF_ACTIVE;
207 buf->count = q->count++;
208 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
209 } else if (prev->vb.width == buf->vb.width &&
210 prev->vb.height == buf->vb.height &&
211 prev->fmt == buf->fmt) {
212 list_move_tail(&buf->vb.queue, &q->active);
213 buf->vb.state = VIDEOBUF_ACTIVE;
214 buf->count = q->count++;
215 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800216 prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300217 } else {
218 return 0;
219 }
220 prev = buf;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300221 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300222}
223
Mauro Carvalho Chehabdafc4562012-10-27 12:42:59 -0300224static void cx25821_vid_timeout(unsigned long data)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300225{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300226 struct cx25821_data *timeout_data = (struct cx25821_data *)data;
227 struct cx25821_dev *dev = timeout_data->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300228 const struct sram_channel *channel = timeout_data->channel;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300229 struct cx25821_dmaqueue *q = &dev->channels[channel->i].dma_vidq;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300230 struct cx25821_buffer *buf;
231 unsigned long flags;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300232
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800233 /* cx25821_sram_channel_dump(dev, channel); */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300234 cx_clear(channel->dma_ctl, 0x11);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300235
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300236 spin_lock_irqsave(&dev->slock, flags);
237 while (!list_empty(&q->active)) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300238 buf = list_entry(q->active.next, struct cx25821_buffer,
239 vb.queue);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300240 list_del(&buf->vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300241
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300242 buf->vb.state = VIDEOBUF_ERROR;
243 wake_up(&buf->vb.done);
244 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300245
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300246 cx25821_restart_video_queue(dev, q, channel);
247 spin_unlock_irqrestore(&dev->slock, flags);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300248}
249
250int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
251{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300252 u32 count = 0;
253 int handled = 0;
254 u32 mask;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300255 const struct sram_channel *channel = dev->channels[chan_num].sram_channels;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300256
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300257 mask = cx_read(channel->int_msk);
258 if (0 == (status & mask))
259 return handled;
260
261 cx_write(channel->int_stat, status);
262
263 /* risc op code error */
264 if (status & (1 << 16)) {
Joe Perches36d89f72010-11-07 17:48:21 -0300265 pr_warn("%s, %s: video risc op code error\n",
266 dev->name, channel->name);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300267 cx_clear(channel->dma_ctl, 0x11);
268 cx25821_sram_channel_dump(dev, channel);
269 }
270
271 /* risc1 y */
272 if (status & FLD_VID_DST_RISC1) {
273 spin_lock(&dev->slock);
274 count = cx_read(channel->gpcnt);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300275 cx25821_video_wakeup(dev, &dev->channels[channel->i].dma_vidq,
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800276 count);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300277 spin_unlock(&dev->slock);
278 handled++;
279 }
280
281 /* risc2 y */
282 if (status & 0x10) {
283 dprintk(2, "stopper video\n");
284 spin_lock(&dev->slock);
Leonid V. Fedorenchik788d0f32011-09-16 14:14:39 +0800285 cx25821_restart_video_queue(dev,
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300286 &dev->channels[channel->i].dma_vidq, channel);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300287 spin_unlock(&dev->slock);
288 handled++;
289 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300290 return handled;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300291}
292
Hans Verkuil95c232a2013-04-13 07:41:29 -0300293static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300294 unsigned int *size)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300295{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300296 struct cx25821_channel *chan = q->priv_data;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300297
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300298 *size = chan->fmt->depth * chan->width * chan->height >> 3;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300299
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300300 if (0 == *count)
301 *count = 32;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300302
Andreas Bombedab7e312010-03-21 16:02:45 -0300303 if (*size * *count > vid_limit * 1024 * 1024)
304 *count = (vid_limit * 1024 * 1024) / *size;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300305
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300306 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300307}
308
Hans Verkuil95c232a2013-04-13 07:41:29 -0300309static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300310 enum v4l2_field field)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300311{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300312 struct cx25821_channel *chan = q->priv_data;
313 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300314 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300315 container_of(vb, struct cx25821_buffer, vb);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300316 int rc, init_buffer = 0;
Hans Verkuil30fdf032012-04-20 06:26:19 -0300317 u32 line0_offset;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300318 struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
319 int bpl_local = LINE_SIZE_D1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300320
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300321 BUG_ON(NULL == chan->fmt);
322 if (chan->width < 48 || chan->width > 720 ||
323 chan->height < 32 || chan->height > 576)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300324 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300325
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300326 buf->vb.size = (chan->width * chan->height * chan->fmt->depth) >> 3;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300327
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300328 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
329 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300330
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300331 if (buf->fmt != chan->fmt ||
332 buf->vb.width != chan->width ||
333 buf->vb.height != chan->height || buf->vb.field != field) {
334 buf->fmt = chan->fmt;
335 buf->vb.width = chan->width;
336 buf->vb.height = chan->height;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300337 buf->vb.field = field;
338 init_buffer = 1;
339 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300340
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300341 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
342 init_buffer = 1;
343 rc = videobuf_iolock(q, &buf->vb, NULL);
344 if (0 != rc) {
Joe Perches36d89f72010-11-07 17:48:21 -0300345 printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n"));
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300346 goto fail;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300347 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300348 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300349
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300350 dprintk(1, "init_buffer=%d\n", init_buffer);
351
352 if (init_buffer) {
Hans Verkuil8d125c52013-04-14 11:57:18 -0300353 if (chan->pixel_formats == PIXEL_FRMT_411)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300354 buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
355 else
356 buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
357
Hans Verkuil8d125c52013-04-14 11:57:18 -0300358 if (chan->pixel_formats == PIXEL_FRMT_411) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300359 bpl_local = buf->bpl;
360 } else {
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800361 bpl_local = buf->bpl; /* Default */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300362
Hans Verkuil8d125c52013-04-14 11:57:18 -0300363 if (chan->use_cif_resolution) {
Hans Verkuil988f7b82013-04-13 13:06:00 -0300364 if (dev->tvnorm & V4L2_STD_625_50)
Hans Verkuil8d125c52013-04-14 11:57:18 -0300365 bpl_local = 352 << 1;
366 else
367 bpl_local = chan->cif_width << 1;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300368 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300369 }
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300370
371 switch (buf->vb.field) {
372 case V4L2_FIELD_TOP:
373 cx25821_risc_buffer(dev->pci, &buf->risc,
374 dma->sglist, 0, UNSET,
375 buf->bpl, 0, buf->vb.height);
376 break;
377 case V4L2_FIELD_BOTTOM:
378 cx25821_risc_buffer(dev->pci, &buf->risc,
379 dma->sglist, UNSET, 0,
380 buf->bpl, 0, buf->vb.height);
381 break;
382 case V4L2_FIELD_INTERLACED:
383 /* All other formats are top field first */
384 line0_offset = 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300385 dprintk(1, "top field first\n");
386
387 cx25821_risc_buffer(dev->pci, &buf->risc,
388 dma->sglist, line0_offset,
389 bpl_local, bpl_local, bpl_local,
390 buf->vb.height >> 1);
391 break;
392 case V4L2_FIELD_SEQ_TB:
393 cx25821_risc_buffer(dev->pci, &buf->risc,
394 dma->sglist,
395 0, buf->bpl * (buf->vb.height >> 1),
396 buf->bpl, 0, buf->vb.height >> 1);
397 break;
398 case V4L2_FIELD_SEQ_BT:
399 cx25821_risc_buffer(dev->pci, &buf->risc,
400 dma->sglist,
401 buf->bpl * (buf->vb.height >> 1), 0,
402 buf->bpl, 0, buf->vb.height >> 1);
403 break;
404 default:
405 BUG();
406 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300407 }
408
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300409 dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300410 buf, buf->vb.i, chan->width, chan->height, chan->fmt->depth,
411 chan->fmt->name, (unsigned long)buf->risc.dma);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300412
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300413 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300414
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300415 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300416
Leonid V. Fedorenchik2748f262011-09-16 14:14:34 +0800417fail:
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300418 cx25821_free_buffer(q, buf);
419 return rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300420}
421
Hans Verkuil95c232a2013-04-13 07:41:29 -0300422static void cx25821_buffer_release(struct videobuf_queue *q,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800423 struct videobuf_buffer *vb)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300424{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300425 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300426 container_of(vb, struct cx25821_buffer, vb);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300427
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300428 cx25821_free_buffer(q, buf);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300429}
430
Hans Verkuil95c232a2013-04-13 07:41:29 -0300431static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300432{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300433 struct cx25821_channel *chan = video_drvdata(file);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300434
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300435 return videobuf_mmap_mapper(&chan->vidq, vma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300436}
437
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300438
439static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
440{
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800441 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300442 container_of(vb, struct cx25821_buffer, vb);
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800443 struct cx25821_buffer *prev;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300444 struct cx25821_channel *chan = vq->priv_data;
445 struct cx25821_dev *dev = chan->dev;
446 struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300447
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800448 /* add jump to stopper */
449 buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
450 buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
451 buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300452
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800453 dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300454
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800455 if (!list_empty(&q->queued)) {
456 list_add_tail(&buf->vb.queue, &q->queued);
457 buf->vb.state = VIDEOBUF_QUEUED;
458 dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
459 buf->vb.i);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300460
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800461 } else if (list_empty(&q->active)) {
462 list_add_tail(&buf->vb.queue, &q->active);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300463 cx25821_start_video_dma(dev, q, buf, chan->sram_channels);
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800464 buf->vb.state = VIDEOBUF_ACTIVE;
465 buf->count = q->count++;
466 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
467 dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
468 buf, buf->vb.i, buf->count, q->count);
469 } else {
470 prev = list_entry(q->active.prev, struct cx25821_buffer,
471 vb.queue);
472 if (prev->vb.width == buf->vb.width
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300473 && prev->vb.height == buf->vb.height
474 && prev->fmt == buf->fmt) {
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800475 list_add_tail(&buf->vb.queue, &q->active);
476 buf->vb.state = VIDEOBUF_ACTIVE;
477 buf->count = q->count++;
478 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300479
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800480 /* 64 bit bits 63-32 */
481 prev->risc.jmp[2] = cpu_to_le32(0);
482 dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
483 buf, buf->vb.i, buf->count);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300484
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800485 } else {
486 list_add_tail(&buf->vb.queue, &q->queued);
487 buf->vb.state = VIDEOBUF_QUEUED;
488 dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
489 buf->vb.i);
490 }
491 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300492
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800493 if (list_empty(&q->active))
494 dprintk(2, "active queue empty!\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300495}
496
497static struct videobuf_queue_ops cx25821_video_qops = {
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800498 .buf_setup = cx25821_buffer_setup,
499 .buf_prepare = cx25821_buffer_prepare,
500 .buf_queue = buffer_queue,
501 .buf_release = cx25821_buffer_release,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300502};
503
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300504static ssize_t video_read(struct file *file, char __user * data, size_t count,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300505 loff_t *ppos)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300506{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300507 struct v4l2_fh *fh = file->private_data;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300508 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuil8d125c52013-04-14 11:57:18 -0300509 struct cx25821_dev *dev = chan->dev;
Hans Verkuil84293f02013-04-14 11:56:39 -0300510 int err = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300511
Hans Verkuil11f095a2013-04-14 11:54:56 -0300512 if (mutex_lock_interruptible(&dev->lock))
513 return -ERESTARTSYS;
Hans Verkuil84293f02013-04-14 11:56:39 -0300514 if (chan->streaming_fh && chan->streaming_fh != fh) {
Hans Verkuil11f095a2013-04-14 11:54:56 -0300515 err = -EBUSY;
Hans Verkuil84293f02013-04-14 11:56:39 -0300516 goto unlock;
517 }
518 chan->streaming_fh = fh;
519
520 err = videobuf_read_one(&chan->vidq, data, count, ppos,
Hans Verkuil11f095a2013-04-14 11:54:56 -0300521 file->f_flags & O_NONBLOCK);
Hans Verkuil84293f02013-04-14 11:56:39 -0300522unlock:
Hans Verkuil11f095a2013-04-14 11:54:56 -0300523 mutex_unlock(&dev->lock);
524 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300525}
526
527static unsigned int video_poll(struct file *file,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300528 struct poll_table_struct *wait)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300529{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300530 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuil8d125c52013-04-14 11:57:18 -0300531 unsigned long req_events = poll_requested_events(wait);
532 unsigned int res = v4l2_ctrl_poll(file, wait);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300533
Hans Verkuil8d125c52013-04-14 11:57:18 -0300534 if (req_events & (POLLIN | POLLRDNORM))
535 res |= videobuf_poll_stream(file, &chan->vidq, wait);
536 return res;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300537
Hans Verkuil84293f02013-04-14 11:56:39 -0300538 /* This doesn't belong in poll(). This can be done
539 * much better with vb2. We keep this code here as a
540 * reminder.
541 if ((res & POLLIN) && buf->vb.state == VIDEOBUF_DONE) {
542 struct cx25821_dev *dev = chan->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300543
Hans Verkuil84293f02013-04-14 11:56:39 -0300544 if (dev && chan->use_cif_resolution) {
545 u8 cam_id = *((char *)buf->vb.baddr + 3);
546 memcpy((char *)buf->vb.baddr,
547 (char *)buf->vb.baddr + (chan->width * 2),
548 (chan->width * 2));
549 *((char *)buf->vb.baddr + 3) = cam_id;
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800550 }
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800551 }
Hans Verkuil84293f02013-04-14 11:56:39 -0300552 */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300553}
554
555static int video_release(struct file *file)
556{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300557 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuil8d125c52013-04-14 11:57:18 -0300558 struct v4l2_fh *fh = file->private_data;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300559 struct cx25821_dev *dev = chan->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300560 const struct sram_channel *sram_ch =
561 dev->channels[0].sram_channels;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300562
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300563 mutex_lock(&dev->lock);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800564 /* stop the risc engine and fifo */
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300565 cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300566
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800567 /* stop video capture */
Hans Verkuil84293f02013-04-14 11:56:39 -0300568 if (chan->streaming_fh == fh) {
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300569 videobuf_queue_cancel(&chan->vidq);
Hans Verkuil84293f02013-04-14 11:56:39 -0300570 chan->streaming_fh = NULL;
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800571 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300572
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300573 if (chan->vidq.read_buf) {
574 cx25821_buffer_release(&chan->vidq, chan->vidq.read_buf);
575 kfree(chan->vidq.read_buf);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800576 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300577
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300578 videobuf_mmap_free(&chan->vidq);
Hans Verkuil84293f02013-04-14 11:56:39 -0300579 mutex_unlock(&dev->lock);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300580
Hans Verkuil8d125c52013-04-14 11:57:18 -0300581 return v4l2_fh_release(file);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300582}
583
Hans Verkuil95c232a2013-04-13 07:41:29 -0300584/* VIDEO IOCTLS */
585static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
586 struct v4l2_format *f)
587{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300588 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuil95c232a2013-04-13 07:41:29 -0300589
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300590 f->fmt.pix.width = chan->width;
591 f->fmt.pix.height = chan->height;
592 f->fmt.pix.field = chan->vidq.field;
593 f->fmt.pix.pixelformat = chan->fmt->fourcc;
Hans Verkuil988f7b82013-04-13 13:06:00 -0300594 f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3;
595 f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline;
596 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
597 f->fmt.pix.priv = 0;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300598
599 return 0;
600}
601
602static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
603 struct v4l2_format *f)
604{
Hans Verkuil988f7b82013-04-13 13:06:00 -0300605 struct cx25821_channel *chan = video_drvdata(file);
606 struct cx25821_dev *dev = chan->dev;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300607 const struct cx25821_fmt *fmt;
Hans Verkuil988f7b82013-04-13 13:06:00 -0300608 enum v4l2_field field = f->fmt.pix.field;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300609 unsigned int maxw, maxh;
Hans Verkuil988f7b82013-04-13 13:06:00 -0300610 unsigned w;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300611
612 fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
613 if (NULL == fmt)
614 return -EINVAL;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300615 maxw = 720;
Hans Verkuil988f7b82013-04-13 13:06:00 -0300616 maxh = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300617
Hans Verkuil988f7b82013-04-13 13:06:00 -0300618 w = f->fmt.pix.width;
619 if (field != V4L2_FIELD_BOTTOM)
620 field = V4L2_FIELD_TOP;
621 if (w < 352) {
622 w = 176;
623 f->fmt.pix.height = maxh / 4;
624 } else if (w < 720) {
625 w = 352;
626 f->fmt.pix.height = maxh / 2;
627 } else {
628 w = 720;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300629 f->fmt.pix.height = maxh;
Hans Verkuil988f7b82013-04-13 13:06:00 -0300630 field = V4L2_FIELD_INTERLACED;
631 }
632 f->fmt.pix.field = field;
633 f->fmt.pix.width = w;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300634 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
635 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
Hans Verkuil988f7b82013-04-13 13:06:00 -0300636 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
637 f->fmt.pix.priv = 0;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300638
639 return 0;
640}
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300641static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
642{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300643 struct cx25821_channel *chan = video_drvdata(file);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300644
Hans Verkuil11f095a2013-04-14 11:54:56 -0300645 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800646 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300647
Hans Verkuil8d125c52013-04-14 11:57:18 -0300648 if (chan->streaming_fh && chan->streaming_fh != priv)
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800649 return -EBUSY;
Hans Verkuil8d125c52013-04-14 11:57:18 -0300650 chan->streaming_fh = priv;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300651
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300652 return videobuf_streamon(&chan->vidq);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300653}
654
655static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
656{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300657 struct cx25821_channel *chan = video_drvdata(file);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300658
Hans Verkuil11f095a2013-04-14 11:54:56 -0300659 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800660 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300661
Hans Verkuil8d125c52013-04-14 11:57:18 -0300662 if (chan->streaming_fh && chan->streaming_fh != priv)
Hans Verkuil84293f02013-04-14 11:56:39 -0300663 return -EBUSY;
664 if (chan->streaming_fh == NULL)
665 return 0;
666
667 chan->streaming_fh = NULL;
668 return videobuf_streamoff(&chan->vidq);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300669}
670
671static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800672 struct v4l2_format *f)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300673{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300674 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuil8d125c52013-04-14 11:57:18 -0300675 struct cx25821_dev *dev = chan->dev;
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300676 struct v4l2_mbus_framefmt mbus_fmt;
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800677 int err;
678 int pix_format = PIXEL_FRMT_422;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300679
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800680 err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300681
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800682 if (0 != err)
683 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300684
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300685 chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
686 chan->vidq.field = f->fmt.pix.field;
Hans Verkuil988f7b82013-04-13 13:06:00 -0300687 chan->width = f->fmt.pix.width;
688 chan->height = f->fmt.pix.height;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300689
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800690 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
691 pix_format = PIXEL_FRMT_411;
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800692 else
Hans Verkuil988f7b82013-04-13 13:06:00 -0300693 pix_format = PIXEL_FRMT_422;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300694
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800695 cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300696
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800697 /* check if cif resolution */
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300698 if (chan->width == 320 || chan->width == 352)
699 chan->use_cif_resolution = 1;
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800700 else
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300701 chan->use_cif_resolution = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300702
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300703 chan->cif_width = chan->width;
704 medusa_set_resolution(dev, chan->width, SRAM_CH00);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300705
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300706 v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
707 cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300708
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800709 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300710}
711
712static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
713{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800714 int ret_val = 0;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300715 struct cx25821_channel *chan = video_drvdata(file);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300716
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300717 ret_val = videobuf_dqbuf(&chan->vidq, p, file->f_flags & O_NONBLOCK);
718 p->sequence = chan->dma_vidq.count;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300719
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800720 return ret_val;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300721}
722
723static int vidioc_log_status(struct file *file, void *priv)
724{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300725 struct cx25821_channel *chan = video_drvdata(file);
726 struct cx25821_dev *dev = chan->dev;
727 const struct sram_channel *sram_ch = chan->sram_channels;
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800728 u32 tmp = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300729
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800730 cx25821_call_all(dev, core, log_status);
731 tmp = cx_read(sram_ch->dma_ctl);
Joe Perches36d89f72010-11-07 17:48:21 -0300732 pr_info("Video input 0 is %s\n",
733 (tmp & 0x11) ? "streaming" : "stopped");
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800734 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300735}
736
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300737
Hans Verkuil95c232a2013-04-13 07:41:29 -0300738static int cx25821_vidioc_querycap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800739 struct v4l2_capability *cap)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300740{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300741 struct cx25821_channel *chan = video_drvdata(file);
742 struct cx25821_dev *dev = chan->dev;
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300743 const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE |
744 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
745 const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300746
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300747 strcpy(cap->driver, "cx25821");
748 strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
749 sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
Hans Verkuil8d125c52013-04-14 11:57:18 -0300750 if (chan->id >= VID_CHANNEL_NUM)
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300751 cap->device_caps = cap_output;
752 else
753 cap->device_caps = cap_input;
754 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300755 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300756}
757
Hans Verkuil95c232a2013-04-13 07:41:29 -0300758static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300759 struct v4l2_fmtdesc *f)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300760{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300761 if (unlikely(f->index >= ARRAY_SIZE(formats)))
762 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300763
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300764 strlcpy(f->description, formats[f->index].name, sizeof(f->description));
765 f->pixelformat = formats[f->index].fourcc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300766
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300767 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300768}
769
Hans Verkuil95c232a2013-04-13 07:41:29 -0300770static int cx25821_vidioc_reqbufs(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800771 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300772{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300773 struct cx25821_channel *chan = video_drvdata(file);
774
775 return videobuf_reqbufs(&chan->vidq, p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300776}
777
Hans Verkuil95c232a2013-04-13 07:41:29 -0300778static int cx25821_vidioc_querybuf(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800779 struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300780{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300781 struct cx25821_channel *chan = video_drvdata(file);
782
783 return videobuf_querybuf(&chan->vidq, p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300784}
785
Hans Verkuil95c232a2013-04-13 07:41:29 -0300786static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300787{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300788 struct cx25821_channel *chan = video_drvdata(file);
789
790 return videobuf_qbuf(&chan->vidq, p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300791}
792
Hans Verkuil95c232a2013-04-13 07:41:29 -0300793static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
Hans Verkuil18c73af2013-04-13 05:50:18 -0300794{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300795 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuil18c73af2013-04-13 05:50:18 -0300796
Hans Verkuil8d125c52013-04-14 11:57:18 -0300797 *tvnorms = chan->dev->tvnorm;
Hans Verkuil18c73af2013-04-13 05:50:18 -0300798 return 0;
799}
800
Hans Verkuil314527a2013-03-15 06:10:40 -0300801int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300802{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300803 struct cx25821_channel *chan = video_drvdata(file);
804 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300805
Hans Verkuil314527a2013-03-15 06:10:40 -0300806 if (dev->tvnorm == tvnorms)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300807 return 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300808
Hans Verkuil314527a2013-03-15 06:10:40 -0300809 cx25821_set_tvnorm(dev, tvnorms);
Hans Verkuil988f7b82013-04-13 13:06:00 -0300810 chan->width = 720;
811 chan->height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300812
813 medusa_set_videostandard(dev);
814
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300815 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300816}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300817
Hans Verkuil95c232a2013-04-13 07:41:29 -0300818static int cx25821_vidioc_enum_input(struct file *file, void *priv,
819 struct v4l2_input *i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300820{
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +0800821 static const char * const iname[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300822 [CX25821_VMUX_COMPOSITE] = "Composite",
823 [CX25821_VMUX_SVIDEO] = "S-Video",
824 [CX25821_VMUX_DEBUG] = "for debug only",
825 };
Hans Verkuil8d125c52013-04-14 11:57:18 -0300826 struct cx25821_channel *chan = video_drvdata(file);
827 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300828 unsigned int n;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300829
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300830 n = i->index;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300831 if (n >= CX25821_NR_INPUT)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300832 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300833
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300834 if (0 == INPUT(n)->type)
835 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300836
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300837 i->type = V4L2_INPUT_TYPE_CAMERA;
838 strcpy(i->name, iname[INPUT(n)->type]);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300839
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300840 i->std = CX25821_NORMS;
841 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300842}
843
Hans Verkuil95c232a2013-04-13 07:41:29 -0300844static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300845{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300846 struct cx25821_channel *chan = video_drvdata(file);
847 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300848
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300849 *i = dev->input;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300850 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300851}
852
Hans Verkuil95c232a2013-04-13 07:41:29 -0300853static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300854{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300855 struct cx25821_channel *chan = video_drvdata(file);
856 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300857
Hans Verkuil6b1dce22013-04-13 07:39:19 -0300858 if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300859 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300860
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300861 cx25821_video_mux(dev, i);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300862 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300863}
864
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300865#ifdef CONFIG_VIDEO_ADV_DEBUG
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -0300866int cx25821_vidioc_g_register(struct file *file, void *fh,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300867 struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300868{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300869 struct cx25821_channel *chan = video_drvdata(file);
870 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300871
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300872 if (!v4l2_chip_match_host(&reg->match))
873 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300874
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300875 cx25821_call_all(dev, core, g_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300876
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300877 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300878}
879
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -0300880int cx25821_vidioc_s_register(struct file *file, void *fh,
Hans Verkuil977ba3b2013-03-24 08:28:46 -0300881 const struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300882{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300883 struct cx25821_channel *chan = video_drvdata(file);
884 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300885
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300886 if (!v4l2_chip_match_host(&reg->match))
887 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300888
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300889 cx25821_call_all(dev, core, s_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300890
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300891 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300892}
893
894#endif
895
Hans Verkuilf8d7ee72013-04-13 08:38:14 -0300896static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300897{
Hans Verkuilf8d7ee72013-04-13 08:38:14 -0300898 struct cx25821_channel *chan =
899 container_of(ctrl->handler, struct cx25821_channel, hdl);
900 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300901
Hans Verkuilf8d7ee72013-04-13 08:38:14 -0300902 switch (ctrl->id) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300903 case V4L2_CID_BRIGHTNESS:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -0300904 medusa_set_brightness(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300905 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300906 case V4L2_CID_HUE:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -0300907 medusa_set_hue(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300908 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300909 case V4L2_CID_CONTRAST:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -0300910 medusa_set_contrast(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300911 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300912 case V4L2_CID_SATURATION:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -0300913 medusa_set_saturation(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300914 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300915 default:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -0300916 return -EINVAL;
Joe Perches95cd17c2011-04-10 14:31:35 -0700917 }
Hans Verkuilf8d7ee72013-04-13 08:38:14 -0300918 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300919}
920
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300921static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300922 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300923{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300924 struct cx25821_channel *chan = video_drvdata(file);
925 struct cx25821_dev *dev = chan->dev;
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +0800926 int command = 0;
927 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300928
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +0800929 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300930
Joe Perches36d89f72010-11-07 17:48:21 -0300931 if (!data_from_user) {
932 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
933 return 0;
934 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300935
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +0800936 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300937
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +0800938 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
939 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300940
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +0800941 dev->input_filename = data_from_user->input_filename;
942 dev->input_audiofilename = data_from_user->input_filename;
943 dev->vid_stdname = data_from_user->vid_stdname;
944 dev->pixel_format = data_from_user->pixel_format;
945 dev->channel_select = data_from_user->channel_select;
946 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300947
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +0800948 switch (command) {
949 case UPSTREAM_START_VIDEO:
950 cx25821_start_upstream_video_ch1(dev, data_from_user);
951 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300952
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +0800953 case UPSTREAM_STOP_VIDEO:
954 cx25821_stop_upstream_video_ch1(dev);
955 break;
956 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300957
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +0800958 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300959}
960
961static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300962 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300963{
Hans Verkuil8d125c52013-04-14 11:57:18 -0300964 struct cx25821_channel *chan = video_drvdata(file);
965 struct cx25821_dev *dev = chan->dev;
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +0800966 int command = 0;
967 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300968
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +0800969 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300970
Joe Perches36d89f72010-11-07 17:48:21 -0300971 if (!data_from_user) {
972 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
973 return 0;
974 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300975
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +0800976 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300977
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +0800978 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
979 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300980
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +0800981 dev->input_filename_ch2 = data_from_user->input_filename;
982 dev->input_audiofilename = data_from_user->input_filename;
983 dev->vid_stdname_ch2 = data_from_user->vid_stdname;
984 dev->pixel_format_ch2 = data_from_user->pixel_format;
985 dev->channel_select_ch2 = data_from_user->channel_select;
986 dev->command_ch2 = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300987
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +0800988 switch (command) {
989 case UPSTREAM_START_VIDEO:
990 cx25821_start_upstream_video_ch2(dev, data_from_user);
991 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300992
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +0800993 case UPSTREAM_STOP_VIDEO:
994 cx25821_stop_upstream_video_ch2(dev);
995 break;
996 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300997
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +0800998 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300999}
1000
1001static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001002 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001003{
Hans Verkuil8d125c52013-04-14 11:57:18 -03001004 struct cx25821_channel *chan = video_drvdata(file);
1005 struct cx25821_dev *dev = chan->dev;
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001006 int command = 0;
1007 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001008
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001009 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001010
Joe Perches36d89f72010-11-07 17:48:21 -03001011 if (!data_from_user) {
1012 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1013 return 0;
1014 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001015
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001016 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001017
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001018 if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO)
1019 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001020
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001021 dev->input_filename = data_from_user->input_filename;
1022 dev->input_audiofilename = data_from_user->input_filename;
1023 dev->vid_stdname = data_from_user->vid_stdname;
1024 dev->pixel_format = data_from_user->pixel_format;
1025 dev->channel_select = data_from_user->channel_select;
1026 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001027
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001028 switch (command) {
1029 case UPSTREAM_START_AUDIO:
1030 cx25821_start_upstream_audio(dev, data_from_user);
1031 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001032
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001033 case UPSTREAM_STOP_AUDIO:
1034 cx25821_stop_upstream_audio(dev);
1035 break;
1036 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001037
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001038 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001039}
1040
1041static long video_ioctl_set(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001042 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001043{
Hans Verkuil8d125c52013-04-14 11:57:18 -03001044 struct cx25821_channel *chan = video_drvdata(file);
1045 struct cx25821_dev *dev = chan->dev;
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001046 struct downstream_user_struct *data_from_user;
1047 int command;
1048 int width = 720;
Leonid V. Fedorenchik4a33b6f2011-10-22 01:43:52 -03001049 int selected_channel = 0;
1050 int pix_format = 0;
1051 int i = 0;
1052 int cif_enable = 0;
1053 int cif_width = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001054
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001055 data_from_user = (struct downstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001056
Joe Perches36d89f72010-11-07 17:48:21 -03001057 if (!data_from_user) {
1058 pr_err("%s(): User data is INVALID. Returning\n", __func__);
1059 return 0;
1060 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001061
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001062 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001063
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001064 if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001065 && command != ENABLE_CIF_RESOLUTION && command != REG_READ
1066 && command != REG_WRITE && command != MEDUSA_READ
1067 && command != MEDUSA_WRITE) {
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001068 return 0;
1069 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001070
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001071 switch (command) {
1072 case SET_VIDEO_STD:
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001073 if (!strcmp(data_from_user->vid_stdname, "PAL"))
1074 dev->tvnorm = V4L2_STD_PAL_BG;
1075 else
1076 dev->tvnorm = V4L2_STD_NTSC_M;
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001077 medusa_set_videostandard(dev);
1078 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001079
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001080 case SET_PIXEL_FORMAT:
1081 selected_channel = data_from_user->decoder_select;
1082 pix_format = data_from_user->pixel_format;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001083
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001084 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1085 selected_channel -= 4;
1086 selected_channel = selected_channel % 8;
1087 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001088
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001089 if (selected_channel >= 0)
1090 cx25821_set_pixel_format(dev, selected_channel,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001091 pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001092
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001093 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001094
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001095 case ENABLE_CIF_RESOLUTION:
1096 selected_channel = data_from_user->decoder_select;
1097 cif_enable = data_from_user->cif_resolution_enable;
1098 cif_width = data_from_user->cif_width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001099
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001100 if (cif_enable) {
1101 if (dev->tvnorm & V4L2_STD_PAL_BG
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001102 || dev->tvnorm & V4L2_STD_PAL_DK) {
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001103 width = 352;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001104 } else {
1105 width = cif_width;
1106 if (cif_width != 320 && cif_width != 352)
1107 width = 320;
1108 }
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001109 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001110
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001111 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1112 selected_channel -= 4;
1113 selected_channel = selected_channel % 8;
1114 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001115
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001116 if (selected_channel <= 7 && selected_channel >= 0) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -03001117 dev->channels[selected_channel].use_cif_resolution =
1118 cif_enable;
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001119 dev->channels[selected_channel].cif_width = width;
1120 } else {
1121 for (i = 0; i < VID_CHANNEL_NUM; i++) {
1122 dev->channels[i].use_cif_resolution =
1123 cif_enable;
1124 dev->channels[i].cif_width = width;
1125 }
1126 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001127
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001128 medusa_set_resolution(dev, width, selected_channel);
1129 break;
1130 case REG_READ:
1131 data_from_user->reg_data = cx_read(data_from_user->reg_address);
1132 break;
1133 case REG_WRITE:
1134 cx_write(data_from_user->reg_address, data_from_user->reg_data);
1135 break;
1136 case MEDUSA_READ:
Hans Verkuil30fdf032012-04-20 06:26:19 -03001137 cx25821_i2c_read(&dev->i2c_bus[0],
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001138 (u16) data_from_user->reg_address,
1139 &data_from_user->reg_data);
1140 break;
1141 case MEDUSA_WRITE:
1142 cx25821_i2c_write(&dev->i2c_bus[0],
1143 (u16) data_from_user->reg_address,
1144 data_from_user->reg_data);
1145 break;
1146 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001147
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001148 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001149}
1150
1151static long cx25821_video_ioctl(struct file *file,
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001152 unsigned int cmd, unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001153{
Hans Verkuil8d125c52013-04-14 11:57:18 -03001154 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001155 int ret = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001156
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001157 /* check to see if it's the video upstream */
Hans Verkuil8d125c52013-04-14 11:57:18 -03001158 if (chan->id == SRAM_CH09) {
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001159 ret = video_ioctl_upstream9(file, cmd, arg);
1160 return ret;
Hans Verkuil8d125c52013-04-14 11:57:18 -03001161 } else if (chan->id == SRAM_CH10) {
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001162 ret = video_ioctl_upstream10(file, cmd, arg);
1163 return ret;
Hans Verkuil8d125c52013-04-14 11:57:18 -03001164 } else if (chan->id == SRAM_CH11) {
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001165 ret = video_ioctl_upstream11(file, cmd, arg);
1166 ret = video_ioctl_set(file, cmd, arg);
1167 return ret;
1168 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001169
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001170 return video_ioctl2(file, cmd, arg);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001171}
1172
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001173static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
1174 .s_ctrl = cx25821_s_ctrl,
1175};
1176
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001177static const struct v4l2_file_operations video_fops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001178 .owner = THIS_MODULE,
Hans Verkuil8d125c52013-04-14 11:57:18 -03001179 .open = v4l2_fh_open,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001180 .release = video_release,
1181 .read = video_read,
1182 .poll = video_poll,
1183 .mmap = cx25821_video_mmap,
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001184 .unlocked_ioctl = cx25821_video_ioctl,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001185};
1186
1187static const struct v4l2_ioctl_ops video_ioctl_ops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001188 .vidioc_querycap = cx25821_vidioc_querycap,
1189 .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
1190 .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
1191 .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
1192 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1193 .vidioc_reqbufs = cx25821_vidioc_reqbufs,
1194 .vidioc_querybuf = cx25821_vidioc_querybuf,
1195 .vidioc_qbuf = cx25821_vidioc_qbuf,
1196 .vidioc_dqbuf = vidioc_dqbuf,
Hans Verkuil18c73af2013-04-13 05:50:18 -03001197 .vidioc_g_std = cx25821_vidioc_g_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001198 .vidioc_s_std = cx25821_vidioc_s_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001199 .vidioc_enum_input = cx25821_vidioc_enum_input,
1200 .vidioc_g_input = cx25821_vidioc_g_input,
1201 .vidioc_s_input = cx25821_vidioc_s_input,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001202 .vidioc_streamon = vidioc_streamon,
1203 .vidioc_streamoff = vidioc_streamoff,
1204 .vidioc_log_status = vidioc_log_status,
Hans Verkuil8d125c52013-04-14 11:57:18 -03001205 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
1206 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001207#ifdef CONFIG_VIDEO_ADV_DEBUG
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001208 .vidioc_g_register = cx25821_vidioc_g_register,
1209 .vidioc_s_register = cx25821_vidioc_s_register,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001210#endif
1211};
1212
Hans Verkuilffd3c232013-04-13 05:30:48 -03001213static const struct video_device cx25821_video_device = {
1214 .name = "cx25821-video",
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001215 .fops = &video_fops,
Hans Verkuil467870c2013-04-13 08:18:00 -03001216 .release = video_device_release_empty,
Hans Verkuilffd3c232013-04-13 05:30:48 -03001217 .minor = -1,
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001218 .ioctl_ops = &video_ioctl_ops,
1219 .tvnorms = CX25821_NORMS,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001220};
Hans Verkuilffd3c232013-04-13 05:30:48 -03001221
1222void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
1223{
1224 cx_clear(PCI_INT_MSK, 1);
1225
Hans Verkuil467870c2013-04-13 08:18:00 -03001226 if (video_is_registered(&dev->channels[chan_num].vdev)) {
1227 video_unregister_device(&dev->channels[chan_num].vdev);
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001228 v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001229
1230 btcx_riscmem_free(dev->pci,
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001231 &dev->channels[chan_num].dma_vidq.stopper);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001232 }
Hans Verkuilffd3c232013-04-13 05:30:48 -03001233}
1234
1235int cx25821_video_register(struct cx25821_dev *dev)
1236{
1237 int err;
1238 int i;
1239
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001240 /* initial device configuration */
1241 dev->tvnorm = V4L2_STD_NTSC_M,
1242 cx25821_set_tvnorm(dev, dev->tvnorm);
1243
Hans Verkuilffd3c232013-04-13 05:30:48 -03001244 spin_lock_init(&dev->slock);
1245
1246 for (i = 0; i < VID_CHANNEL_NUM; ++i) {
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001247 struct cx25821_channel *chan = &dev->channels[i];
1248 struct video_device *vdev = &chan->vdev;
1249 struct v4l2_ctrl_handler *hdl = &chan->hdl;
Hans Verkuil467870c2013-04-13 08:18:00 -03001250
Hans Verkuilffd3c232013-04-13 05:30:48 -03001251 if (i == SRAM_CH08) /* audio channel */
1252 continue;
1253
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001254 v4l2_ctrl_handler_init(hdl, 4);
1255 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1256 V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
1257 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1258 V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
1259 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1260 V4L2_CID_SATURATION, 0, 10000, 1, 5000);
1261 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1262 V4L2_CID_HUE, 0, 10000, 1, 5000);
1263 if (hdl->error) {
1264 err = hdl->error;
1265 goto fail_unreg;
1266 }
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001267 err = v4l2_ctrl_handler_setup(hdl);
1268 if (err)
1269 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001270
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001271 cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper,
1272 chan->sram_channels->dma_ctl, 0x11, 0);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001273
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001274 chan->sram_channels = &cx25821_sram_channels[i];
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001275 chan->width = 720;
1276 if (dev->tvnorm & V4L2_STD_625_50)
1277 chan->height = 576;
1278 else
1279 chan->height = 480;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001280
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001281 if (chan->pixel_formats == PIXEL_FRMT_411)
1282 chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_Y41P);
1283 else
1284 chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_YUYV);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001285
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001286 cx_write(chan->sram_channels->int_stat, 0xffffffff);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001287
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001288 INIT_LIST_HEAD(&chan->dma_vidq.active);
1289 INIT_LIST_HEAD(&chan->dma_vidq.queued);
1290
1291 chan->timeout_data.dev = dev;
1292 chan->timeout_data.channel = &cx25821_sram_channels[i];
1293 chan->dma_vidq.timeout.function = cx25821_vid_timeout;
1294 chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data;
1295 init_timer(&chan->dma_vidq.timeout);
1296
1297 videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev,
1298 &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
1299 V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
1300 chan, &dev->lock);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001301
1302 /* register v4l devices */
Hans Verkuil467870c2013-04-13 08:18:00 -03001303 *vdev = cx25821_video_device;
1304 vdev->v4l2_dev = &dev->v4l2_dev;
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001305 vdev->ctrl_handler = hdl;
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001306 vdev->lock = &dev->lock;
Hans Verkuil8d125c52013-04-14 11:57:18 -03001307 set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
Hans Verkuil467870c2013-04-13 08:18:00 -03001308 snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001309 video_set_drvdata(vdev, chan);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001310
Hans Verkuil467870c2013-04-13 08:18:00 -03001311 err = video_register_device(vdev, VFL_TYPE_GRABBER,
1312 video_nr[dev->nr]);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001313
1314 if (err < 0)
1315 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001316 }
1317
1318 /* set PCI interrupt */
1319 cx_set(PCI_INT_MSK, 0xff);
1320
Hans Verkuilffd3c232013-04-13 05:30:48 -03001321 return 0;
1322
1323fail_unreg:
Hans Verkuil467870c2013-04-13 08:18:00 -03001324 while (i >= 0)
1325 cx25821_video_unregister(dev, i--);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001326 return err;
1327}