blob: ab79bd5e5f6833c8bd1df1511c999452fd619e6a [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;
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800291 struct cx25821_dmaqueue *q = &dev->channels[channel->i].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);
Leonid V. Fedorenchik69dfe452011-09-16 14:14:38 +0800337 cx25821_video_wakeup(dev, &dev->channels[channel->i].vidq,
338 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,
348 &dev->channels[channel->i].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{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300358 struct cx25821_fh *fh = q->priv_data;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300359
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300360 *size = fh->fmt->depth * fh->width * fh->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{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300374 struct cx25821_fh *fh = q->priv_data;
375 struct cx25821_dev *dev = fh->dev;
376 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;
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800382 int channel_opened = fh->channel_id;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300383
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300384 BUG_ON(NULL == fh->fmt);
385 if (fh->width < 48 || fh->width > 720 ||
386 fh->height < 32 || fh->height > 576)
387 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300388
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300389 buf->vb.size = (fh->width * fh->height * fh->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
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300394 if (buf->fmt != fh->fmt ||
395 buf->vb.width != fh->width ||
396 buf->vb.height != fh->height || buf->vb.field != field) {
397 buf->fmt = fh->fmt;
398 buf->vb.width = fh->width;
399 buf->vb.height = fh->height;
400 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) {
416
417 channel_opened = dev->channel_opened;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +0800418 if (channel_opened < 0 || channel_opened > 7)
419 channel_opened = 7;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300420
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800421 if (dev->channels[channel_opened].pixel_formats ==
422 PIXEL_FRMT_411)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300423 buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
424 else
425 buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
426
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800427 if (dev->channels[channel_opened].pixel_formats ==
428 PIXEL_FRMT_411) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300429 bpl_local = buf->bpl;
430 } else {
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800431 bpl_local = buf->bpl; /* Default */
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300432
433 if (channel_opened >= 0 && channel_opened <= 7) {
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800434 if (dev->channels[channel_opened]
435 .use_cif_resolution) {
Leonid V. Fedorenchikcd52b2c2011-10-22 01:43:53 -0300436 if (dev->tvnorm & V4L2_STD_PAL_BG ||
437 dev->tvnorm & V4L2_STD_PAL_DK)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300438 bpl_local = 352 << 1;
439 else
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300440 bpl_local = dev->channels[
441 channel_opened].
442 cif_width << 1;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300443 }
444 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300445 }
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300446
447 switch (buf->vb.field) {
448 case V4L2_FIELD_TOP:
449 cx25821_risc_buffer(dev->pci, &buf->risc,
450 dma->sglist, 0, UNSET,
451 buf->bpl, 0, buf->vb.height);
452 break;
453 case V4L2_FIELD_BOTTOM:
454 cx25821_risc_buffer(dev->pci, &buf->risc,
455 dma->sglist, UNSET, 0,
456 buf->bpl, 0, buf->vb.height);
457 break;
458 case V4L2_FIELD_INTERLACED:
459 /* All other formats are top field first */
460 line0_offset = 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300461 dprintk(1, "top field first\n");
462
463 cx25821_risc_buffer(dev->pci, &buf->risc,
464 dma->sglist, line0_offset,
465 bpl_local, bpl_local, bpl_local,
466 buf->vb.height >> 1);
467 break;
468 case V4L2_FIELD_SEQ_TB:
469 cx25821_risc_buffer(dev->pci, &buf->risc,
470 dma->sglist,
471 0, buf->bpl * (buf->vb.height >> 1),
472 buf->bpl, 0, buf->vb.height >> 1);
473 break;
474 case V4L2_FIELD_SEQ_BT:
475 cx25821_risc_buffer(dev->pci, &buf->risc,
476 dma->sglist,
477 buf->bpl * (buf->vb.height >> 1), 0,
478 buf->bpl, 0, buf->vb.height >> 1);
479 break;
480 default:
481 BUG();
482 }
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300483 }
484
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300485 dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
486 buf, buf->vb.i, fh->width, fh->height, fh->fmt->depth,
487 fh->fmt->name, (unsigned long)buf->risc.dma);
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300488
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300489 buf->vb.state = VIDEOBUF_PREPARED;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -0300490
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300491 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300492
Leonid V. Fedorenchik2748f262011-09-16 14:14:34 +0800493fail:
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300494 cx25821_free_buffer(q, buf);
495 return rc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300496}
497
Hans Verkuil95c232a2013-04-13 07:41:29 -0300498static void cx25821_buffer_release(struct videobuf_queue *q,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800499 struct videobuf_buffer *vb)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300500{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300501 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300502 container_of(vb, struct cx25821_buffer, vb);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300503
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300504 cx25821_free_buffer(q, buf);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300505}
506
Hans Verkuil95c232a2013-04-13 07:41:29 -0300507static struct videobuf_queue *get_queue(struct cx25821_fh *fh)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300508{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300509 switch (fh->type) {
510 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
511 return &fh->vidq;
512 default:
513 BUG();
514 return NULL;
515 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300516}
517
Hans Verkuil95c232a2013-04-13 07:41:29 -0300518static int cx25821_get_resource(struct cx25821_fh *fh, int resource)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300519{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300520 switch (fh->type) {
521 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
522 return resource;
523 default:
524 BUG();
525 return 0;
526 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300527}
528
Hans Verkuil95c232a2013-04-13 07:41:29 -0300529static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300530{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300531 struct cx25821_fh *fh = file->private_data;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300532
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300533 return videobuf_mmap_mapper(get_queue(fh), vma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300534}
535
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300536
537static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
538{
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800539 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300540 container_of(vb, struct cx25821_buffer, vb);
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800541 struct cx25821_buffer *prev;
542 struct cx25821_fh *fh = vq->priv_data;
543 struct cx25821_dev *dev = fh->dev;
544 struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300545
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800546 /* add jump to stopper */
547 buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
548 buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
549 buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300550
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800551 dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300552
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800553 if (!list_empty(&q->queued)) {
554 list_add_tail(&buf->vb.queue, &q->queued);
555 buf->vb.state = VIDEOBUF_QUEUED;
556 dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
557 buf->vb.i);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300558
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800559 } else if (list_empty(&q->active)) {
560 list_add_tail(&buf->vb.queue, &q->active);
561 cx25821_start_video_dma(dev, q, buf,
562 dev->channels[fh->channel_id].sram_channels);
563 buf->vb.state = VIDEOBUF_ACTIVE;
564 buf->count = q->count++;
565 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
566 dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
567 buf, buf->vb.i, buf->count, q->count);
568 } else {
569 prev = list_entry(q->active.prev, struct cx25821_buffer,
570 vb.queue);
571 if (prev->vb.width == buf->vb.width
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300572 && prev->vb.height == buf->vb.height
573 && prev->fmt == buf->fmt) {
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800574 list_add_tail(&buf->vb.queue, &q->active);
575 buf->vb.state = VIDEOBUF_ACTIVE;
576 buf->count = q->count++;
577 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300578
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800579 /* 64 bit bits 63-32 */
580 prev->risc.jmp[2] = cpu_to_le32(0);
581 dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
582 buf, buf->vb.i, buf->count);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300583
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800584 } else {
585 list_add_tail(&buf->vb.queue, &q->queued);
586 buf->vb.state = VIDEOBUF_QUEUED;
587 dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
588 buf->vb.i);
589 }
590 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300591
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800592 if (list_empty(&q->active))
593 dprintk(2, "active queue empty!\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300594}
595
596static struct videobuf_queue_ops cx25821_video_qops = {
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800597 .buf_setup = cx25821_buffer_setup,
598 .buf_prepare = cx25821_buffer_prepare,
599 .buf_queue = buffer_queue,
600 .buf_release = cx25821_buffer_release,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300601};
602
603static int video_open(struct file *file)
604{
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800605 struct video_device *vdev = video_devdata(file);
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300606 struct cx25821_dev *dev = video_drvdata(file);
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800607 struct cx25821_fh *fh;
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800608 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
609 u32 pix_format;
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300610 int ch_id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300611
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300612 for (ch_id = 0; ch_id < MAX_VID_CHANNEL_NUM - 1; ch_id++)
Hans Verkuil467870c2013-04-13 08:18:00 -0300613 if (&dev->channels[ch_id].vdev == vdev)
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300614 break;
615
616 /* Can't happen */
617 if (ch_id >= MAX_VID_CHANNEL_NUM - 1)
618 return -ENODEV;
619
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800620 /* allocate + initialize per filehandle data */
621 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
622 if (NULL == fh)
623 return -ENOMEM;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300624
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800625 file->private_data = fh;
626 fh->dev = dev;
627 fh->type = type;
628 fh->width = 720;
629 fh->channel_id = ch_id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300630
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800631 if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
632 fh->height = 576;
633 else
634 fh->height = 480;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300635
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800636 dev->channel_opened = fh->channel_id;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +0800637 if (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411)
638 pix_format = V4L2_PIX_FMT_Y41P;
639 else
640 pix_format = V4L2_PIX_FMT_YUYV;
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800641 fh->fmt = cx25821_format_by_fourcc(pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300642
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800643 v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300644
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300645 videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev,
646 &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
647 V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300648 fh, &dev->lock);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300649
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800650 dprintk(1, "post videobuf_queue_init()\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300651
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800652 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300653}
654
655static ssize_t video_read(struct file *file, char __user * data, size_t count,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300656 loff_t *ppos)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300657{
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800658 struct cx25821_fh *fh = file->private_data;
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300659 struct cx25821_dev *dev = fh->dev;
660 int err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300661
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800662 switch (fh->type) {
663 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300664 if (mutex_lock_interruptible(&dev->lock))
665 return -ERESTARTSYS;
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800666 if (cx25821_res_locked(fh, RESOURCE_VIDEO0))
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300667 err = -EBUSY;
668 else
669 err = videobuf_read_one(&fh->vidq, data, count, ppos,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300670 file->f_flags & O_NONBLOCK);
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300671 mutex_unlock(&dev->lock);
672 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300673
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800674 default:
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300675 return -ENODEV;
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800676 }
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300677
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300678}
679
680static unsigned int video_poll(struct file *file,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300681 struct poll_table_struct *wait)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300682{
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800683 struct cx25821_fh *fh = file->private_data;
684 struct cx25821_buffer *buf;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300685
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800686 if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
687 /* streaming capture */
688 if (list_empty(&fh->vidq.stream))
689 return POLLERR;
690 buf = list_entry(fh->vidq.stream.next,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300691 struct cx25821_buffer, vb.stream);
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800692 } else {
693 /* read() capture */
694 buf = (struct cx25821_buffer *)fh->vidq.read_buf;
695 if (NULL == buf)
696 return POLLERR;
697 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300698
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800699 poll_wait(file, &buf->vb.done, wait);
700 if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
701 if (buf->vb.state == VIDEOBUF_DONE) {
702 struct cx25821_dev *dev = fh->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300703
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800704 if (dev && dev->channels[fh->channel_id]
705 .use_cif_resolution) {
706 u8 cam_id = *((char *)buf->vb.baddr + 3);
707 memcpy((char *)buf->vb.baddr,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300708 (char *)buf->vb.baddr + (fh->width * 2),
709 (fh->width * 2));
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800710 *((char *)buf->vb.baddr + 3) = cam_id;
711 }
712 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300713
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800714 return POLLIN | POLLRDNORM;
715 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300716
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800717 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300718}
719
720static int video_release(struct file *file)
721{
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800722 struct cx25821_fh *fh = file->private_data;
723 struct cx25821_dev *dev = fh->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300724 const struct sram_channel *sram_ch =
725 dev->channels[0].sram_channels;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300726
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300727 mutex_lock(&dev->lock);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800728 /* stop the risc engine and fifo */
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300729 cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300730
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800731 /* stop video capture */
732 if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
733 videobuf_queue_cancel(&fh->vidq);
734 cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
735 }
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300736 mutex_unlock(&dev->lock);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300737
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800738 if (fh->vidq.read_buf) {
739 cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
740 kfree(fh->vidq.read_buf);
741 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300742
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800743 videobuf_mmap_free(&fh->vidq);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300744
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800745 v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio);
746 file->private_data = NULL;
747 kfree(fh);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300748
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800749 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300750}
751
Hans Verkuil95c232a2013-04-13 07:41:29 -0300752/* VIDEO IOCTLS */
753static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
754 struct v4l2_format *f)
755{
756 struct cx25821_fh *fh = priv;
757
758 f->fmt.pix.width = fh->width;
759 f->fmt.pix.height = fh->height;
760 f->fmt.pix.field = fh->vidq.field;
761 f->fmt.pix.pixelformat = fh->fmt->fourcc;
762 f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3;
763 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
764
765 return 0;
766}
767
768static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
769 struct v4l2_format *f)
770{
771 const struct cx25821_fmt *fmt;
772 enum v4l2_field field;
773 unsigned int maxw, maxh;
774
775 fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
776 if (NULL == fmt)
777 return -EINVAL;
778
779 field = f->fmt.pix.field;
780 maxw = 720;
781 maxh = 576;
782
783 if (V4L2_FIELD_ANY == field) {
784 if (f->fmt.pix.height > maxh / 2)
785 field = V4L2_FIELD_INTERLACED;
786 else
787 field = V4L2_FIELD_TOP;
788 }
789
790 switch (field) {
791 case V4L2_FIELD_TOP:
792 case V4L2_FIELD_BOTTOM:
793 maxh = maxh / 2;
794 break;
795 case V4L2_FIELD_INTERLACED:
796 break;
797 default:
798 return -EINVAL;
799 }
800
801 f->fmt.pix.field = field;
802 if (f->fmt.pix.height < 32)
803 f->fmt.pix.height = 32;
804 if (f->fmt.pix.height > maxh)
805 f->fmt.pix.height = maxh;
806 if (f->fmt.pix.width < 48)
807 f->fmt.pix.width = 48;
808 if (f->fmt.pix.width > maxw)
809 f->fmt.pix.width = maxw;
810 f->fmt.pix.width &= ~0x03;
811 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
812 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
813
814 return 0;
815}
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300816static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
817{
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800818 struct cx25821_fh *fh = priv;
819 struct cx25821_dev *dev = fh->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300820
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800821 if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
822 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300823
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800824 if (unlikely(i != fh->type))
825 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300826
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800827 if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh,
828 RESOURCE_VIDEO0))))
829 return -EBUSY;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300830
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800831 return videobuf_streamon(get_queue(fh));
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300832}
833
834static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
835{
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800836 struct cx25821_fh *fh = priv;
837 struct cx25821_dev *dev = fh->dev;
838 int err, res;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300839
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800840 if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
841 return -EINVAL;
842 if (i != fh->type)
843 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300844
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800845 res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
846 err = videobuf_streamoff(get_queue(fh));
847 if (err < 0)
848 return err;
849 cx25821_res_free(dev, fh, res);
850 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300851}
852
Hans Verkuil95c232a2013-04-13 07:41:29 -0300853static int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm)
854{
855 if (tvnorm == V4L2_STD_PAL_BG) {
856 if (width == 352 || width == 720)
857 return 1;
858 else
859 return 0;
860 }
861
862 if (tvnorm == V4L2_STD_NTSC_M) {
863 if (width == 320 || width == 352 || width == 720)
864 return 1;
865 else
866 return 0;
867 }
868 return 0;
869}
870
871static int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
872{
873 if (tvnorm == V4L2_STD_PAL_BG) {
874 if (height == 576 || height == 288)
875 return 1;
876 else
877 return 0;
878 }
879
880 if (tvnorm == V4L2_STD_NTSC_M) {
881 if (height == 480 || height == 240)
882 return 1;
883 else
884 return 0;
885 }
886
887 return 0;
888}
889
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300890static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800891 struct v4l2_format *f)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300892{
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800893 struct cx25821_fh *fh = priv;
894 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300895 struct v4l2_mbus_framefmt mbus_fmt;
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800896 int err;
897 int pix_format = PIXEL_FRMT_422;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300898
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800899 if (fh) {
900 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
901 fh->prio);
902 if (0 != err)
903 return err;
904 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300905
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800906 err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300907
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800908 if (0 != err)
909 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300910
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800911 fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
912 fh->vidq.field = f->fmt.pix.field;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300913
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800914 /* check if width and height is valid based on set standard */
915 if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
916 fh->width = f->fmt.pix.width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300917
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800918 if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
919 fh->height = f->fmt.pix.height;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300920
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800921 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
922 pix_format = PIXEL_FRMT_411;
923 else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
924 pix_format = PIXEL_FRMT_422;
925 else
926 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300927
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800928 cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300929
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800930 /* check if cif resolution */
931 if (fh->width == 320 || fh->width == 352)
932 dev->channels[fh->channel_id].use_cif_resolution = 1;
933 else
934 dev->channels[fh->channel_id].use_cif_resolution = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300935
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800936 dev->channels[fh->channel_id].cif_width = fh->width;
937 medusa_set_resolution(dev, fh->width, SRAM_CH00);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300938
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300939 v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
940 cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300941
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800942 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300943}
944
945static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
946{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800947 int ret_val = 0;
948 struct cx25821_fh *fh = priv;
949 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300950
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800951 ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300952
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800953 p->sequence = dev->channels[fh->channel_id].vidq.count;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300954
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800955 return ret_val;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300956}
957
958static int vidioc_log_status(struct file *file, void *priv)
959{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800960 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
961 struct cx25821_fh *fh = priv;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300962 const struct sram_channel *sram_ch =
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300963 dev->channels[fh->channel_id].sram_channels;
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800964 u32 tmp = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300965
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800966 cx25821_call_all(dev, core, log_status);
967 tmp = cx_read(sram_ch->dma_ctl);
Joe Perches36d89f72010-11-07 17:48:21 -0300968 pr_info("Video input 0 is %s\n",
969 (tmp & 0x11) ? "streaming" : "stopped");
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800970 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300971}
972
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300973
Hans Verkuil95c232a2013-04-13 07:41:29 -0300974static int cx25821_vidioc_querycap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800975 struct v4l2_capability *cap)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300976{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300977 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300978 struct cx25821_fh *fh = priv;
979 const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE |
980 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
981 const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300982
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300983 strcpy(cap->driver, "cx25821");
984 strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
985 sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300986 if (fh->channel_id >= VID_CHANNEL_NUM)
987 cap->device_caps = cap_output;
988 else
989 cap->device_caps = cap_input;
990 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300991 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300992}
993
Hans Verkuil95c232a2013-04-13 07:41:29 -0300994static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300995 struct v4l2_fmtdesc *f)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300996{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300997 if (unlikely(f->index >= ARRAY_SIZE(formats)))
998 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300999
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001000 strlcpy(f->description, formats[f->index].name, sizeof(f->description));
1001 f->pixelformat = formats[f->index].fourcc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001002
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001003 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001004}
1005
Hans Verkuil95c232a2013-04-13 07:41:29 -03001006static int cx25821_vidioc_reqbufs(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +08001007 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001008{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001009 struct cx25821_fh *fh = priv;
1010 return videobuf_reqbufs(get_queue(fh), p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001011}
1012
Hans Verkuil95c232a2013-04-13 07:41:29 -03001013static int cx25821_vidioc_querybuf(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +08001014 struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001015{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001016 struct cx25821_fh *fh = priv;
1017 return videobuf_querybuf(get_queue(fh), p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001018}
1019
Hans Verkuil95c232a2013-04-13 07:41:29 -03001020static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001021{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001022 struct cx25821_fh *fh = priv;
1023 return videobuf_qbuf(get_queue(fh), p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001024}
1025
Hans Verkuil95c232a2013-04-13 07:41:29 -03001026static int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001027{
1028 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001029 struct cx25821_fh *fh = f;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001030
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001031 *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001032
1033 return 0;
1034}
1035
Hans Verkuil95c232a2013-04-13 07:41:29 -03001036static int cx25821_vidioc_s_priority(struct file *file, void *f,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +08001037 enum v4l2_priority prio)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001038{
1039 struct cx25821_fh *fh = f;
1040 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
1041
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001042 return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio,
1043 prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001044}
1045
Hans Verkuil95c232a2013-04-13 07:41:29 -03001046static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
Hans Verkuil18c73af2013-04-13 05:50:18 -03001047{
1048 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1049
1050 *tvnorms = dev->tvnorm;
1051 return 0;
1052}
1053
Hans Verkuil314527a2013-03-15 06:10:40 -03001054int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001055{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001056 struct cx25821_fh *fh = priv;
1057 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1058 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001059
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001060 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001061 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
1062 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001063 if (0 != err)
1064 return err;
1065 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001066
Hans Verkuil314527a2013-03-15 06:10:40 -03001067 if (dev->tvnorm == tvnorms)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001068 return 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001069
Hans Verkuil314527a2013-03-15 06:10:40 -03001070 cx25821_set_tvnorm(dev, tvnorms);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001071
1072 medusa_set_videostandard(dev);
1073
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001074 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001075}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001076
Hans Verkuil95c232a2013-04-13 07:41:29 -03001077static int cx25821_vidioc_enum_input(struct file *file, void *priv,
1078 struct v4l2_input *i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001079{
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001080 static const char * const iname[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001081 [CX25821_VMUX_COMPOSITE] = "Composite",
1082 [CX25821_VMUX_SVIDEO] = "S-Video",
1083 [CX25821_VMUX_DEBUG] = "for debug only",
1084 };
Hans Verkuil95c232a2013-04-13 07:41:29 -03001085 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001086 unsigned int n;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001087
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001088 n = i->index;
Hans Verkuil95c232a2013-04-13 07:41:29 -03001089 if (n >= CX25821_NR_INPUT)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001090 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001091
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001092 if (0 == INPUT(n)->type)
1093 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001094
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001095 i->type = V4L2_INPUT_TYPE_CAMERA;
1096 strcpy(i->name, iname[INPUT(n)->type]);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001097
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001098 i->std = CX25821_NORMS;
1099 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001100}
1101
Hans Verkuil95c232a2013-04-13 07:41:29 -03001102static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001103{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001104 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001105
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001106 *i = dev->input;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001107 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001108}
1109
Hans Verkuil95c232a2013-04-13 07:41:29 -03001110static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001111{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001112 struct cx25821_fh *fh = priv;
1113 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1114 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001115
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001116 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001117 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
1118 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001119 if (0 != err)
1120 return err;
1121 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001122
Hans Verkuil6b1dce22013-04-13 07:39:19 -03001123 if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001124 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001125
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001126 cx25821_video_mux(dev, i);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001127 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001128}
1129
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001130#ifdef CONFIG_VIDEO_ADV_DEBUG
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001131int cx25821_vidioc_g_register(struct file *file, void *fh,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001132 struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001133{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001134 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001135
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001136 if (!v4l2_chip_match_host(&reg->match))
1137 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001138
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001139 cx25821_call_all(dev, core, g_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001140
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001141 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001142}
1143
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001144int cx25821_vidioc_s_register(struct file *file, void *fh,
Hans Verkuil977ba3b2013-03-24 08:28:46 -03001145 const struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001146{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001147 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001148
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001149 if (!v4l2_chip_match_host(&reg->match))
1150 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001151
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001152 cx25821_call_all(dev, core, s_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001153
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001154 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001155}
1156
1157#endif
1158
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001159static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001160{
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001161 struct cx25821_channel *chan =
1162 container_of(ctrl->handler, struct cx25821_channel, hdl);
1163 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001164
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001165 switch (ctrl->id) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001166 case V4L2_CID_BRIGHTNESS:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001167 medusa_set_brightness(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001168 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001169 case V4L2_CID_HUE:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001170 medusa_set_hue(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001171 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001172 case V4L2_CID_CONTRAST:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001173 medusa_set_contrast(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001174 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001175 case V4L2_CID_SATURATION:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001176 medusa_set_saturation(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001177 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001178 default:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001179 return -EINVAL;
Joe Perches95cd17c2011-04-10 14:31:35 -07001180 }
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001181 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001182}
1183
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001184static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001185 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001186{
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001187 struct cx25821_fh *fh = file->private_data;
1188 struct cx25821_dev *dev = fh->dev;
1189 int command = 0;
1190 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001191
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001192 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001193
Joe Perches36d89f72010-11-07 17:48:21 -03001194 if (!data_from_user) {
1195 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1196 return 0;
1197 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001198
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001199 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001200
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001201 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1202 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001203
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001204 dev->input_filename = data_from_user->input_filename;
1205 dev->input_audiofilename = data_from_user->input_filename;
1206 dev->vid_stdname = data_from_user->vid_stdname;
1207 dev->pixel_format = data_from_user->pixel_format;
1208 dev->channel_select = data_from_user->channel_select;
1209 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001210
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001211 switch (command) {
1212 case UPSTREAM_START_VIDEO:
1213 cx25821_start_upstream_video_ch1(dev, data_from_user);
1214 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001215
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001216 case UPSTREAM_STOP_VIDEO:
1217 cx25821_stop_upstream_video_ch1(dev);
1218 break;
1219 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001220
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001221 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001222}
1223
1224static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001225 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001226{
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001227 struct cx25821_fh *fh = file->private_data;
1228 struct cx25821_dev *dev = fh->dev;
1229 int command = 0;
1230 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001231
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001232 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001233
Joe Perches36d89f72010-11-07 17:48:21 -03001234 if (!data_from_user) {
1235 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1236 return 0;
1237 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001238
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001239 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001240
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001241 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1242 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001243
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001244 dev->input_filename_ch2 = data_from_user->input_filename;
1245 dev->input_audiofilename = data_from_user->input_filename;
1246 dev->vid_stdname_ch2 = data_from_user->vid_stdname;
1247 dev->pixel_format_ch2 = data_from_user->pixel_format;
1248 dev->channel_select_ch2 = data_from_user->channel_select;
1249 dev->command_ch2 = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001250
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001251 switch (command) {
1252 case UPSTREAM_START_VIDEO:
1253 cx25821_start_upstream_video_ch2(dev, data_from_user);
1254 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001255
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001256 case UPSTREAM_STOP_VIDEO:
1257 cx25821_stop_upstream_video_ch2(dev);
1258 break;
1259 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001260
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001261 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001262}
1263
1264static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001265 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001266{
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001267 struct cx25821_fh *fh = file->private_data;
1268 struct cx25821_dev *dev = fh->dev;
1269 int command = 0;
1270 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001271
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001272 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001273
Joe Perches36d89f72010-11-07 17:48:21 -03001274 if (!data_from_user) {
1275 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1276 return 0;
1277 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001278
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001279 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001280
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001281 if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO)
1282 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001283
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001284 dev->input_filename = data_from_user->input_filename;
1285 dev->input_audiofilename = data_from_user->input_filename;
1286 dev->vid_stdname = data_from_user->vid_stdname;
1287 dev->pixel_format = data_from_user->pixel_format;
1288 dev->channel_select = data_from_user->channel_select;
1289 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001290
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001291 switch (command) {
1292 case UPSTREAM_START_AUDIO:
1293 cx25821_start_upstream_audio(dev, data_from_user);
1294 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001295
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001296 case UPSTREAM_STOP_AUDIO:
1297 cx25821_stop_upstream_audio(dev);
1298 break;
1299 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001300
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001301 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001302}
1303
1304static long video_ioctl_set(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001305 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001306{
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001307 struct cx25821_fh *fh = file->private_data;
1308 struct cx25821_dev *dev = fh->dev;
1309 struct downstream_user_struct *data_from_user;
1310 int command;
1311 int width = 720;
Leonid V. Fedorenchik4a33b6f2011-10-22 01:43:52 -03001312 int selected_channel = 0;
1313 int pix_format = 0;
1314 int i = 0;
1315 int cif_enable = 0;
1316 int cif_width = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001317
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001318 data_from_user = (struct downstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001319
Joe Perches36d89f72010-11-07 17:48:21 -03001320 if (!data_from_user) {
1321 pr_err("%s(): User data is INVALID. Returning\n", __func__);
1322 return 0;
1323 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001324
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001325 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001326
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001327 if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001328 && command != ENABLE_CIF_RESOLUTION && command != REG_READ
1329 && command != REG_WRITE && command != MEDUSA_READ
1330 && command != MEDUSA_WRITE) {
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001331 return 0;
1332 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001333
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001334 switch (command) {
1335 case SET_VIDEO_STD:
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001336 if (!strcmp(data_from_user->vid_stdname, "PAL"))
1337 dev->tvnorm = V4L2_STD_PAL_BG;
1338 else
1339 dev->tvnorm = V4L2_STD_NTSC_M;
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001340 medusa_set_videostandard(dev);
1341 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001342
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001343 case SET_PIXEL_FORMAT:
1344 selected_channel = data_from_user->decoder_select;
1345 pix_format = data_from_user->pixel_format;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001346
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001347 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1348 selected_channel -= 4;
1349 selected_channel = selected_channel % 8;
1350 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001351
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001352 if (selected_channel >= 0)
1353 cx25821_set_pixel_format(dev, selected_channel,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001354 pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001355
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001356 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001357
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001358 case ENABLE_CIF_RESOLUTION:
1359 selected_channel = data_from_user->decoder_select;
1360 cif_enable = data_from_user->cif_resolution_enable;
1361 cif_width = data_from_user->cif_width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001362
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001363 if (cif_enable) {
1364 if (dev->tvnorm & V4L2_STD_PAL_BG
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001365 || dev->tvnorm & V4L2_STD_PAL_DK) {
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001366 width = 352;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001367 } else {
1368 width = cif_width;
1369 if (cif_width != 320 && cif_width != 352)
1370 width = 320;
1371 }
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001372 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001373
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001374 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1375 selected_channel -= 4;
1376 selected_channel = selected_channel % 8;
1377 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001378
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001379 if (selected_channel <= 7 && selected_channel >= 0) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -03001380 dev->channels[selected_channel].use_cif_resolution =
1381 cif_enable;
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001382 dev->channels[selected_channel].cif_width = width;
1383 } else {
1384 for (i = 0; i < VID_CHANNEL_NUM; i++) {
1385 dev->channels[i].use_cif_resolution =
1386 cif_enable;
1387 dev->channels[i].cif_width = width;
1388 }
1389 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001390
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001391 medusa_set_resolution(dev, width, selected_channel);
1392 break;
1393 case REG_READ:
1394 data_from_user->reg_data = cx_read(data_from_user->reg_address);
1395 break;
1396 case REG_WRITE:
1397 cx_write(data_from_user->reg_address, data_from_user->reg_data);
1398 break;
1399 case MEDUSA_READ:
Hans Verkuil30fdf032012-04-20 06:26:19 -03001400 cx25821_i2c_read(&dev->i2c_bus[0],
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001401 (u16) data_from_user->reg_address,
1402 &data_from_user->reg_data);
1403 break;
1404 case MEDUSA_WRITE:
1405 cx25821_i2c_write(&dev->i2c_bus[0],
1406 (u16) data_from_user->reg_address,
1407 data_from_user->reg_data);
1408 break;
1409 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001410
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001411 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001412}
1413
1414static long cx25821_video_ioctl(struct file *file,
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001415 unsigned int cmd, unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001416{
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001417 int ret = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001418
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001419 struct cx25821_fh *fh = file->private_data;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001420
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001421 /* check to see if it's the video upstream */
1422 if (fh->channel_id == SRAM_CH09) {
1423 ret = video_ioctl_upstream9(file, cmd, arg);
1424 return ret;
1425 } else if (fh->channel_id == SRAM_CH10) {
1426 ret = video_ioctl_upstream10(file, cmd, arg);
1427 return ret;
1428 } else if (fh->channel_id == SRAM_CH11) {
1429 ret = video_ioctl_upstream11(file, cmd, arg);
1430 ret = video_ioctl_set(file, cmd, arg);
1431 return ret;
1432 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001433
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001434 return video_ioctl2(file, cmd, arg);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001435}
1436
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001437static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
1438 .s_ctrl = cx25821_s_ctrl,
1439};
1440
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001441static const struct v4l2_file_operations video_fops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001442 .owner = THIS_MODULE,
1443 .open = video_open,
1444 .release = video_release,
1445 .read = video_read,
1446 .poll = video_poll,
1447 .mmap = cx25821_video_mmap,
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001448 .unlocked_ioctl = cx25821_video_ioctl,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001449};
1450
1451static const struct v4l2_ioctl_ops video_ioctl_ops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001452 .vidioc_querycap = cx25821_vidioc_querycap,
1453 .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
1454 .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
1455 .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
1456 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1457 .vidioc_reqbufs = cx25821_vidioc_reqbufs,
1458 .vidioc_querybuf = cx25821_vidioc_querybuf,
1459 .vidioc_qbuf = cx25821_vidioc_qbuf,
1460 .vidioc_dqbuf = vidioc_dqbuf,
Hans Verkuil18c73af2013-04-13 05:50:18 -03001461 .vidioc_g_std = cx25821_vidioc_g_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001462 .vidioc_s_std = cx25821_vidioc_s_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001463 .vidioc_enum_input = cx25821_vidioc_enum_input,
1464 .vidioc_g_input = cx25821_vidioc_g_input,
1465 .vidioc_s_input = cx25821_vidioc_s_input,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001466 .vidioc_streamon = vidioc_streamon,
1467 .vidioc_streamoff = vidioc_streamoff,
1468 .vidioc_log_status = vidioc_log_status,
1469 .vidioc_g_priority = cx25821_vidioc_g_priority,
1470 .vidioc_s_priority = cx25821_vidioc_s_priority,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001471#ifdef CONFIG_VIDEO_ADV_DEBUG
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001472 .vidioc_g_register = cx25821_vidioc_g_register,
1473 .vidioc_s_register = cx25821_vidioc_s_register,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001474#endif
1475};
1476
Hans Verkuilffd3c232013-04-13 05:30:48 -03001477static const struct video_device cx25821_video_device = {
1478 .name = "cx25821-video",
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001479 .fops = &video_fops,
Hans Verkuil467870c2013-04-13 08:18:00 -03001480 .release = video_device_release_empty,
Hans Verkuilffd3c232013-04-13 05:30:48 -03001481 .minor = -1,
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001482 .ioctl_ops = &video_ioctl_ops,
1483 .tvnorms = CX25821_NORMS,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001484};
Hans Verkuilffd3c232013-04-13 05:30:48 -03001485
1486void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
1487{
1488 cx_clear(PCI_INT_MSK, 1);
1489
Hans Verkuil467870c2013-04-13 08:18:00 -03001490 if (video_is_registered(&dev->channels[chan_num].vdev)) {
1491 video_unregister_device(&dev->channels[chan_num].vdev);
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001492 v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001493
1494 btcx_riscmem_free(dev->pci,
1495 &dev->channels[chan_num].vidq.stopper);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001496 }
Hans Verkuilffd3c232013-04-13 05:30:48 -03001497}
1498
1499int cx25821_video_register(struct cx25821_dev *dev)
1500{
1501 int err;
1502 int i;
1503
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001504 /* initial device configuration */
1505 dev->tvnorm = V4L2_STD_NTSC_M,
1506 cx25821_set_tvnorm(dev, dev->tvnorm);
1507
Hans Verkuilffd3c232013-04-13 05:30:48 -03001508 spin_lock_init(&dev->slock);
1509
1510 for (i = 0; i < VID_CHANNEL_NUM; ++i) {
Hans Verkuil467870c2013-04-13 08:18:00 -03001511 struct video_device *vdev = &dev->channels[i].vdev;
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001512 struct v4l2_ctrl_handler *hdl = &dev->channels[i].hdl;
Hans Verkuil467870c2013-04-13 08:18:00 -03001513
Hans Verkuilffd3c232013-04-13 05:30:48 -03001514 if (i == SRAM_CH08) /* audio channel */
1515 continue;
1516
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001517 v4l2_ctrl_handler_init(hdl, 4);
1518 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1519 V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
1520 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1521 V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
1522 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1523 V4L2_CID_SATURATION, 0, 10000, 1, 5000);
1524 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1525 V4L2_CID_HUE, 0, 10000, 1, 5000);
1526 if (hdl->error) {
1527 err = hdl->error;
1528 goto fail_unreg;
1529 }
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001530 err = v4l2_ctrl_handler_setup(hdl);
1531 if (err)
1532 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001533
1534 cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper,
1535 dev->channels[i].sram_channels->dma_ctl, 0x11, 0);
1536
1537 dev->channels[i].sram_channels = &cx25821_sram_channels[i];
Hans Verkuilffd3c232013-04-13 05:30:48 -03001538 dev->channels[i].resources = 0;
1539
1540 cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
1541
1542 INIT_LIST_HEAD(&dev->channels[i].vidq.active);
1543 INIT_LIST_HEAD(&dev->channels[i].vidq.queued);
1544
1545 dev->channels[i].timeout_data.dev = dev;
1546 dev->channels[i].timeout_data.channel =
1547 &cx25821_sram_channels[i];
1548 dev->channels[i].vidq.timeout.function = cx25821_vid_timeout;
1549 dev->channels[i].vidq.timeout.data =
1550 (unsigned long)&dev->channels[i].timeout_data;
1551 init_timer(&dev->channels[i].vidq.timeout);
1552
1553 /* register v4l devices */
Hans Verkuil467870c2013-04-13 08:18:00 -03001554 *vdev = cx25821_video_device;
1555 vdev->v4l2_dev = &dev->v4l2_dev;
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001556 vdev->ctrl_handler = hdl;
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001557 vdev->lock = &dev->lock;
Hans Verkuil467870c2013-04-13 08:18:00 -03001558 snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
1559 video_set_drvdata(vdev, dev);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001560
Hans Verkuil467870c2013-04-13 08:18:00 -03001561 err = video_register_device(vdev, VFL_TYPE_GRABBER,
1562 video_nr[dev->nr]);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001563
1564 if (err < 0)
1565 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001566 }
1567
1568 /* set PCI interrupt */
1569 cx_set(PCI_INT_MSK, 0xff);
1570
Hans Verkuilffd3c232013-04-13 05:30:48 -03001571 return 0;
1572
1573fail_unreg:
Hans Verkuil467870c2013-04-13 08:18:00 -03001574 while (i >= 0)
1575 cx25821_video_unregister(dev, i--);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001576 return err;
1577}