blob: d88316c5f5de3f3d2ac6a9e5383c233a967518bd [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
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300147/* resource management */
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300148static int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800149 unsigned int bit)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300150{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300151 dprintk(1, "%s()\n", __func__);
152 if (fh->resources & bit)
153 /* have it already allocated */
154 return 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300155
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300156 /* is it free? */
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800157 if (dev->channels[fh->channel_id].resources & bit) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300158 /* no, someone else uses it */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300159 return 0;
160 }
161 /* it's free, grab it */
162 fh->resources |= bit;
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800163 dev->channels[fh->channel_id].resources |= bit;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300164 dprintk(1, "res: get %d\n", bit);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300165 return 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300166}
167
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300168static int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300169{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300170 return fh->resources & bit;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300171}
172
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300173static int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300174{
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800175 return fh->dev->channels[fh->channel_id].resources & bit;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300176}
177
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300178static void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800179 unsigned int bits)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300180{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300181 BUG_ON((fh->resources & bits) != bits);
182 dprintk(1, "%s()\n", __func__);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300183
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300184 fh->resources &= ~bits;
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800185 dev->channels[fh->channel_id].resources &= ~bits;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300186 dprintk(1, "res: put %d\n", bits);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300187}
188
Hans Verkuil95c232a2013-04-13 07:41:29 -0300189static int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300190{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300191 struct v4l2_routing route;
192 memset(&route, 0, sizeof(route));
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300193
Joe Perches36d89f72010-11-07 17:48:21 -0300194 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 -0300195 __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0,
196 INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3);
197 dev->input = input;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300198
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300199 route.input = INPUT(input)->vmux;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300200
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300201 /* Tell the internal A/V decoder */
202 cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300203
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300204 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300205}
206
207int cx25821_start_video_dma(struct cx25821_dev *dev,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300208 struct cx25821_dmaqueue *q,
209 struct cx25821_buffer *buf,
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300210 const struct sram_channel *channel)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300211{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300212 int tmp = 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300213
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300214 /* setup fifo + format */
215 cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300216
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300217 /* reset counter */
218 cx_write(channel->gpcnt_ctl, 3);
219 q->count = 1;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300220
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300221 /* enable irq */
222 cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i));
223 cx_set(channel->int_msk, 0x11);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300224
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300225 /* start dma */
226 cx_write(channel->dma_ctl, 0x11); /* FIFO and RISC enable */
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300227
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300228 /* make sure upstream setting if any is reversed */
229 tmp = cx_read(VID_CH_MODE_SEL);
230 cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300231
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300232 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300233}
234
Mauro Carvalho Chehabdafc4562012-10-27 12:42:59 -0300235static int cx25821_restart_video_queue(struct cx25821_dev *dev,
236 struct cx25821_dmaqueue *q,
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300237 const struct sram_channel *channel)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300238{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300239 struct cx25821_buffer *buf, *prev;
240 struct list_head *item;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300241
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300242 if (!list_empty(&q->active)) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300243 buf = list_entry(q->active.next, struct cx25821_buffer,
244 vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300245
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300246 cx25821_start_video_dma(dev, q, buf, channel);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300247
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300248 list_for_each(item, &q->active) {
249 buf = list_entry(item, struct cx25821_buffer, vb.queue);
250 buf->count = q->count++;
251 }
252
253 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
254 return 0;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300255 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300256
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300257 prev = NULL;
258 for (;;) {
259 if (list_empty(&q->queued))
260 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300261
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300262 buf = list_entry(q->queued.next, struct cx25821_buffer,
263 vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300264
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300265 if (NULL == prev) {
266 list_move_tail(&buf->vb.queue, &q->active);
267 cx25821_start_video_dma(dev, q, buf, channel);
268 buf->vb.state = VIDEOBUF_ACTIVE;
269 buf->count = q->count++;
270 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
271 } else if (prev->vb.width == buf->vb.width &&
272 prev->vb.height == buf->vb.height &&
273 prev->fmt == buf->fmt) {
274 list_move_tail(&buf->vb.queue, &q->active);
275 buf->vb.state = VIDEOBUF_ACTIVE;
276 buf->count = q->count++;
277 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800278 prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300279 } else {
280 return 0;
281 }
282 prev = buf;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300283 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300284}
285
Mauro Carvalho Chehabdafc4562012-10-27 12:42:59 -0300286static void cx25821_vid_timeout(unsigned long data)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300287{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300288 struct cx25821_data *timeout_data = (struct cx25821_data *)data;
289 struct cx25821_dev *dev = timeout_data->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300290 const struct sram_channel *channel = timeout_data->channel;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300291 struct cx25821_dmaqueue *q = &dev->channels[channel->i].dma_vidq;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300292 struct cx25821_buffer *buf;
293 unsigned long flags;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300294
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800295 /* cx25821_sram_channel_dump(dev, channel); */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300296 cx_clear(channel->dma_ctl, 0x11);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300297
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300298 spin_lock_irqsave(&dev->slock, flags);
299 while (!list_empty(&q->active)) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300300 buf = list_entry(q->active.next, struct cx25821_buffer,
301 vb.queue);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300302 list_del(&buf->vb.queue);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300303
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300304 buf->vb.state = VIDEOBUF_ERROR;
305 wake_up(&buf->vb.done);
306 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300307
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300308 cx25821_restart_video_queue(dev, q, channel);
309 spin_unlock_irqrestore(&dev->slock, flags);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300310}
311
312int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
313{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300314 u32 count = 0;
315 int handled = 0;
316 u32 mask;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300317 const struct sram_channel *channel = dev->channels[chan_num].sram_channels;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300318
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300319 mask = cx_read(channel->int_msk);
320 if (0 == (status & mask))
321 return handled;
322
323 cx_write(channel->int_stat, status);
324
325 /* risc op code error */
326 if (status & (1 << 16)) {
Joe Perches36d89f72010-11-07 17:48:21 -0300327 pr_warn("%s, %s: video risc op code error\n",
328 dev->name, channel->name);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300329 cx_clear(channel->dma_ctl, 0x11);
330 cx25821_sram_channel_dump(dev, channel);
331 }
332
333 /* risc1 y */
334 if (status & FLD_VID_DST_RISC1) {
335 spin_lock(&dev->slock);
336 count = cx_read(channel->gpcnt);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300337 cx25821_video_wakeup(dev, &dev->channels[channel->i].dma_vidq,
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800338 count);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300339 spin_unlock(&dev->slock);
340 handled++;
341 }
342
343 /* risc2 y */
344 if (status & 0x10) {
345 dprintk(2, "stopper video\n");
346 spin_lock(&dev->slock);
Leonid V. Fedorenchik788d0f32011-09-16 14:14:39 +0800347 cx25821_restart_video_queue(dev,
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300348 &dev->channels[channel->i].dma_vidq, channel);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300349 spin_unlock(&dev->slock);
350 handled++;
351 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300352 return handled;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300353}
354
Hans Verkuil95c232a2013-04-13 07:41:29 -0300355static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300356 unsigned int *size)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300357{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300358 struct cx25821_channel *chan = q->priv_data;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300359
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300360 *size = chan->fmt->depth * chan->width * chan->height >> 3;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300361
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300362 if (0 == *count)
363 *count = 32;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300364
Andreas Bombedab7e312010-03-21 16:02:45 -0300365 if (*size * *count > vid_limit * 1024 * 1024)
366 *count = (vid_limit * 1024 * 1024) / *size;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300367
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300368 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300369}
370
Hans Verkuil95c232a2013-04-13 07:41:29 -0300371static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300372 enum v4l2_field field)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300373{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300374 struct cx25821_channel *chan = q->priv_data;
375 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300376 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300377 container_of(vb, struct cx25821_buffer, vb);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300378 int rc, init_buffer = 0;
Hans Verkuil30fdf032012-04-20 06:26:19 -0300379 u32 line0_offset;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300380 struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
381 int bpl_local = LINE_SIZE_D1;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300382 int channel_opened = chan->id;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300383
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300384 BUG_ON(NULL == chan->fmt);
385 if (chan->width < 48 || chan->width > 720 ||
386 chan->height < 32 || chan->height > 576)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300387 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300388
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300389 buf->vb.size = (chan->width * chan->height * chan->fmt->depth) >> 3;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300390
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300391 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
392 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300393
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300394 if (buf->fmt != chan->fmt ||
395 buf->vb.width != chan->width ||
396 buf->vb.height != chan->height || buf->vb.field != field) {
397 buf->fmt = chan->fmt;
398 buf->vb.width = chan->width;
399 buf->vb.height = chan->height;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300400 buf->vb.field = field;
401 init_buffer = 1;
402 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300403
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300404 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
405 init_buffer = 1;
406 rc = videobuf_iolock(q, &buf->vb, NULL);
407 if (0 != rc) {
Joe Perches36d89f72010-11-07 17:48:21 -0300408 printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n"));
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300409 goto fail;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300410 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300411 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300412
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300413 dprintk(1, "init_buffer=%d\n", init_buffer);
414
415 if (init_buffer) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300416 channel_opened = dev->channel_opened;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +0800417 if (channel_opened < 0 || channel_opened > 7)
418 channel_opened = 7;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300419
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800420 if (dev->channels[channel_opened].pixel_formats ==
421 PIXEL_FRMT_411)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300422 buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
423 else
424 buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
425
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800426 if (dev->channels[channel_opened].pixel_formats ==
427 PIXEL_FRMT_411) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300428 bpl_local = buf->bpl;
429 } else {
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800430 bpl_local = buf->bpl; /* Default */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300431
432 if (channel_opened >= 0 && channel_opened <= 7) {
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800433 if (dev->channels[channel_opened]
434 .use_cif_resolution) {
Leonid V. Fedorenchikcd52b2c2011-10-22 01:43:53 -0300435 if (dev->tvnorm & V4L2_STD_PAL_BG ||
436 dev->tvnorm & V4L2_STD_PAL_DK)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300437 bpl_local = 352 << 1;
438 else
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300439 bpl_local = dev->channels[
440 channel_opened].
441 cif_width << 1;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300442 }
443 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300444 }
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300445
446 switch (buf->vb.field) {
447 case V4L2_FIELD_TOP:
448 cx25821_risc_buffer(dev->pci, &buf->risc,
449 dma->sglist, 0, UNSET,
450 buf->bpl, 0, buf->vb.height);
451 break;
452 case V4L2_FIELD_BOTTOM:
453 cx25821_risc_buffer(dev->pci, &buf->risc,
454 dma->sglist, UNSET, 0,
455 buf->bpl, 0, buf->vb.height);
456 break;
457 case V4L2_FIELD_INTERLACED:
458 /* All other formats are top field first */
459 line0_offset = 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300460 dprintk(1, "top field first\n");
461
462 cx25821_risc_buffer(dev->pci, &buf->risc,
463 dma->sglist, line0_offset,
464 bpl_local, bpl_local, bpl_local,
465 buf->vb.height >> 1);
466 break;
467 case V4L2_FIELD_SEQ_TB:
468 cx25821_risc_buffer(dev->pci, &buf->risc,
469 dma->sglist,
470 0, buf->bpl * (buf->vb.height >> 1),
471 buf->bpl, 0, buf->vb.height >> 1);
472 break;
473 case V4L2_FIELD_SEQ_BT:
474 cx25821_risc_buffer(dev->pci, &buf->risc,
475 dma->sglist,
476 buf->bpl * (buf->vb.height >> 1), 0,
477 buf->bpl, 0, buf->vb.height >> 1);
478 break;
479 default:
480 BUG();
481 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300482 }
483
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300484 dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300485 buf, buf->vb.i, chan->width, chan->height, chan->fmt->depth,
486 chan->fmt->name, (unsigned long)buf->risc.dma);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300487
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300488 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300489
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300490 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300491
Leonid V. Fedorenchik2748f262011-09-16 14:14:34 +0800492fail:
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300493 cx25821_free_buffer(q, buf);
494 return rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300495}
496
Hans Verkuil95c232a2013-04-13 07:41:29 -0300497static void cx25821_buffer_release(struct videobuf_queue *q,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800498 struct videobuf_buffer *vb)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300499{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300500 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300501 container_of(vb, struct cx25821_buffer, vb);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300502
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300503 cx25821_free_buffer(q, buf);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300504}
505
Hans Verkuil95c232a2013-04-13 07:41:29 -0300506static int cx25821_get_resource(struct cx25821_fh *fh, int resource)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300507{
Hans Verkuil11f095a2013-04-14 11:54:56 -0300508 return resource;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300509}
510
Hans Verkuil95c232a2013-04-13 07:41:29 -0300511static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300512{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300513 struct cx25821_channel *chan = video_drvdata(file);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300514
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300515 return videobuf_mmap_mapper(&chan->vidq, vma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300516}
517
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300518
519static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
520{
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800521 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300522 container_of(vb, struct cx25821_buffer, vb);
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800523 struct cx25821_buffer *prev;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300524 struct cx25821_channel *chan = vq->priv_data;
525 struct cx25821_dev *dev = chan->dev;
526 struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300527
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800528 /* add jump to stopper */
529 buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
530 buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
531 buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300532
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800533 dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300534
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800535 if (!list_empty(&q->queued)) {
536 list_add_tail(&buf->vb.queue, &q->queued);
537 buf->vb.state = VIDEOBUF_QUEUED;
538 dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
539 buf->vb.i);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300540
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800541 } else if (list_empty(&q->active)) {
542 list_add_tail(&buf->vb.queue, &q->active);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300543 cx25821_start_video_dma(dev, q, buf, chan->sram_channels);
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800544 buf->vb.state = VIDEOBUF_ACTIVE;
545 buf->count = q->count++;
546 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
547 dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
548 buf, buf->vb.i, buf->count, q->count);
549 } else {
550 prev = list_entry(q->active.prev, struct cx25821_buffer,
551 vb.queue);
552 if (prev->vb.width == buf->vb.width
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300553 && prev->vb.height == buf->vb.height
554 && prev->fmt == buf->fmt) {
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800555 list_add_tail(&buf->vb.queue, &q->active);
556 buf->vb.state = VIDEOBUF_ACTIVE;
557 buf->count = q->count++;
558 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300559
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800560 /* 64 bit bits 63-32 */
561 prev->risc.jmp[2] = cpu_to_le32(0);
562 dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
563 buf, buf->vb.i, buf->count);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300564
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800565 } else {
566 list_add_tail(&buf->vb.queue, &q->queued);
567 buf->vb.state = VIDEOBUF_QUEUED;
568 dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
569 buf->vb.i);
570 }
571 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300572
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800573 if (list_empty(&q->active))
574 dprintk(2, "active queue empty!\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300575}
576
577static struct videobuf_queue_ops cx25821_video_qops = {
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800578 .buf_setup = cx25821_buffer_setup,
579 .buf_prepare = cx25821_buffer_prepare,
580 .buf_queue = buffer_queue,
581 .buf_release = cx25821_buffer_release,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300582};
583
584static int video_open(struct file *file)
585{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300586 struct cx25821_channel *chan = video_drvdata(file);
587 struct cx25821_dev *dev = chan->dev;
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800588 struct cx25821_fh *fh;
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300589
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800590 /* allocate + initialize per filehandle data */
591 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
592 if (NULL == fh)
593 return -ENOMEM;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300594
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800595 file->private_data = fh;
596 fh->dev = dev;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300597 fh->channel_id = chan->id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300598
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800599 dev->channel_opened = fh->channel_id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300600
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300601 v4l2_prio_open(&chan->prio, &fh->prio);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300602
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800603 dprintk(1, "post videobuf_queue_init()\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300604
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800605 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300606}
607
608static ssize_t video_read(struct file *file, char __user * data, size_t count,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300609 loff_t *ppos)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300610{
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800611 struct cx25821_fh *fh = file->private_data;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300612 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300613 struct cx25821_dev *dev = fh->dev;
614 int err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300615
Hans Verkuil11f095a2013-04-14 11:54:56 -0300616 if (mutex_lock_interruptible(&dev->lock))
617 return -ERESTARTSYS;
618 if (cx25821_res_locked(fh, RESOURCE_VIDEO0))
619 err = -EBUSY;
620 else
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300621 err = videobuf_read_one(&chan->vidq, data, count, ppos,
Hans Verkuil11f095a2013-04-14 11:54:56 -0300622 file->f_flags & O_NONBLOCK);
623 mutex_unlock(&dev->lock);
624 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300625}
626
627static unsigned int video_poll(struct file *file,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300628 struct poll_table_struct *wait)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300629{
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800630 struct cx25821_fh *fh = file->private_data;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300631 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800632 struct cx25821_buffer *buf;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300633
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800634 if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
635 /* streaming capture */
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300636 if (list_empty(&chan->vidq.stream))
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800637 return POLLERR;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300638 buf = list_entry(chan->vidq.stream.next,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300639 struct cx25821_buffer, vb.stream);
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800640 } else {
641 /* read() capture */
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300642 buf = (struct cx25821_buffer *)chan->vidq.read_buf;
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800643 if (NULL == buf)
644 return POLLERR;
645 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300646
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800647 poll_wait(file, &buf->vb.done, wait);
648 if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
649 if (buf->vb.state == VIDEOBUF_DONE) {
650 struct cx25821_dev *dev = fh->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300651
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300652 if (dev && chan->use_cif_resolution) {
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800653 u8 cam_id = *((char *)buf->vb.baddr + 3);
654 memcpy((char *)buf->vb.baddr,
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300655 (char *)buf->vb.baddr + (chan->width * 2),
656 (chan->width * 2));
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800657 *((char *)buf->vb.baddr + 3) = cam_id;
658 }
659 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300660
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800661 return POLLIN | POLLRDNORM;
662 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300663
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800664 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300665}
666
667static int video_release(struct file *file)
668{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300669 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800670 struct cx25821_fh *fh = file->private_data;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300671 struct cx25821_dev *dev = chan->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300672 const struct sram_channel *sram_ch =
673 dev->channels[0].sram_channels;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300674
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300675 mutex_lock(&dev->lock);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800676 /* stop the risc engine and fifo */
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300677 cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300678
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800679 /* stop video capture */
680 if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300681 videobuf_queue_cancel(&chan->vidq);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800682 cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
683 }
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300684 mutex_unlock(&dev->lock);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300685
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300686 if (chan->vidq.read_buf) {
687 cx25821_buffer_release(&chan->vidq, chan->vidq.read_buf);
688 kfree(chan->vidq.read_buf);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800689 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300690
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300691 videobuf_mmap_free(&chan->vidq);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300692
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300693 v4l2_prio_close(&chan->prio, fh->prio);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800694 file->private_data = NULL;
695 kfree(fh);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300696
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800697 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300698}
699
Hans Verkuil95c232a2013-04-13 07:41:29 -0300700/* VIDEO IOCTLS */
701static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
702 struct v4l2_format *f)
703{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300704 struct cx25821_channel *chan = video_drvdata(file);
Hans Verkuil95c232a2013-04-13 07:41:29 -0300705
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300706 f->fmt.pix.width = chan->width;
707 f->fmt.pix.height = chan->height;
708 f->fmt.pix.field = chan->vidq.field;
709 f->fmt.pix.pixelformat = chan->fmt->fourcc;
710 f->fmt.pix.bytesperline = (f->fmt.pix.width * chan->fmt->depth) >> 3;
Hans Verkuil95c232a2013-04-13 07:41:29 -0300711 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
712
713 return 0;
714}
715
716static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
717 struct v4l2_format *f)
718{
719 const struct cx25821_fmt *fmt;
720 enum v4l2_field field;
721 unsigned int maxw, maxh;
722
723 fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
724 if (NULL == fmt)
725 return -EINVAL;
726
727 field = f->fmt.pix.field;
728 maxw = 720;
729 maxh = 576;
730
731 if (V4L2_FIELD_ANY == field) {
732 if (f->fmt.pix.height > maxh / 2)
733 field = V4L2_FIELD_INTERLACED;
734 else
735 field = V4L2_FIELD_TOP;
736 }
737
738 switch (field) {
739 case V4L2_FIELD_TOP:
740 case V4L2_FIELD_BOTTOM:
741 maxh = maxh / 2;
742 break;
743 case V4L2_FIELD_INTERLACED:
744 break;
745 default:
746 return -EINVAL;
747 }
748
749 f->fmt.pix.field = field;
750 if (f->fmt.pix.height < 32)
751 f->fmt.pix.height = 32;
752 if (f->fmt.pix.height > maxh)
753 f->fmt.pix.height = maxh;
754 if (f->fmt.pix.width < 48)
755 f->fmt.pix.width = 48;
756 if (f->fmt.pix.width > maxw)
757 f->fmt.pix.width = maxw;
758 f->fmt.pix.width &= ~0x03;
759 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
760 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
761
762 return 0;
763}
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300764static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
765{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300766 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800767 struct cx25821_fh *fh = priv;
768 struct cx25821_dev *dev = fh->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300769
Hans Verkuil11f095a2013-04-14 11:54:56 -0300770 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800771 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300772
Hans Verkuil11f095a2013-04-14 11:54:56 -0300773 if (!cx25821_res_get(dev, fh,
774 cx25821_get_resource(fh, RESOURCE_VIDEO0)))
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800775 return -EBUSY;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300776
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300777 return videobuf_streamon(&chan->vidq);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300778}
779
780static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
781{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300782 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800783 struct cx25821_fh *fh = priv;
784 struct cx25821_dev *dev = fh->dev;
785 int err, res;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300786
Hans Verkuil11f095a2013-04-14 11:54:56 -0300787 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800788 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300789
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800790 res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300791 err = videobuf_streamoff(&chan->vidq);
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800792 if (err < 0)
793 return err;
794 cx25821_res_free(dev, fh, res);
795 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300796}
797
Hans Verkuil95c232a2013-04-13 07:41:29 -0300798static int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm)
799{
800 if (tvnorm == V4L2_STD_PAL_BG) {
801 if (width == 352 || width == 720)
802 return 1;
803 else
804 return 0;
805 }
806
807 if (tvnorm == V4L2_STD_NTSC_M) {
808 if (width == 320 || width == 352 || width == 720)
809 return 1;
810 else
811 return 0;
812 }
813 return 0;
814}
815
816static int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
817{
818 if (tvnorm == V4L2_STD_PAL_BG) {
819 if (height == 576 || height == 288)
820 return 1;
821 else
822 return 0;
823 }
824
825 if (tvnorm == V4L2_STD_NTSC_M) {
826 if (height == 480 || height == 240)
827 return 1;
828 else
829 return 0;
830 }
831
832 return 0;
833}
834
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300835static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800836 struct v4l2_format *f)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300837{
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800838 struct cx25821_fh *fh = priv;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300839 struct cx25821_channel *chan = video_drvdata(file);
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800840 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300841 struct v4l2_mbus_framefmt mbus_fmt;
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800842 int err;
843 int pix_format = PIXEL_FRMT_422;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300844
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800845 if (fh) {
846 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
847 fh->prio);
848 if (0 != err)
849 return err;
850 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300851
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800852 err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300853
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800854 if (0 != err)
855 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300856
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300857 chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
858 chan->vidq.field = f->fmt.pix.field;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300859
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800860 /* check if width and height is valid based on set standard */
861 if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300862 chan->width = f->fmt.pix.width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300863
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800864 if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300865 chan->height = f->fmt.pix.height;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300866
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800867 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
868 pix_format = PIXEL_FRMT_411;
869 else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
870 pix_format = PIXEL_FRMT_422;
871 else
872 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300873
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800874 cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300875
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800876 /* check if cif resolution */
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300877 if (chan->width == 320 || chan->width == 352)
878 chan->use_cif_resolution = 1;
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800879 else
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300880 chan->use_cif_resolution = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300881
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300882 chan->cif_width = chan->width;
883 medusa_set_resolution(dev, chan->width, SRAM_CH00);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300884
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300885 v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
886 cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300887
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800888 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300889}
890
891static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
892{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800893 int ret_val = 0;
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300894 struct cx25821_channel *chan = video_drvdata(file);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300895
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300896 ret_val = videobuf_dqbuf(&chan->vidq, p, file->f_flags & O_NONBLOCK);
897 p->sequence = chan->dma_vidq.count;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300898
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800899 return ret_val;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300900}
901
902static int vidioc_log_status(struct file *file, void *priv)
903{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800904 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
905 struct cx25821_fh *fh = priv;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300906 const struct sram_channel *sram_ch =
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300907 dev->channels[fh->channel_id].sram_channels;
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800908 u32 tmp = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300909
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800910 cx25821_call_all(dev, core, log_status);
911 tmp = cx_read(sram_ch->dma_ctl);
Joe Perches36d89f72010-11-07 17:48:21 -0300912 pr_info("Video input 0 is %s\n",
913 (tmp & 0x11) ? "streaming" : "stopped");
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800914 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300915}
916
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300917
Hans Verkuil95c232a2013-04-13 07:41:29 -0300918static int cx25821_vidioc_querycap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800919 struct v4l2_capability *cap)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300920{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300921 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300922 struct cx25821_fh *fh = priv;
923 const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE |
924 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
925 const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300926
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300927 strcpy(cap->driver, "cx25821");
928 strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
929 sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300930 if (fh->channel_id >= VID_CHANNEL_NUM)
931 cap->device_caps = cap_output;
932 else
933 cap->device_caps = cap_input;
934 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300935 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300936}
937
Hans Verkuil95c232a2013-04-13 07:41:29 -0300938static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300939 struct v4l2_fmtdesc *f)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300940{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300941 if (unlikely(f->index >= ARRAY_SIZE(formats)))
942 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300943
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300944 strlcpy(f->description, formats[f->index].name, sizeof(f->description));
945 f->pixelformat = formats[f->index].fourcc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300946
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300947 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300948}
949
Hans Verkuil95c232a2013-04-13 07:41:29 -0300950static int cx25821_vidioc_reqbufs(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800951 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300952{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300953 struct cx25821_channel *chan = video_drvdata(file);
954
955 return videobuf_reqbufs(&chan->vidq, p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300956}
957
Hans Verkuil95c232a2013-04-13 07:41:29 -0300958static int cx25821_vidioc_querybuf(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800959 struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300960{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300961 struct cx25821_channel *chan = video_drvdata(file);
962
963 return videobuf_querybuf(&chan->vidq, p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300964}
965
Hans Verkuil95c232a2013-04-13 07:41:29 -0300966static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300967{
Hans Verkuil2efe2cc2013-04-13 10:00:52 -0300968 struct cx25821_channel *chan = video_drvdata(file);
969
970 return videobuf_qbuf(&chan->vidq, p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300971}
972
Hans Verkuil95c232a2013-04-13 07:41:29 -0300973static int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300974{
975 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +0800976 struct cx25821_fh *fh = f;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300977
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +0800978 *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300979
980 return 0;
981}
982
Hans Verkuil95c232a2013-04-13 07:41:29 -0300983static int cx25821_vidioc_s_priority(struct file *file, void *f,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800984 enum v4l2_priority prio)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300985{
986 struct cx25821_fh *fh = f;
987 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
988
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +0800989 return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio,
990 prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300991}
992
Hans Verkuil95c232a2013-04-13 07:41:29 -0300993static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
Hans Verkuil18c73af2013-04-13 05:50:18 -0300994{
995 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
996
997 *tvnorms = dev->tvnorm;
998 return 0;
999}
1000
Hans Verkuil314527a2013-03-15 06:10:40 -03001001int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001002{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001003 struct cx25821_fh *fh = priv;
1004 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1005 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001006
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001007 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001008 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
1009 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001010 if (0 != err)
1011 return err;
1012 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001013
Hans Verkuil314527a2013-03-15 06:10:40 -03001014 if (dev->tvnorm == tvnorms)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001015 return 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001016
Hans Verkuil314527a2013-03-15 06:10:40 -03001017 cx25821_set_tvnorm(dev, tvnorms);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001018
1019 medusa_set_videostandard(dev);
1020
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001021 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001022}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001023
Hans Verkuil95c232a2013-04-13 07:41:29 -03001024static int cx25821_vidioc_enum_input(struct file *file, void *priv,
1025 struct v4l2_input *i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001026{
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001027 static const char * const iname[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001028 [CX25821_VMUX_COMPOSITE] = "Composite",
1029 [CX25821_VMUX_SVIDEO] = "S-Video",
1030 [CX25821_VMUX_DEBUG] = "for debug only",
1031 };
Hans Verkuil95c232a2013-04-13 07:41:29 -03001032 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001033 unsigned int n;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001034
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001035 n = i->index;
Hans Verkuil95c232a2013-04-13 07:41:29 -03001036 if (n >= CX25821_NR_INPUT)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001037 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001038
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001039 if (0 == INPUT(n)->type)
1040 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001041
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001042 i->type = V4L2_INPUT_TYPE_CAMERA;
1043 strcpy(i->name, iname[INPUT(n)->type]);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001044
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001045 i->std = CX25821_NORMS;
1046 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001047}
1048
Hans Verkuil95c232a2013-04-13 07:41:29 -03001049static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001050{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001051 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001052
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001053 *i = dev->input;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001054 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001055}
1056
Hans Verkuil95c232a2013-04-13 07:41:29 -03001057static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001058{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001059 struct cx25821_fh *fh = priv;
1060 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1061 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001062
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001063 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001064 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
1065 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001066 if (0 != err)
1067 return err;
1068 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001069
Hans Verkuil6b1dce22013-04-13 07:39:19 -03001070 if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001071 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001072
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001073 cx25821_video_mux(dev, i);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001074 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001075}
1076
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001077#ifdef CONFIG_VIDEO_ADV_DEBUG
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001078int cx25821_vidioc_g_register(struct file *file, void *fh,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001079 struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001080{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001081 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001082
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001083 if (!v4l2_chip_match_host(&reg->match))
1084 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001085
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001086 cx25821_call_all(dev, core, g_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001087
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001088 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001089}
1090
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001091int cx25821_vidioc_s_register(struct file *file, void *fh,
Hans Verkuil977ba3b2013-03-24 08:28:46 -03001092 const struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001093{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001094 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001095
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001096 if (!v4l2_chip_match_host(&reg->match))
1097 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001098
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001099 cx25821_call_all(dev, core, s_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001100
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001101 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001102}
1103
1104#endif
1105
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001106static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001107{
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001108 struct cx25821_channel *chan =
1109 container_of(ctrl->handler, struct cx25821_channel, hdl);
1110 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001111
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001112 switch (ctrl->id) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001113 case V4L2_CID_BRIGHTNESS:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001114 medusa_set_brightness(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001115 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001116 case V4L2_CID_HUE:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001117 medusa_set_hue(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001118 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001119 case V4L2_CID_CONTRAST:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001120 medusa_set_contrast(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001121 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001122 case V4L2_CID_SATURATION:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001123 medusa_set_saturation(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001124 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001125 default:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001126 return -EINVAL;
Joe Perches95cd17c2011-04-10 14:31:35 -07001127 }
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001128 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001129}
1130
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001131static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001132 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001133{
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001134 struct cx25821_fh *fh = file->private_data;
1135 struct cx25821_dev *dev = fh->dev;
1136 int command = 0;
1137 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001138
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001139 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001140
Joe Perches36d89f72010-11-07 17:48:21 -03001141 if (!data_from_user) {
1142 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1143 return 0;
1144 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001145
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001146 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001147
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001148 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1149 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001150
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001151 dev->input_filename = data_from_user->input_filename;
1152 dev->input_audiofilename = data_from_user->input_filename;
1153 dev->vid_stdname = data_from_user->vid_stdname;
1154 dev->pixel_format = data_from_user->pixel_format;
1155 dev->channel_select = data_from_user->channel_select;
1156 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001157
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001158 switch (command) {
1159 case UPSTREAM_START_VIDEO:
1160 cx25821_start_upstream_video_ch1(dev, data_from_user);
1161 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001162
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001163 case UPSTREAM_STOP_VIDEO:
1164 cx25821_stop_upstream_video_ch1(dev);
1165 break;
1166 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001167
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001168 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001169}
1170
1171static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001172 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001173{
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001174 struct cx25821_fh *fh = file->private_data;
1175 struct cx25821_dev *dev = fh->dev;
1176 int command = 0;
1177 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001178
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001179 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001180
Joe Perches36d89f72010-11-07 17:48:21 -03001181 if (!data_from_user) {
1182 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1183 return 0;
1184 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001185
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001186 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001187
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001188 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1189 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001190
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001191 dev->input_filename_ch2 = data_from_user->input_filename;
1192 dev->input_audiofilename = data_from_user->input_filename;
1193 dev->vid_stdname_ch2 = data_from_user->vid_stdname;
1194 dev->pixel_format_ch2 = data_from_user->pixel_format;
1195 dev->channel_select_ch2 = data_from_user->channel_select;
1196 dev->command_ch2 = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001197
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001198 switch (command) {
1199 case UPSTREAM_START_VIDEO:
1200 cx25821_start_upstream_video_ch2(dev, data_from_user);
1201 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001202
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001203 case UPSTREAM_STOP_VIDEO:
1204 cx25821_stop_upstream_video_ch2(dev);
1205 break;
1206 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001207
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001208 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001209}
1210
1211static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001212 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001213{
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001214 struct cx25821_fh *fh = file->private_data;
1215 struct cx25821_dev *dev = fh->dev;
1216 int command = 0;
1217 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001218
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001219 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001220
Joe Perches36d89f72010-11-07 17:48:21 -03001221 if (!data_from_user) {
1222 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1223 return 0;
1224 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001225
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001226 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001227
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001228 if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO)
1229 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001230
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001231 dev->input_filename = data_from_user->input_filename;
1232 dev->input_audiofilename = data_from_user->input_filename;
1233 dev->vid_stdname = data_from_user->vid_stdname;
1234 dev->pixel_format = data_from_user->pixel_format;
1235 dev->channel_select = data_from_user->channel_select;
1236 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001237
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001238 switch (command) {
1239 case UPSTREAM_START_AUDIO:
1240 cx25821_start_upstream_audio(dev, data_from_user);
1241 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001242
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001243 case UPSTREAM_STOP_AUDIO:
1244 cx25821_stop_upstream_audio(dev);
1245 break;
1246 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001247
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001248 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001249}
1250
1251static long video_ioctl_set(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001252 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001253{
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001254 struct cx25821_fh *fh = file->private_data;
1255 struct cx25821_dev *dev = fh->dev;
1256 struct downstream_user_struct *data_from_user;
1257 int command;
1258 int width = 720;
Leonid V. Fedorenchik4a33b6f2011-10-22 01:43:52 -03001259 int selected_channel = 0;
1260 int pix_format = 0;
1261 int i = 0;
1262 int cif_enable = 0;
1263 int cif_width = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001264
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001265 data_from_user = (struct downstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001266
Joe Perches36d89f72010-11-07 17:48:21 -03001267 if (!data_from_user) {
1268 pr_err("%s(): User data is INVALID. Returning\n", __func__);
1269 return 0;
1270 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001271
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001272 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001273
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001274 if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001275 && command != ENABLE_CIF_RESOLUTION && command != REG_READ
1276 && command != REG_WRITE && command != MEDUSA_READ
1277 && command != MEDUSA_WRITE) {
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001278 return 0;
1279 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001280
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001281 switch (command) {
1282 case SET_VIDEO_STD:
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001283 if (!strcmp(data_from_user->vid_stdname, "PAL"))
1284 dev->tvnorm = V4L2_STD_PAL_BG;
1285 else
1286 dev->tvnorm = V4L2_STD_NTSC_M;
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001287 medusa_set_videostandard(dev);
1288 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001289
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001290 case SET_PIXEL_FORMAT:
1291 selected_channel = data_from_user->decoder_select;
1292 pix_format = data_from_user->pixel_format;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001293
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001294 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1295 selected_channel -= 4;
1296 selected_channel = selected_channel % 8;
1297 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001298
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001299 if (selected_channel >= 0)
1300 cx25821_set_pixel_format(dev, selected_channel,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001301 pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001302
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001303 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001304
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001305 case ENABLE_CIF_RESOLUTION:
1306 selected_channel = data_from_user->decoder_select;
1307 cif_enable = data_from_user->cif_resolution_enable;
1308 cif_width = data_from_user->cif_width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001309
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001310 if (cif_enable) {
1311 if (dev->tvnorm & V4L2_STD_PAL_BG
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001312 || dev->tvnorm & V4L2_STD_PAL_DK) {
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001313 width = 352;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001314 } else {
1315 width = cif_width;
1316 if (cif_width != 320 && cif_width != 352)
1317 width = 320;
1318 }
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001319 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001320
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001321 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1322 selected_channel -= 4;
1323 selected_channel = selected_channel % 8;
1324 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001325
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001326 if (selected_channel <= 7 && selected_channel >= 0) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -03001327 dev->channels[selected_channel].use_cif_resolution =
1328 cif_enable;
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001329 dev->channels[selected_channel].cif_width = width;
1330 } else {
1331 for (i = 0; i < VID_CHANNEL_NUM; i++) {
1332 dev->channels[i].use_cif_resolution =
1333 cif_enable;
1334 dev->channels[i].cif_width = width;
1335 }
1336 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001337
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001338 medusa_set_resolution(dev, width, selected_channel);
1339 break;
1340 case REG_READ:
1341 data_from_user->reg_data = cx_read(data_from_user->reg_address);
1342 break;
1343 case REG_WRITE:
1344 cx_write(data_from_user->reg_address, data_from_user->reg_data);
1345 break;
1346 case MEDUSA_READ:
Hans Verkuil30fdf032012-04-20 06:26:19 -03001347 cx25821_i2c_read(&dev->i2c_bus[0],
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001348 (u16) data_from_user->reg_address,
1349 &data_from_user->reg_data);
1350 break;
1351 case MEDUSA_WRITE:
1352 cx25821_i2c_write(&dev->i2c_bus[0],
1353 (u16) data_from_user->reg_address,
1354 data_from_user->reg_data);
1355 break;
1356 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001357
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001358 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001359}
1360
1361static long cx25821_video_ioctl(struct file *file,
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001362 unsigned int cmd, unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001363{
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001364 int ret = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001365
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001366 struct cx25821_fh *fh = file->private_data;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001367
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001368 /* check to see if it's the video upstream */
1369 if (fh->channel_id == SRAM_CH09) {
1370 ret = video_ioctl_upstream9(file, cmd, arg);
1371 return ret;
1372 } else if (fh->channel_id == SRAM_CH10) {
1373 ret = video_ioctl_upstream10(file, cmd, arg);
1374 return ret;
1375 } else if (fh->channel_id == SRAM_CH11) {
1376 ret = video_ioctl_upstream11(file, cmd, arg);
1377 ret = video_ioctl_set(file, cmd, arg);
1378 return ret;
1379 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001380
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001381 return video_ioctl2(file, cmd, arg);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001382}
1383
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001384static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
1385 .s_ctrl = cx25821_s_ctrl,
1386};
1387
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001388static const struct v4l2_file_operations video_fops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001389 .owner = THIS_MODULE,
1390 .open = video_open,
1391 .release = video_release,
1392 .read = video_read,
1393 .poll = video_poll,
1394 .mmap = cx25821_video_mmap,
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001395 .unlocked_ioctl = cx25821_video_ioctl,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001396};
1397
1398static const struct v4l2_ioctl_ops video_ioctl_ops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001399 .vidioc_querycap = cx25821_vidioc_querycap,
1400 .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
1401 .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
1402 .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
1403 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1404 .vidioc_reqbufs = cx25821_vidioc_reqbufs,
1405 .vidioc_querybuf = cx25821_vidioc_querybuf,
1406 .vidioc_qbuf = cx25821_vidioc_qbuf,
1407 .vidioc_dqbuf = vidioc_dqbuf,
Hans Verkuil18c73af2013-04-13 05:50:18 -03001408 .vidioc_g_std = cx25821_vidioc_g_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001409 .vidioc_s_std = cx25821_vidioc_s_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001410 .vidioc_enum_input = cx25821_vidioc_enum_input,
1411 .vidioc_g_input = cx25821_vidioc_g_input,
1412 .vidioc_s_input = cx25821_vidioc_s_input,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001413 .vidioc_streamon = vidioc_streamon,
1414 .vidioc_streamoff = vidioc_streamoff,
1415 .vidioc_log_status = vidioc_log_status,
1416 .vidioc_g_priority = cx25821_vidioc_g_priority,
1417 .vidioc_s_priority = cx25821_vidioc_s_priority,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001418#ifdef CONFIG_VIDEO_ADV_DEBUG
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001419 .vidioc_g_register = cx25821_vidioc_g_register,
1420 .vidioc_s_register = cx25821_vidioc_s_register,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001421#endif
1422};
1423
Hans Verkuilffd3c232013-04-13 05:30:48 -03001424static const struct video_device cx25821_video_device = {
1425 .name = "cx25821-video",
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001426 .fops = &video_fops,
Hans Verkuil467870c2013-04-13 08:18:00 -03001427 .release = video_device_release_empty,
Hans Verkuilffd3c232013-04-13 05:30:48 -03001428 .minor = -1,
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001429 .ioctl_ops = &video_ioctl_ops,
1430 .tvnorms = CX25821_NORMS,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001431};
Hans Verkuilffd3c232013-04-13 05:30:48 -03001432
1433void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
1434{
1435 cx_clear(PCI_INT_MSK, 1);
1436
Hans Verkuil467870c2013-04-13 08:18:00 -03001437 if (video_is_registered(&dev->channels[chan_num].vdev)) {
1438 video_unregister_device(&dev->channels[chan_num].vdev);
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001439 v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001440
1441 btcx_riscmem_free(dev->pci,
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001442 &dev->channels[chan_num].dma_vidq.stopper);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001443 }
Hans Verkuilffd3c232013-04-13 05:30:48 -03001444}
1445
1446int cx25821_video_register(struct cx25821_dev *dev)
1447{
1448 int err;
1449 int i;
1450
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001451 /* initial device configuration */
1452 dev->tvnorm = V4L2_STD_NTSC_M,
1453 cx25821_set_tvnorm(dev, dev->tvnorm);
1454
Hans Verkuilffd3c232013-04-13 05:30:48 -03001455 spin_lock_init(&dev->slock);
1456
1457 for (i = 0; i < VID_CHANNEL_NUM; ++i) {
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001458 struct cx25821_channel *chan = &dev->channels[i];
1459 struct video_device *vdev = &chan->vdev;
1460 struct v4l2_ctrl_handler *hdl = &chan->hdl;
Hans Verkuil467870c2013-04-13 08:18:00 -03001461
Hans Verkuilffd3c232013-04-13 05:30:48 -03001462 if (i == SRAM_CH08) /* audio channel */
1463 continue;
1464
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001465 v4l2_ctrl_handler_init(hdl, 4);
1466 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1467 V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
1468 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1469 V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
1470 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1471 V4L2_CID_SATURATION, 0, 10000, 1, 5000);
1472 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1473 V4L2_CID_HUE, 0, 10000, 1, 5000);
1474 if (hdl->error) {
1475 err = hdl->error;
1476 goto fail_unreg;
1477 }
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001478 err = v4l2_ctrl_handler_setup(hdl);
1479 if (err)
1480 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001481
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001482 cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper,
1483 chan->sram_channels->dma_ctl, 0x11, 0);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001484
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001485 chan->sram_channels = &cx25821_sram_channels[i];
1486 chan->resources = 0;
1487 chan->width = 720;
1488 if (dev->tvnorm & V4L2_STD_625_50)
1489 chan->height = 576;
1490 else
1491 chan->height = 480;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001492
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001493 if (chan->pixel_formats == PIXEL_FRMT_411)
1494 chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_Y41P);
1495 else
1496 chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_YUYV);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001497
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001498 cx_write(chan->sram_channels->int_stat, 0xffffffff);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001499
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001500 INIT_LIST_HEAD(&chan->dma_vidq.active);
1501 INIT_LIST_HEAD(&chan->dma_vidq.queued);
1502
1503 chan->timeout_data.dev = dev;
1504 chan->timeout_data.channel = &cx25821_sram_channels[i];
1505 chan->dma_vidq.timeout.function = cx25821_vid_timeout;
1506 chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data;
1507 init_timer(&chan->dma_vidq.timeout);
1508
1509 videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev,
1510 &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
1511 V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
1512 chan, &dev->lock);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001513
1514 /* register v4l devices */
Hans Verkuil467870c2013-04-13 08:18:00 -03001515 *vdev = cx25821_video_device;
1516 vdev->v4l2_dev = &dev->v4l2_dev;
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001517 vdev->ctrl_handler = hdl;
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001518 vdev->lock = &dev->lock;
Hans Verkuil467870c2013-04-13 08:18:00 -03001519 snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
Hans Verkuil2efe2cc2013-04-13 10:00:52 -03001520 video_set_drvdata(vdev, chan);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001521
Hans Verkuil467870c2013-04-13 08:18:00 -03001522 err = video_register_device(vdev, VFL_TYPE_GRABBER,
1523 video_nr[dev->nr]);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001524
1525 if (err < 0)
1526 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001527 }
1528
1529 /* set PCI interrupt */
1530 cx_set(PCI_INT_MSK, 0xff);
1531
Hans Verkuilffd3c232013-04-13 05:30:48 -03001532 return 0;
1533
1534fail_unreg:
Hans Verkuil467870c2013-04-13 08:18:00 -03001535 while (i >= 0)
1536 cx25821_video_unregister(dev, i--);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001537 return err;
1538}