blob: e7a2db158a0ebe61da8761cb68d7fd82907491eb [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 = "8 bpp, gray",
58 .fourcc = V4L2_PIX_FMT_GREY,
59 .depth = 8,
60 .flags = FORMAT_FLAGS_PACKED,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030061 }, {
Mauro Carvalho Chehabd7d93382010-03-24 14:23:25 -030062 .name = "4:1:1, packed, Y41P",
63 .fourcc = V4L2_PIX_FMT_Y41P,
64 .depth = 12,
65 .flags = FORMAT_FLAGS_PACKED,
66 }, {
67 .name = "4:2:2, packed, YUYV",
68 .fourcc = V4L2_PIX_FMT_YUYV,
69 .depth = 16,
70 .flags = FORMAT_FLAGS_PACKED,
71 }, {
72 .name = "4:2:2, packed, UYVY",
73 .fourcc = V4L2_PIX_FMT_UYVY,
74 .depth = 16,
75 .flags = FORMAT_FLAGS_PACKED,
76 }, {
77 .name = "4:2:0, YUV",
78 .fourcc = V4L2_PIX_FMT_YUV420,
79 .depth = 12,
80 .flags = FORMAT_FLAGS_PACKED,
81 },
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030082};
83
Hans Verkuil95c232a2013-04-13 07:41:29 -030084static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030085{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030086 unsigned int i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030087
Leonid V. Fedorenchike313e1f2011-09-16 14:15:13 +080088 if (fourcc == V4L2_PIX_FMT_Y41P || fourcc == V4L2_PIX_FMT_YUV411P)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030089 return formats + 1;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -030090
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030091 for (i = 0; i < ARRAY_SIZE(formats); i++)
92 if (formats[i].fourcc == fourcc)
93 return formats + i;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030094
Joe Perches36d89f72010-11-07 17:48:21 -030095 pr_err("%s(0x%08x) NOT FOUND\n", __func__, fourcc);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030096 return NULL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -030097}
98
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -030099void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
100 u32 count)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300101{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300102 struct cx25821_buffer *buf;
103 int bc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300104
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300105 for (bc = 0;; bc++) {
106 if (list_empty(&q->active)) {
107 dprintk(1, "bc=%d (=0: active empty)\n", bc);
108 break;
109 }
110
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300111 buf = list_entry(q->active.next, struct cx25821_buffer,
112 vb.queue);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300113
114 /* count comes from the hw and it is 16bit wide --
115 * this trick handles wrap-arounds correctly for
116 * up to 32767 buffers in flight... */
Leonid V. Fedorenchike313e1f2011-09-16 14:15:13 +0800117 if ((s16) (count - buf->count) < 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300118 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300119
Sakari Ailus8e6057b2012-09-15 15:14:42 -0300120 v4l2_get_timestamp(&buf->vb.ts);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300121 buf->vb.state = VIDEOBUF_DONE;
122 list_del(&buf->vb.queue);
123 wake_up(&buf->vb.done);
124 }
125
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300126 if (list_empty(&q->active))
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300127 del_timer(&q->timeout);
128 else
129 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
130 if (bc != 1)
Leonid V. Fedorenchik692cfb92011-09-16 14:14:36 +0800131 pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300132}
133
Hans Verkuil95c232a2013-04-13 07:41:29 -0300134static int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300135{
Joe Perches36d89f72010-11-07 17:48:21 -0300136 dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
137 __func__, (unsigned int)norm, v4l2_norm_to_name(norm));
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300138
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300139 dev->tvnorm = norm;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300140
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300141 /* Tell the internal A/V decoder */
142 cx25821_call_all(dev, core, s_std, norm);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300143
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300144 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300145}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300146
Hans Verkuil95c232a2013-04-13 07:41:29 -0300147static int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300148{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300149 struct v4l2_routing route;
150 memset(&route, 0, sizeof(route));
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300151
Joe Perches36d89f72010-11-07 17:48:21 -0300152 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 -0300153 __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0,
154 INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3);
155 dev->input = input;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300156
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300157 route.input = INPUT(input)->vmux;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300158
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300159 /* Tell the internal A/V decoder */
160 cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300161
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300162 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300163}
164
165int cx25821_start_video_dma(struct cx25821_dev *dev,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300166 struct cx25821_dmaqueue *q,
167 struct cx25821_buffer *buf,
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300168 const struct sram_channel *channel)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300169{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300170 int tmp = 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300171
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300172 /* setup fifo + format */
173 cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300174
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300175 /* reset counter */
176 cx_write(channel->gpcnt_ctl, 3);
177 q->count = 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300178
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300179 /* enable irq */
180 cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i));
181 cx_set(channel->int_msk, 0x11);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300182
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300183 /* start dma */
184 cx_write(channel->dma_ctl, 0x11); /* FIFO and RISC enable */
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300185
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300186 /* make sure upstream setting if any is reversed */
187 tmp = cx_read(VID_CH_MODE_SEL);
188 cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300189
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300190 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300191}
192
Mauro Carvalho Chehabdafc4562012-10-27 12:42:59 -0300193static int cx25821_restart_video_queue(struct cx25821_dev *dev,
194 struct cx25821_dmaqueue *q,
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300195 const struct sram_channel *channel)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300196{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300197 struct cx25821_buffer *buf, *prev;
198 struct list_head *item;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300199
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300200 if (!list_empty(&q->active)) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300201 buf = list_entry(q->active.next, struct cx25821_buffer,
202 vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300203
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300204 cx25821_start_video_dma(dev, q, buf, channel);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300205
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300206 list_for_each(item, &q->active) {
207 buf = list_entry(item, struct cx25821_buffer, vb.queue);
208 buf->count = q->count++;
209 }
210
211 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
212 return 0;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300213 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300214
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300215 prev = NULL;
216 for (;;) {
217 if (list_empty(&q->queued))
218 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300219
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300220 buf = list_entry(q->queued.next, struct cx25821_buffer,
221 vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300222
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300223 if (NULL == prev) {
224 list_move_tail(&buf->vb.queue, &q->active);
225 cx25821_start_video_dma(dev, q, buf, channel);
226 buf->vb.state = VIDEOBUF_ACTIVE;
227 buf->count = q->count++;
228 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
229 } else if (prev->vb.width == buf->vb.width &&
230 prev->vb.height == buf->vb.height &&
231 prev->fmt == buf->fmt) {
232 list_move_tail(&buf->vb.queue, &q->active);
233 buf->vb.state = VIDEOBUF_ACTIVE;
234 buf->count = q->count++;
235 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800236 prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300237 } else {
238 return 0;
239 }
240 prev = buf;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300241 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300242}
243
Mauro Carvalho Chehabdafc4562012-10-27 12:42:59 -0300244static void cx25821_vid_timeout(unsigned long data)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300245{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300246 struct cx25821_data *timeout_data = (struct cx25821_data *)data;
247 struct cx25821_dev *dev = timeout_data->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300248 const struct sram_channel *channel = timeout_data->channel;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300249 struct cx25821_dmaqueue *q = &dev->channels[channel->i].dma_vidq;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300250 struct cx25821_buffer *buf;
251 unsigned long flags;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300252
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800253 /* cx25821_sram_channel_dump(dev, channel); */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300254 cx_clear(channel->dma_ctl, 0x11);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300255
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300256 spin_lock_irqsave(&dev->slock, flags);
257 while (!list_empty(&q->active)) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300258 buf = list_entry(q->active.next, struct cx25821_buffer,
259 vb.queue);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300260 list_del(&buf->vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300261
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300262 buf->vb.state = VIDEOBUF_ERROR;
263 wake_up(&buf->vb.done);
264 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300265
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300266 cx25821_restart_video_queue(dev, q, channel);
267 spin_unlock_irqrestore(&dev->slock, flags);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300268}
269
270int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
271{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300272 u32 count = 0;
273 int handled = 0;
274 u32 mask;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300275 const struct sram_channel *channel = dev->channels[chan_num].sram_channels;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300276
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300277 mask = cx_read(channel->int_msk);
278 if (0 == (status & mask))
279 return handled;
280
281 cx_write(channel->int_stat, status);
282
283 /* risc op code error */
284 if (status & (1 << 16)) {
Joe Perches36d89f72010-11-07 17:48:21 -0300285 pr_warn("%s, %s: video risc op code error\n",
286 dev->name, channel->name);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300287 cx_clear(channel->dma_ctl, 0x11);
288 cx25821_sram_channel_dump(dev, channel);
289 }
290
291 /* risc1 y */
292 if (status & FLD_VID_DST_RISC1) {
293 spin_lock(&dev->slock);
294 count = cx_read(channel->gpcnt);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300295 cx25821_video_wakeup(dev, &dev->channels[channel->i].dma_vidq,
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800296 count);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300297 spin_unlock(&dev->slock);
298 handled++;
299 }
300
301 /* risc2 y */
302 if (status & 0x10) {
303 dprintk(2, "stopper video\n");
304 spin_lock(&dev->slock);
Leonid V. Fedorenchik788d0f32011-09-16 14:14:39 +0800305 cx25821_restart_video_queue(dev,
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300306 &dev->channels[channel->i].dma_vidq, channel);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300307 spin_unlock(&dev->slock);
308 handled++;
309 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300310 return handled;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300311}
312
Hans Verkuil95c232a2013-04-13 07:41:29 -0300313static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300314 unsigned int *size)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300315{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300316 struct cx25821_channel *chan = q->priv_data;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300317
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300318 *size = chan->fmt->depth * chan->width * chan->height >> 3;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300319
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300320 if (0 == *count)
321 *count = 32;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300322
Andreas Bombedab7e312010-03-21 16:02:45 -0300323 if (*size * *count > vid_limit * 1024 * 1024)
324 *count = (vid_limit * 1024 * 1024) / *size;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300325
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300326 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300327}
328
Hans Verkuil95c232a2013-04-13 07:41:29 -0300329static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300330 enum v4l2_field field)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300331{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300332 struct cx25821_channel *chan = q->priv_data;
333 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300334 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300335 container_of(vb, struct cx25821_buffer, vb);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300336 int rc, init_buffer = 0;
Hans Verkuil30fdf032012-04-20 06:26:19 -0300337 u32 line0_offset;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300338 struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
339 int bpl_local = LINE_SIZE_D1;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300340 int channel_opened = chan->id;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300341
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300342 BUG_ON(NULL == chan->fmt);
343 if (chan->width < 48 || chan->width > 720 ||
344 chan->height < 32 || chan->height > 576)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300345 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300346
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300347 buf->vb.size = (chan->width * chan->height * chan->fmt->depth) >> 3;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300348
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300349 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
350 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300351
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300352 if (buf->fmt != chan->fmt ||
353 buf->vb.width != chan->width ||
354 buf->vb.height != chan->height || buf->vb.field != field) {
355 buf->fmt = chan->fmt;
356 buf->vb.width = chan->width;
357 buf->vb.height = chan->height;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300358 buf->vb.field = field;
359 init_buffer = 1;
360 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300361
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300362 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
363 init_buffer = 1;
364 rc = videobuf_iolock(q, &buf->vb, NULL);
365 if (0 != rc) {
Joe Perches36d89f72010-11-07 17:48:21 -0300366 printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n"));
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300367 goto fail;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300368 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300369 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300370
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300371 dprintk(1, "init_buffer=%d\n", init_buffer);
372
373 if (init_buffer) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300374 channel_opened = dev->channel_opened;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +0800375 if (channel_opened < 0 || channel_opened > 7)
376 channel_opened = 7;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300377
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800378 if (dev->channels[channel_opened].pixel_formats ==
379 PIXEL_FRMT_411)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300380 buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
381 else
382 buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
383
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800384 if (dev->channels[channel_opened].pixel_formats ==
385 PIXEL_FRMT_411) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300386 bpl_local = buf->bpl;
387 } else {
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800388 bpl_local = buf->bpl; /* Default */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300389
390 if (channel_opened >= 0 && channel_opened <= 7) {
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800391 if (dev->channels[channel_opened]
392 .use_cif_resolution) {
Leonid V. Fedorenchikcd52b2c2011-10-22 01:43:53 -0300393 if (dev->tvnorm & V4L2_STD_PAL_BG ||
394 dev->tvnorm & V4L2_STD_PAL_DK)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300395 bpl_local = 352 << 1;
396 else
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300397 bpl_local = dev->channels[
398 channel_opened].
399 cif_width << 1;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300400 }
401 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300402 }
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300403
404 switch (buf->vb.field) {
405 case V4L2_FIELD_TOP:
406 cx25821_risc_buffer(dev->pci, &buf->risc,
407 dma->sglist, 0, UNSET,
408 buf->bpl, 0, buf->vb.height);
409 break;
410 case V4L2_FIELD_BOTTOM:
411 cx25821_risc_buffer(dev->pci, &buf->risc,
412 dma->sglist, UNSET, 0,
413 buf->bpl, 0, buf->vb.height);
414 break;
415 case V4L2_FIELD_INTERLACED:
416 /* All other formats are top field first */
417 line0_offset = 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300418 dprintk(1, "top field first\n");
419
420 cx25821_risc_buffer(dev->pci, &buf->risc,
421 dma->sglist, line0_offset,
422 bpl_local, bpl_local, bpl_local,
423 buf->vb.height >> 1);
424 break;
425 case V4L2_FIELD_SEQ_TB:
426 cx25821_risc_buffer(dev->pci, &buf->risc,
427 dma->sglist,
428 0, buf->bpl * (buf->vb.height >> 1),
429 buf->bpl, 0, buf->vb.height >> 1);
430 break;
431 case V4L2_FIELD_SEQ_BT:
432 cx25821_risc_buffer(dev->pci, &buf->risc,
433 dma->sglist,
434 buf->bpl * (buf->vb.height >> 1), 0,
435 buf->bpl, 0, buf->vb.height >> 1);
436 break;
437 default:
438 BUG();
439 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300440 }
441
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300442 dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300443 buf, buf->vb.i, chan->width, chan->height, chan->fmt->depth,
444 chan->fmt->name, (unsigned long)buf->risc.dma);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300445
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300446 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300447
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300448 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300449
Leonid V. Fedorenchik2748f262011-09-16 14:14:34 +0800450fail:
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300451 cx25821_free_buffer(q, buf);
452 return rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300453}
454
Hans Verkuil95c232a2013-04-13 07:41:29 -0300455static void cx25821_buffer_release(struct videobuf_queue *q,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800456 struct videobuf_buffer *vb)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300457{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300458 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300459 container_of(vb, struct cx25821_buffer, vb);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300460
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300461 cx25821_free_buffer(q, buf);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300462}
463
Hans Verkuil95c232a2013-04-13 07:41:29 -0300464static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300465{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300466 struct cx25821_channel *chan = video_drvdata(file);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300467
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300468 return videobuf_mmap_mapper(&chan->vidq, vma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300469}
470
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300471
472static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
473{
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800474 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300475 container_of(vb, struct cx25821_buffer, vb);
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800476 struct cx25821_buffer *prev;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300477 struct cx25821_channel *chan = vq->priv_data;
478 struct cx25821_dev *dev = chan->dev;
479 struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300480
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800481 /* add jump to stopper */
482 buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
483 buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
484 buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300485
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800486 dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300487
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800488 if (!list_empty(&q->queued)) {
489 list_add_tail(&buf->vb.queue, &q->queued);
490 buf->vb.state = VIDEOBUF_QUEUED;
491 dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
492 buf->vb.i);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300493
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800494 } else if (list_empty(&q->active)) {
495 list_add_tail(&buf->vb.queue, &q->active);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300496 cx25821_start_video_dma(dev, q, buf, chan->sram_channels);
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800497 buf->vb.state = VIDEOBUF_ACTIVE;
498 buf->count = q->count++;
499 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
500 dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
501 buf, buf->vb.i, buf->count, q->count);
502 } else {
503 prev = list_entry(q->active.prev, struct cx25821_buffer,
504 vb.queue);
505 if (prev->vb.width == buf->vb.width
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300506 && prev->vb.height == buf->vb.height
507 && prev->fmt == buf->fmt) {
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800508 list_add_tail(&buf->vb.queue, &q->active);
509 buf->vb.state = VIDEOBUF_ACTIVE;
510 buf->count = q->count++;
511 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300512
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800513 /* 64 bit bits 63-32 */
514 prev->risc.jmp[2] = cpu_to_le32(0);
515 dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
516 buf, buf->vb.i, buf->count);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300517
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800518 } else {
519 list_add_tail(&buf->vb.queue, &q->queued);
520 buf->vb.state = VIDEOBUF_QUEUED;
521 dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
522 buf->vb.i);
523 }
524 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300525
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800526 if (list_empty(&q->active))
527 dprintk(2, "active queue empty!\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300528}
529
530static struct videobuf_queue_ops cx25821_video_qops = {
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800531 .buf_setup = cx25821_buffer_setup,
532 .buf_prepare = cx25821_buffer_prepare,
533 .buf_queue = buffer_queue,
534 .buf_release = cx25821_buffer_release,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300535};
536
537static int video_open(struct file *file)
538{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300539 struct cx25821_channel *chan = video_drvdata(file);
540 struct cx25821_dev *dev = chan->dev;
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800541 struct cx25821_fh *fh;
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300542
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800543 /* allocate + initialize per filehandle data */
544 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
545 if (NULL == fh)
546 return -ENOMEM;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300547
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800548 file->private_data = fh;
549 fh->dev = dev;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300550 fh->channel_id = chan->id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300551
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800552 dev->channel_opened = fh->channel_id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300553
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300554 v4l2_prio_open(&chan->prio, &fh->prio);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300555
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800556 dprintk(1, "post videobuf_queue_init()\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300557
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800558 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300559}
560
561static ssize_t video_read(struct file *file, char __user * data, size_t count,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300562 loff_t *ppos)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300563{
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800564 struct cx25821_fh *fh = file->private_data;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300565 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300566 struct cx25821_dev *dev = fh->dev;
Hans Verkuil84293f02013-04-14 11:56:39 -0300567 int err = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300568
Hans Verkuil11f095a2013-04-14 11:54:56 -0300569 if (mutex_lock_interruptible(&dev->lock))
570 return -ERESTARTSYS;
Hans Verkuil84293f02013-04-14 11:56:39 -0300571 if (chan->streaming_fh && chan->streaming_fh != fh) {
Hans Verkuil11f095a2013-04-14 11:54:56 -0300572 err = -EBUSY;
Hans Verkuil84293f02013-04-14 11:56:39 -0300573 goto unlock;
574 }
575 chan->streaming_fh = fh;
576
577 err = videobuf_read_one(&chan->vidq, data, count, ppos,
Hans Verkuil11f095a2013-04-14 11:54:56 -0300578 file->f_flags & O_NONBLOCK);
Hans Verkuil84293f02013-04-14 11:56:39 -0300579unlock:
Hans Verkuil11f095a2013-04-14 11:54:56 -0300580 mutex_unlock(&dev->lock);
581 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300582}
583
584static unsigned int video_poll(struct file *file,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300585 struct poll_table_struct *wait)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300586{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300587 struct cx25821_channel *chan = video_drvdata(file);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300588
Hans Verkuil84293f02013-04-14 11:56:39 -0300589 return videobuf_poll_stream(file, &chan->vidq, wait);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300590
Hans Verkuil84293f02013-04-14 11:56:39 -0300591 /* This doesn't belong in poll(). This can be done
592 * much better with vb2. We keep this code here as a
593 * reminder.
594 if ((res & POLLIN) && buf->vb.state == VIDEOBUF_DONE) {
595 struct cx25821_dev *dev = chan->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300596
Hans Verkuil84293f02013-04-14 11:56:39 -0300597 if (dev && chan->use_cif_resolution) {
598 u8 cam_id = *((char *)buf->vb.baddr + 3);
599 memcpy((char *)buf->vb.baddr,
600 (char *)buf->vb.baddr + (chan->width * 2),
601 (chan->width * 2));
602 *((char *)buf->vb.baddr + 3) = cam_id;
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800603 }
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800604 }
Hans Verkuil84293f02013-04-14 11:56:39 -0300605 */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300606}
607
608static int video_release(struct file *file)
609{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300610 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800611 struct cx25821_fh *fh = file->private_data;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300612 struct cx25821_dev *dev = chan->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300613 const struct sram_channel *sram_ch =
614 dev->channels[0].sram_channels;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300615
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300616 mutex_lock(&dev->lock);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800617 /* stop the risc engine and fifo */
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300618 cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300619
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800620 /* stop video capture */
Hans Verkuil84293f02013-04-14 11:56:39 -0300621 if (chan->streaming_fh == fh) {
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300622 videobuf_queue_cancel(&chan->vidq);
Hans Verkuil84293f02013-04-14 11:56:39 -0300623 chan->streaming_fh = NULL;
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800624 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300625
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300626 if (chan->vidq.read_buf) {
627 cx25821_buffer_release(&chan->vidq, chan->vidq.read_buf);
628 kfree(chan->vidq.read_buf);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800629 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300630
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300631 videobuf_mmap_free(&chan->vidq);
Hans Verkuil84293f02013-04-14 11:56:39 -0300632 mutex_unlock(&dev->lock);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300633
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300634 v4l2_prio_close(&chan->prio, fh->prio);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800635 file->private_data = NULL;
636 kfree(fh);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300637
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800638 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300639}
640
Hans Verkuil95c232a2013-04-13 07:41:29 -0300641/* VIDEO IOCTLS */
642static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
643 struct v4l2_format *f)
644{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300645 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuil95c232a2013-04-13 07:41:29 -0300646
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300647 f->fmt.pix.width = chan->width;
648 f->fmt.pix.height = chan->height;
649 f->fmt.pix.field = chan->vidq.field;
650 f->fmt.pix.pixelformat = chan->fmt->fourcc;
651 f->fmt.pix.bytesperline = (f->fmt.pix.width * chan->fmt->depth) >> 3;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300652 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
653
654 return 0;
655}
656
657static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
658 struct v4l2_format *f)
659{
660 const struct cx25821_fmt *fmt;
661 enum v4l2_field field;
662 unsigned int maxw, maxh;
663
664 fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
665 if (NULL == fmt)
666 return -EINVAL;
667
668 field = f->fmt.pix.field;
669 maxw = 720;
670 maxh = 576;
671
672 if (V4L2_FIELD_ANY == field) {
673 if (f->fmt.pix.height > maxh / 2)
674 field = V4L2_FIELD_INTERLACED;
675 else
676 field = V4L2_FIELD_TOP;
677 }
678
679 switch (field) {
680 case V4L2_FIELD_TOP:
681 case V4L2_FIELD_BOTTOM:
682 maxh = maxh / 2;
683 break;
684 case V4L2_FIELD_INTERLACED:
685 break;
686 default:
687 return -EINVAL;
688 }
689
690 f->fmt.pix.field = field;
691 if (f->fmt.pix.height < 32)
692 f->fmt.pix.height = 32;
693 if (f->fmt.pix.height > maxh)
694 f->fmt.pix.height = maxh;
695 if (f->fmt.pix.width < 48)
696 f->fmt.pix.width = 48;
697 if (f->fmt.pix.width > maxw)
698 f->fmt.pix.width = maxw;
699 f->fmt.pix.width &= ~0x03;
700 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
701 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
702
703 return 0;
704}
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300705static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
706{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300707 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800708 struct cx25821_fh *fh = priv;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300709
Hans Verkuil11f095a2013-04-14 11:54:56 -0300710 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800711 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300712
Hans Verkuil84293f02013-04-14 11:56:39 -0300713 if (chan->streaming_fh && chan->streaming_fh != fh)
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800714 return -EBUSY;
Hans Verkuil84293f02013-04-14 11:56:39 -0300715 chan->streaming_fh = fh;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300716
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300717 return videobuf_streamon(&chan->vidq);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300718}
719
720static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
721{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300722 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800723 struct cx25821_fh *fh = priv;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300724
Hans Verkuil11f095a2013-04-14 11:54:56 -0300725 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800726 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300727
Hans Verkuil84293f02013-04-14 11:56:39 -0300728 if (chan->streaming_fh && chan->streaming_fh != fh)
729 return -EBUSY;
730 if (chan->streaming_fh == NULL)
731 return 0;
732
733 chan->streaming_fh = NULL;
734 return videobuf_streamoff(&chan->vidq);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300735}
736
Hans Verkuil95c232a2013-04-13 07:41:29 -0300737static int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm)
738{
739 if (tvnorm == V4L2_STD_PAL_BG) {
740 if (width == 352 || width == 720)
741 return 1;
742 else
743 return 0;
744 }
745
746 if (tvnorm == V4L2_STD_NTSC_M) {
747 if (width == 320 || width == 352 || width == 720)
748 return 1;
749 else
750 return 0;
751 }
752 return 0;
753}
754
755static int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
756{
757 if (tvnorm == V4L2_STD_PAL_BG) {
758 if (height == 576 || height == 288)
759 return 1;
760 else
761 return 0;
762 }
763
764 if (tvnorm == V4L2_STD_NTSC_M) {
765 if (height == 480 || height == 240)
766 return 1;
767 else
768 return 0;
769 }
770
771 return 0;
772}
773
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300774static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800775 struct v4l2_format *f)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300776{
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800777 struct cx25821_fh *fh = priv;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300778 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800779 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300780 struct v4l2_mbus_framefmt mbus_fmt;
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800781 int err;
782 int pix_format = PIXEL_FRMT_422;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300783
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800784 if (fh) {
785 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
786 fh->prio);
787 if (0 != err)
788 return err;
789 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300790
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800791 err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300792
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800793 if (0 != err)
794 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300795
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300796 chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
797 chan->vidq.field = f->fmt.pix.field;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300798
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800799 /* check if width and height is valid based on set standard */
800 if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300801 chan->width = f->fmt.pix.width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300802
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800803 if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300804 chan->height = f->fmt.pix.height;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300805
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800806 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
807 pix_format = PIXEL_FRMT_411;
808 else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
809 pix_format = PIXEL_FRMT_422;
810 else
811 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300812
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800813 cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300814
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800815 /* check if cif resolution */
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300816 if (chan->width == 320 || chan->width == 352)
817 chan->use_cif_resolution = 1;
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800818 else
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300819 chan->use_cif_resolution = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300820
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300821 chan->cif_width = chan->width;
822 medusa_set_resolution(dev, chan->width, SRAM_CH00);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300823
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300824 v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
825 cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300826
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800827 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300828}
829
830static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
831{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800832 int ret_val = 0;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300833 struct cx25821_channel *chan = video_drvdata(file);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300834
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300835 ret_val = videobuf_dqbuf(&chan->vidq, p, file->f_flags & O_NONBLOCK);
836 p->sequence = chan->dma_vidq.count;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300837
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800838 return ret_val;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300839}
840
841static int vidioc_log_status(struct file *file, void *priv)
842{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800843 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
844 struct cx25821_fh *fh = priv;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300845 const struct sram_channel *sram_ch =
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300846 dev->channels[fh->channel_id].sram_channels;
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800847 u32 tmp = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300848
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800849 cx25821_call_all(dev, core, log_status);
850 tmp = cx_read(sram_ch->dma_ctl);
Joe Perches36d89f72010-11-07 17:48:21 -0300851 pr_info("Video input 0 is %s\n",
852 (tmp & 0x11) ? "streaming" : "stopped");
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800853 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300854}
855
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300856
Hans Verkuil95c232a2013-04-13 07:41:29 -0300857static int cx25821_vidioc_querycap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800858 struct v4l2_capability *cap)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300859{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300860 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300861 struct cx25821_fh *fh = priv;
862 const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE |
863 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
864 const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300865
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300866 strcpy(cap->driver, "cx25821");
867 strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
868 sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300869 if (fh->channel_id >= VID_CHANNEL_NUM)
870 cap->device_caps = cap_output;
871 else
872 cap->device_caps = cap_input;
873 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300874 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300875}
876
Hans Verkuil95c232a2013-04-13 07:41:29 -0300877static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300878 struct v4l2_fmtdesc *f)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300879{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300880 if (unlikely(f->index >= ARRAY_SIZE(formats)))
881 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300882
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300883 strlcpy(f->description, formats[f->index].name, sizeof(f->description));
884 f->pixelformat = formats[f->index].fourcc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300885
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300886 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300887}
888
Hans Verkuil95c232a2013-04-13 07:41:29 -0300889static int cx25821_vidioc_reqbufs(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800890 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300891{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300892 struct cx25821_channel *chan = video_drvdata(file);
893
894 return videobuf_reqbufs(&chan->vidq, p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300895}
896
Hans Verkuil95c232a2013-04-13 07:41:29 -0300897static int cx25821_vidioc_querybuf(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800898 struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300899{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300900 struct cx25821_channel *chan = video_drvdata(file);
901
902 return videobuf_querybuf(&chan->vidq, p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300903}
904
Hans Verkuil95c232a2013-04-13 07:41:29 -0300905static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300906{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300907 struct cx25821_channel *chan = video_drvdata(file);
908
909 return videobuf_qbuf(&chan->vidq, p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300910}
911
Hans Verkuil95c232a2013-04-13 07:41:29 -0300912static int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300913{
914 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +0800915 struct cx25821_fh *fh = f;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300916
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +0800917 *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300918
919 return 0;
920}
921
Hans Verkuil95c232a2013-04-13 07:41:29 -0300922static int cx25821_vidioc_s_priority(struct file *file, void *f,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800923 enum v4l2_priority prio)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300924{
925 struct cx25821_fh *fh = f;
926 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
927
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +0800928 return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio,
929 prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300930}
931
Hans Verkuil95c232a2013-04-13 07:41:29 -0300932static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
Hans Verkuil18c73af2013-04-13 05:50:18 -0300933{
934 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
935
936 *tvnorms = dev->tvnorm;
937 return 0;
938}
939
Hans Verkuil314527a2013-03-15 06:10:40 -0300940int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300941{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300942 struct cx25821_fh *fh = priv;
943 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
944 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300945
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300946 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +0800947 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
948 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300949 if (0 != err)
950 return err;
951 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300952
Hans Verkuil314527a2013-03-15 06:10:40 -0300953 if (dev->tvnorm == tvnorms)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300954 return 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300955
Hans Verkuil314527a2013-03-15 06:10:40 -0300956 cx25821_set_tvnorm(dev, tvnorms);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300957
958 medusa_set_videostandard(dev);
959
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300960 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300961}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300962
Hans Verkuil95c232a2013-04-13 07:41:29 -0300963static int cx25821_vidioc_enum_input(struct file *file, void *priv,
964 struct v4l2_input *i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300965{
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +0800966 static const char * const iname[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300967 [CX25821_VMUX_COMPOSITE] = "Composite",
968 [CX25821_VMUX_SVIDEO] = "S-Video",
969 [CX25821_VMUX_DEBUG] = "for debug only",
970 };
Hans Verkuil95c232a2013-04-13 07:41:29 -0300971 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300972 unsigned int n;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300973
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300974 n = i->index;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300975 if (n >= CX25821_NR_INPUT)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300976 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300977
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300978 if (0 == INPUT(n)->type)
979 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300980
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300981 i->type = V4L2_INPUT_TYPE_CAMERA;
982 strcpy(i->name, iname[INPUT(n)->type]);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300983
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300984 i->std = CX25821_NORMS;
985 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300986}
987
Hans Verkuil95c232a2013-04-13 07:41:29 -0300988static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300989{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300990 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300991
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300992 *i = dev->input;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300993 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300994}
995
Hans Verkuil95c232a2013-04-13 07:41:29 -0300996static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300997{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300998 struct cx25821_fh *fh = priv;
999 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1000 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001001
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001002 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001003 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
1004 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001005 if (0 != err)
1006 return err;
1007 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001008
Hans Verkuil6b1dce22013-04-13 07:39:19 -03001009 if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001010 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001011
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001012 cx25821_video_mux(dev, i);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001013 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001014}
1015
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001016#ifdef CONFIG_VIDEO_ADV_DEBUG
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001017int cx25821_vidioc_g_register(struct file *file, void *fh,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001018 struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001019{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001020 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001021
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001022 if (!v4l2_chip_match_host(&reg->match))
1023 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001024
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001025 cx25821_call_all(dev, core, g_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001026
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001027 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001028}
1029
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001030int cx25821_vidioc_s_register(struct file *file, void *fh,
Hans Verkuil977ba3b2013-03-24 08:28:46 -03001031 const struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001032{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001033 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001034
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001035 if (!v4l2_chip_match_host(&reg->match))
1036 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001037
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001038 cx25821_call_all(dev, core, s_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001039
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001040 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001041}
1042
1043#endif
1044
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001045static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001046{
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001047 struct cx25821_channel *chan =
1048 container_of(ctrl->handler, struct cx25821_channel, hdl);
1049 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001050
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001051 switch (ctrl->id) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001052 case V4L2_CID_BRIGHTNESS:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001053 medusa_set_brightness(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001054 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001055 case V4L2_CID_HUE:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001056 medusa_set_hue(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001057 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001058 case V4L2_CID_CONTRAST:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001059 medusa_set_contrast(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001060 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001061 case V4L2_CID_SATURATION:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001062 medusa_set_saturation(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001063 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001064 default:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001065 return -EINVAL;
Joe Perches95cd17c2011-04-10 14:31:35 -07001066 }
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001067 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001068}
1069
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001070static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001071 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001072{
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001073 struct cx25821_fh *fh = file->private_data;
1074 struct cx25821_dev *dev = fh->dev;
1075 int command = 0;
1076 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001077
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001078 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001079
Joe Perches36d89f72010-11-07 17:48:21 -03001080 if (!data_from_user) {
1081 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1082 return 0;
1083 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001084
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001085 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001086
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001087 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1088 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001089
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001090 dev->input_filename = data_from_user->input_filename;
1091 dev->input_audiofilename = data_from_user->input_filename;
1092 dev->vid_stdname = data_from_user->vid_stdname;
1093 dev->pixel_format = data_from_user->pixel_format;
1094 dev->channel_select = data_from_user->channel_select;
1095 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001096
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001097 switch (command) {
1098 case UPSTREAM_START_VIDEO:
1099 cx25821_start_upstream_video_ch1(dev, data_from_user);
1100 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001101
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001102 case UPSTREAM_STOP_VIDEO:
1103 cx25821_stop_upstream_video_ch1(dev);
1104 break;
1105 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001106
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001107 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001108}
1109
1110static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001111 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001112{
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001113 struct cx25821_fh *fh = file->private_data;
1114 struct cx25821_dev *dev = fh->dev;
1115 int command = 0;
1116 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001117
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001118 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001119
Joe Perches36d89f72010-11-07 17:48:21 -03001120 if (!data_from_user) {
1121 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1122 return 0;
1123 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001124
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001125 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001126
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001127 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1128 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001129
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001130 dev->input_filename_ch2 = data_from_user->input_filename;
1131 dev->input_audiofilename = data_from_user->input_filename;
1132 dev->vid_stdname_ch2 = data_from_user->vid_stdname;
1133 dev->pixel_format_ch2 = data_from_user->pixel_format;
1134 dev->channel_select_ch2 = data_from_user->channel_select;
1135 dev->command_ch2 = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001136
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001137 switch (command) {
1138 case UPSTREAM_START_VIDEO:
1139 cx25821_start_upstream_video_ch2(dev, data_from_user);
1140 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001141
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001142 case UPSTREAM_STOP_VIDEO:
1143 cx25821_stop_upstream_video_ch2(dev);
1144 break;
1145 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001146
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001147 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001148}
1149
1150static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001151 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001152{
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001153 struct cx25821_fh *fh = file->private_data;
1154 struct cx25821_dev *dev = fh->dev;
1155 int command = 0;
1156 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001157
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001158 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001159
Joe Perches36d89f72010-11-07 17:48:21 -03001160 if (!data_from_user) {
1161 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1162 return 0;
1163 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001164
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001165 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001166
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001167 if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO)
1168 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001169
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001170 dev->input_filename = data_from_user->input_filename;
1171 dev->input_audiofilename = data_from_user->input_filename;
1172 dev->vid_stdname = data_from_user->vid_stdname;
1173 dev->pixel_format = data_from_user->pixel_format;
1174 dev->channel_select = data_from_user->channel_select;
1175 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001176
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001177 switch (command) {
1178 case UPSTREAM_START_AUDIO:
1179 cx25821_start_upstream_audio(dev, data_from_user);
1180 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001181
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001182 case UPSTREAM_STOP_AUDIO:
1183 cx25821_stop_upstream_audio(dev);
1184 break;
1185 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001186
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001187 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001188}
1189
1190static long video_ioctl_set(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001191 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001192{
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001193 struct cx25821_fh *fh = file->private_data;
1194 struct cx25821_dev *dev = fh->dev;
1195 struct downstream_user_struct *data_from_user;
1196 int command;
1197 int width = 720;
Leonid V. Fedorenchik4a33b6f2011-10-22 01:43:52 -03001198 int selected_channel = 0;
1199 int pix_format = 0;
1200 int i = 0;
1201 int cif_enable = 0;
1202 int cif_width = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001203
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001204 data_from_user = (struct downstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001205
Joe Perches36d89f72010-11-07 17:48:21 -03001206 if (!data_from_user) {
1207 pr_err("%s(): User data is INVALID. Returning\n", __func__);
1208 return 0;
1209 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001210
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001211 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001212
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001213 if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001214 && command != ENABLE_CIF_RESOLUTION && command != REG_READ
1215 && command != REG_WRITE && command != MEDUSA_READ
1216 && command != MEDUSA_WRITE) {
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001217 return 0;
1218 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001219
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001220 switch (command) {
1221 case SET_VIDEO_STD:
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001222 if (!strcmp(data_from_user->vid_stdname, "PAL"))
1223 dev->tvnorm = V4L2_STD_PAL_BG;
1224 else
1225 dev->tvnorm = V4L2_STD_NTSC_M;
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001226 medusa_set_videostandard(dev);
1227 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001228
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001229 case SET_PIXEL_FORMAT:
1230 selected_channel = data_from_user->decoder_select;
1231 pix_format = data_from_user->pixel_format;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001232
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001233 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1234 selected_channel -= 4;
1235 selected_channel = selected_channel % 8;
1236 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001237
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001238 if (selected_channel >= 0)
1239 cx25821_set_pixel_format(dev, selected_channel,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001240 pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001241
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001242 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001243
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001244 case ENABLE_CIF_RESOLUTION:
1245 selected_channel = data_from_user->decoder_select;
1246 cif_enable = data_from_user->cif_resolution_enable;
1247 cif_width = data_from_user->cif_width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001248
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001249 if (cif_enable) {
1250 if (dev->tvnorm & V4L2_STD_PAL_BG
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001251 || dev->tvnorm & V4L2_STD_PAL_DK) {
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001252 width = 352;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001253 } else {
1254 width = cif_width;
1255 if (cif_width != 320 && cif_width != 352)
1256 width = 320;
1257 }
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001258 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001259
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001260 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1261 selected_channel -= 4;
1262 selected_channel = selected_channel % 8;
1263 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001264
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001265 if (selected_channel <= 7 && selected_channel >= 0) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -03001266 dev->channels[selected_channel].use_cif_resolution =
1267 cif_enable;
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001268 dev->channels[selected_channel].cif_width = width;
1269 } else {
1270 for (i = 0; i < VID_CHANNEL_NUM; i++) {
1271 dev->channels[i].use_cif_resolution =
1272 cif_enable;
1273 dev->channels[i].cif_width = width;
1274 }
1275 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001276
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001277 medusa_set_resolution(dev, width, selected_channel);
1278 break;
1279 case REG_READ:
1280 data_from_user->reg_data = cx_read(data_from_user->reg_address);
1281 break;
1282 case REG_WRITE:
1283 cx_write(data_from_user->reg_address, data_from_user->reg_data);
1284 break;
1285 case MEDUSA_READ:
Hans Verkuil30fdf032012-04-20 06:26:19 -03001286 cx25821_i2c_read(&dev->i2c_bus[0],
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001287 (u16) data_from_user->reg_address,
1288 &data_from_user->reg_data);
1289 break;
1290 case MEDUSA_WRITE:
1291 cx25821_i2c_write(&dev->i2c_bus[0],
1292 (u16) data_from_user->reg_address,
1293 data_from_user->reg_data);
1294 break;
1295 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001296
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001297 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001298}
1299
1300static long cx25821_video_ioctl(struct file *file,
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001301 unsigned int cmd, unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001302{
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001303 int ret = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001304
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001305 struct cx25821_fh *fh = file->private_data;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001306
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001307 /* check to see if it's the video upstream */
1308 if (fh->channel_id == SRAM_CH09) {
1309 ret = video_ioctl_upstream9(file, cmd, arg);
1310 return ret;
1311 } else if (fh->channel_id == SRAM_CH10) {
1312 ret = video_ioctl_upstream10(file, cmd, arg);
1313 return ret;
1314 } else if (fh->channel_id == SRAM_CH11) {
1315 ret = video_ioctl_upstream11(file, cmd, arg);
1316 ret = video_ioctl_set(file, cmd, arg);
1317 return ret;
1318 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001319
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001320 return video_ioctl2(file, cmd, arg);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001321}
1322
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001323static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
1324 .s_ctrl = cx25821_s_ctrl,
1325};
1326
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001327static const struct v4l2_file_operations video_fops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001328 .owner = THIS_MODULE,
1329 .open = video_open,
1330 .release = video_release,
1331 .read = video_read,
1332 .poll = video_poll,
1333 .mmap = cx25821_video_mmap,
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001334 .unlocked_ioctl = cx25821_video_ioctl,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001335};
1336
1337static const struct v4l2_ioctl_ops video_ioctl_ops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001338 .vidioc_querycap = cx25821_vidioc_querycap,
1339 .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
1340 .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
1341 .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
1342 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1343 .vidioc_reqbufs = cx25821_vidioc_reqbufs,
1344 .vidioc_querybuf = cx25821_vidioc_querybuf,
1345 .vidioc_qbuf = cx25821_vidioc_qbuf,
1346 .vidioc_dqbuf = vidioc_dqbuf,
Hans Verkuil18c73af2013-04-13 05:50:18 -03001347 .vidioc_g_std = cx25821_vidioc_g_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001348 .vidioc_s_std = cx25821_vidioc_s_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001349 .vidioc_enum_input = cx25821_vidioc_enum_input,
1350 .vidioc_g_input = cx25821_vidioc_g_input,
1351 .vidioc_s_input = cx25821_vidioc_s_input,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001352 .vidioc_streamon = vidioc_streamon,
1353 .vidioc_streamoff = vidioc_streamoff,
1354 .vidioc_log_status = vidioc_log_status,
1355 .vidioc_g_priority = cx25821_vidioc_g_priority,
1356 .vidioc_s_priority = cx25821_vidioc_s_priority,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001357#ifdef CONFIG_VIDEO_ADV_DEBUG
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001358 .vidioc_g_register = cx25821_vidioc_g_register,
1359 .vidioc_s_register = cx25821_vidioc_s_register,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001360#endif
1361};
1362
Hans Verkuilffd3c232013-04-13 05:30:48 -03001363static const struct video_device cx25821_video_device = {
1364 .name = "cx25821-video",
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001365 .fops = &video_fops,
Hans Verkuil467870c2013-04-13 08:18:00 -03001366 .release = video_device_release_empty,
Hans Verkuilffd3c232013-04-13 05:30:48 -03001367 .minor = -1,
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001368 .ioctl_ops = &video_ioctl_ops,
1369 .tvnorms = CX25821_NORMS,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001370};
Hans Verkuilffd3c232013-04-13 05:30:48 -03001371
1372void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
1373{
1374 cx_clear(PCI_INT_MSK, 1);
1375
Hans Verkuil467870c2013-04-13 08:18:00 -03001376 if (video_is_registered(&dev->channels[chan_num].vdev)) {
1377 video_unregister_device(&dev->channels[chan_num].vdev);
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001378 v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001379
1380 btcx_riscmem_free(dev->pci,
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001381 &dev->channels[chan_num].dma_vidq.stopper);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001382 }
Hans Verkuilffd3c232013-04-13 05:30:48 -03001383}
1384
1385int cx25821_video_register(struct cx25821_dev *dev)
1386{
1387 int err;
1388 int i;
1389
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001390 /* initial device configuration */
1391 dev->tvnorm = V4L2_STD_NTSC_M,
1392 cx25821_set_tvnorm(dev, dev->tvnorm);
1393
Hans Verkuilffd3c232013-04-13 05:30:48 -03001394 spin_lock_init(&dev->slock);
1395
1396 for (i = 0; i < VID_CHANNEL_NUM; ++i) {
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001397 struct cx25821_channel *chan = &dev->channels[i];
1398 struct video_device *vdev = &chan->vdev;
1399 struct v4l2_ctrl_handler *hdl = &chan->hdl;
Hans Verkuil467870c2013-04-13 08:18:00 -03001400
Hans Verkuilffd3c232013-04-13 05:30:48 -03001401 if (i == SRAM_CH08) /* audio channel */
1402 continue;
1403
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001404 v4l2_ctrl_handler_init(hdl, 4);
1405 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1406 V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
1407 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1408 V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
1409 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1410 V4L2_CID_SATURATION, 0, 10000, 1, 5000);
1411 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1412 V4L2_CID_HUE, 0, 10000, 1, 5000);
1413 if (hdl->error) {
1414 err = hdl->error;
1415 goto fail_unreg;
1416 }
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001417 err = v4l2_ctrl_handler_setup(hdl);
1418 if (err)
1419 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001420
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001421 cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper,
1422 chan->sram_channels->dma_ctl, 0x11, 0);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001423
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001424 chan->sram_channels = &cx25821_sram_channels[i];
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001425 chan->width = 720;
1426 if (dev->tvnorm & V4L2_STD_625_50)
1427 chan->height = 576;
1428 else
1429 chan->height = 480;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001430
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001431 if (chan->pixel_formats == PIXEL_FRMT_411)
1432 chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_Y41P);
1433 else
1434 chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_YUYV);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001435
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001436 cx_write(chan->sram_channels->int_stat, 0xffffffff);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001437
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001438 INIT_LIST_HEAD(&chan->dma_vidq.active);
1439 INIT_LIST_HEAD(&chan->dma_vidq.queued);
1440
1441 chan->timeout_data.dev = dev;
1442 chan->timeout_data.channel = &cx25821_sram_channels[i];
1443 chan->dma_vidq.timeout.function = cx25821_vid_timeout;
1444 chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data;
1445 init_timer(&chan->dma_vidq.timeout);
1446
1447 videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev,
1448 &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
1449 V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
1450 chan, &dev->lock);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001451
1452 /* register v4l devices */
Hans Verkuil467870c2013-04-13 08:18:00 -03001453 *vdev = cx25821_video_device;
1454 vdev->v4l2_dev = &dev->v4l2_dev;
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001455 vdev->ctrl_handler = hdl;
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001456 vdev->lock = &dev->lock;
Hans Verkuil467870c2013-04-13 08:18:00 -03001457 snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001458 video_set_drvdata(vdev, chan);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001459
Hans Verkuil467870c2013-04-13 08:18:00 -03001460 err = video_register_device(vdev, VFL_TYPE_GRABBER,
1461 video_nr[dev->nr]);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001462
1463 if (err < 0)
1464 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001465 }
1466
1467 /* set PCI interrupt */
1468 cx_set(PCI_INT_MSK, 0xff);
1469
Hans Verkuilffd3c232013-04-13 05:30:48 -03001470 return 0;
1471
1472fail_unreg:
Hans Verkuil467870c2013-04-13 08:18:00 -03001473 while (i >= 0)
1474 cx25821_video_unregister(dev, i--);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001475 return err;
1476}