blob: 2aba24f2a3d82a15a7c32daa32ec558f52fdedc9 [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{
Hans Verkuil11f095a2013-04-14 11:54:56 -0300509 return &fh->vidq;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300510}
511
Hans Verkuil95c232a2013-04-13 07:41:29 -0300512static int cx25821_get_resource(struct cx25821_fh *fh, int resource)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300513{
Hans Verkuil11f095a2013-04-14 11:54:56 -0300514 return resource;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300515}
516
Hans Verkuil95c232a2013-04-13 07:41:29 -0300517static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300518{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300519 struct cx25821_fh *fh = file->private_data;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300520
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300521 return videobuf_mmap_mapper(get_queue(fh), vma);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300522}
523
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300524
525static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
526{
Leonid V. Fedorenchik8e4ac072011-09-16 14:14:43 +0800527 struct cx25821_buffer *buf =
Leonid V. Fedorenchikf2539812011-10-22 01:43:54 -0300528 container_of(vb, struct cx25821_buffer, vb);
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800529 struct cx25821_buffer *prev;
530 struct cx25821_fh *fh = vq->priv_data;
531 struct cx25821_dev *dev = fh->dev;
532 struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300533
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800534 /* add jump to stopper */
535 buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
536 buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
537 buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300538
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800539 dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300540
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800541 if (!list_empty(&q->queued)) {
542 list_add_tail(&buf->vb.queue, &q->queued);
543 buf->vb.state = VIDEOBUF_QUEUED;
544 dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
545 buf->vb.i);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300546
Leonid V. Fedorenchike6cf66c2011-09-16 14:14:44 +0800547 } else if (list_empty(&q->active)) {
548 list_add_tail(&buf->vb.queue, &q->active);
549 cx25821_start_video_dma(dev, q, buf,
550 dev->channels[fh->channel_id].sram_channels);
551 buf->vb.state = VIDEOBUF_ACTIVE;
552 buf->count = q->count++;
553 mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
554 dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
555 buf, buf->vb.i, buf->count, q->count);
556 } else {
557 prev = list_entry(q->active.prev, struct cx25821_buffer,
558 vb.queue);
559 if (prev->vb.width == buf->vb.width
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300560 && prev->vb.height == buf->vb.height
561 && prev->fmt == buf->fmt) {
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800562 list_add_tail(&buf->vb.queue, &q->active);
563 buf->vb.state = VIDEOBUF_ACTIVE;
564 buf->count = q->count++;
565 prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300566
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800567 /* 64 bit bits 63-32 */
568 prev->risc.jmp[2] = cpu_to_le32(0);
569 dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
570 buf, buf->vb.i, buf->count);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300571
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800572 } else {
573 list_add_tail(&buf->vb.queue, &q->queued);
574 buf->vb.state = VIDEOBUF_QUEUED;
575 dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
576 buf->vb.i);
577 }
578 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300579
Leonid V. Fedorenchik8ebbda42011-09-16 14:14:45 +0800580 if (list_empty(&q->active))
581 dprintk(2, "active queue empty!\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300582}
583
584static struct videobuf_queue_ops cx25821_video_qops = {
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800585 .buf_setup = cx25821_buffer_setup,
586 .buf_prepare = cx25821_buffer_prepare,
587 .buf_queue = buffer_queue,
588 .buf_release = cx25821_buffer_release,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300589};
590
591static int video_open(struct file *file)
592{
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800593 struct video_device *vdev = video_devdata(file);
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300594 struct cx25821_dev *dev = video_drvdata(file);
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800595 struct cx25821_fh *fh;
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800596 u32 pix_format;
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300597 int ch_id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300598
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300599 for (ch_id = 0; ch_id < MAX_VID_CHANNEL_NUM - 1; ch_id++)
Hans Verkuil467870c2013-04-13 08:18:00 -0300600 if (&dev->channels[ch_id].vdev == vdev)
Hans Verkuila8f35ce2013-04-13 07:07:40 -0300601 break;
602
603 /* Can't happen */
604 if (ch_id >= MAX_VID_CHANNEL_NUM - 1)
605 return -ENODEV;
606
Leonid V. Fedorenchikfb5f2c82011-09-16 14:14:46 +0800607 /* allocate + initialize per filehandle data */
608 fh = kzalloc(sizeof(*fh), GFP_KERNEL);
609 if (NULL == fh)
610 return -ENOMEM;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300611
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800612 file->private_data = fh;
613 fh->dev = dev;
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800614 fh->width = 720;
615 fh->channel_id = ch_id;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300616
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800617 if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
618 fh->height = 576;
619 else
620 fh->height = 480;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300621
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800622 dev->channel_opened = fh->channel_id;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +0800623 if (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411)
624 pix_format = V4L2_PIX_FMT_Y41P;
625 else
626 pix_format = V4L2_PIX_FMT_YUYV;
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800627 fh->fmt = cx25821_format_by_fourcc(pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300628
Leonid V. Fedorenchik0bf42c92011-09-16 14:14:48 +0800629 v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300630
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -0300631 videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev,
632 &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
633 V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300634 fh, &dev->lock);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300635
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800636 dprintk(1, "post videobuf_queue_init()\n");
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300637
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800638 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300639}
640
641static ssize_t video_read(struct file *file, char __user * data, size_t count,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300642 loff_t *ppos)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300643{
Leonid V. Fedorenchik20e8a362011-09-16 14:14:49 +0800644 struct cx25821_fh *fh = file->private_data;
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300645 struct cx25821_dev *dev = fh->dev;
646 int err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300647
Hans Verkuil11f095a2013-04-14 11:54:56 -0300648 if (mutex_lock_interruptible(&dev->lock))
649 return -ERESTARTSYS;
650 if (cx25821_res_locked(fh, RESOURCE_VIDEO0))
651 err = -EBUSY;
652 else
653 err = videobuf_read_one(&fh->vidq, data, count, ppos,
654 file->f_flags & O_NONBLOCK);
655 mutex_unlock(&dev->lock);
656 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300657}
658
659static unsigned int video_poll(struct file *file,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300660 struct poll_table_struct *wait)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300661{
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800662 struct cx25821_fh *fh = file->private_data;
663 struct cx25821_buffer *buf;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300664
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800665 if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
666 /* streaming capture */
667 if (list_empty(&fh->vidq.stream))
668 return POLLERR;
669 buf = list_entry(fh->vidq.stream.next,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300670 struct cx25821_buffer, vb.stream);
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800671 } else {
672 /* read() capture */
673 buf = (struct cx25821_buffer *)fh->vidq.read_buf;
674 if (NULL == buf)
675 return POLLERR;
676 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300677
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800678 poll_wait(file, &buf->vb.done, wait);
679 if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
680 if (buf->vb.state == VIDEOBUF_DONE) {
681 struct cx25821_dev *dev = fh->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300682
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800683 if (dev && dev->channels[fh->channel_id]
684 .use_cif_resolution) {
685 u8 cam_id = *((char *)buf->vb.baddr + 3);
686 memcpy((char *)buf->vb.baddr,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -0300687 (char *)buf->vb.baddr + (fh->width * 2),
688 (fh->width * 2));
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800689 *((char *)buf->vb.baddr + 3) = cam_id;
690 }
691 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300692
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800693 return POLLIN | POLLRDNORM;
694 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300695
Leonid V. Fedorenchik55c37c02011-09-16 14:14:50 +0800696 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300697}
698
699static int video_release(struct file *file)
700{
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800701 struct cx25821_fh *fh = file->private_data;
702 struct cx25821_dev *dev = fh->dev;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300703 const struct sram_channel *sram_ch =
704 dev->channels[0].sram_channels;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300705
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300706 mutex_lock(&dev->lock);
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800707 /* stop the risc engine and fifo */
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300708 cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300709
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800710 /* stop video capture */
711 if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
712 videobuf_queue_cancel(&fh->vidq);
713 cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
714 }
Hans Verkuilbe178cb2013-04-14 11:53:35 -0300715 mutex_unlock(&dev->lock);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300716
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800717 if (fh->vidq.read_buf) {
718 cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
719 kfree(fh->vidq.read_buf);
720 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300721
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800722 videobuf_mmap_free(&fh->vidq);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300723
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800724 v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio);
725 file->private_data = NULL;
726 kfree(fh);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300727
Leonid V. Fedorenchik21377cd2011-09-16 14:14:51 +0800728 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300729}
730
Hans Verkuil95c232a2013-04-13 07:41:29 -0300731/* VIDEO IOCTLS */
732static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
733 struct v4l2_format *f)
734{
735 struct cx25821_fh *fh = priv;
736
737 f->fmt.pix.width = fh->width;
738 f->fmt.pix.height = fh->height;
739 f->fmt.pix.field = fh->vidq.field;
740 f->fmt.pix.pixelformat = fh->fmt->fourcc;
741 f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3;
742 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
743
744 return 0;
745}
746
747static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
748 struct v4l2_format *f)
749{
750 const struct cx25821_fmt *fmt;
751 enum v4l2_field field;
752 unsigned int maxw, maxh;
753
754 fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
755 if (NULL == fmt)
756 return -EINVAL;
757
758 field = f->fmt.pix.field;
759 maxw = 720;
760 maxh = 576;
761
762 if (V4L2_FIELD_ANY == field) {
763 if (f->fmt.pix.height > maxh / 2)
764 field = V4L2_FIELD_INTERLACED;
765 else
766 field = V4L2_FIELD_TOP;
767 }
768
769 switch (field) {
770 case V4L2_FIELD_TOP:
771 case V4L2_FIELD_BOTTOM:
772 maxh = maxh / 2;
773 break;
774 case V4L2_FIELD_INTERLACED:
775 break;
776 default:
777 return -EINVAL;
778 }
779
780 f->fmt.pix.field = field;
781 if (f->fmt.pix.height < 32)
782 f->fmt.pix.height = 32;
783 if (f->fmt.pix.height > maxh)
784 f->fmt.pix.height = maxh;
785 if (f->fmt.pix.width < 48)
786 f->fmt.pix.width = 48;
787 if (f->fmt.pix.width > maxw)
788 f->fmt.pix.width = maxw;
789 f->fmt.pix.width &= ~0x03;
790 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
791 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
792
793 return 0;
794}
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300795static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
796{
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800797 struct cx25821_fh *fh = priv;
798 struct cx25821_dev *dev = fh->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300799
Hans Verkuil11f095a2013-04-14 11:54:56 -0300800 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800801 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300802
Hans Verkuil11f095a2013-04-14 11:54:56 -0300803 if (!cx25821_res_get(dev, fh,
804 cx25821_get_resource(fh, RESOURCE_VIDEO0)))
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800805 return -EBUSY;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300806
Leonid V. Fedorenchik3f3d9e42011-09-16 14:14:52 +0800807 return videobuf_streamon(get_queue(fh));
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300808}
809
810static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
811{
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800812 struct cx25821_fh *fh = priv;
813 struct cx25821_dev *dev = fh->dev;
814 int err, res;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300815
Hans Verkuil11f095a2013-04-14 11:54:56 -0300816 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800817 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300818
Leonid V. Fedorenchikeda59eb2011-09-16 14:14:53 +0800819 res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
820 err = videobuf_streamoff(get_queue(fh));
821 if (err < 0)
822 return err;
823 cx25821_res_free(dev, fh, res);
824 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300825}
826
Hans Verkuil95c232a2013-04-13 07:41:29 -0300827static int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm)
828{
829 if (tvnorm == V4L2_STD_PAL_BG) {
830 if (width == 352 || width == 720)
831 return 1;
832 else
833 return 0;
834 }
835
836 if (tvnorm == V4L2_STD_NTSC_M) {
837 if (width == 320 || width == 352 || width == 720)
838 return 1;
839 else
840 return 0;
841 }
842 return 0;
843}
844
845static int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
846{
847 if (tvnorm == V4L2_STD_PAL_BG) {
848 if (height == 576 || height == 288)
849 return 1;
850 else
851 return 0;
852 }
853
854 if (tvnorm == V4L2_STD_NTSC_M) {
855 if (height == 480 || height == 240)
856 return 1;
857 else
858 return 0;
859 }
860
861 return 0;
862}
863
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300864static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800865 struct v4l2_format *f)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300866{
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800867 struct cx25821_fh *fh = priv;
868 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300869 struct v4l2_mbus_framefmt mbus_fmt;
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800870 int err;
871 int pix_format = PIXEL_FRMT_422;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300872
Leonid V. Fedorenchika39bea32011-09-16 14:14:54 +0800873 if (fh) {
874 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
875 fh->prio);
876 if (0 != err)
877 return err;
878 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300879
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800880 err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300881
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800882 if (0 != err)
883 return err;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300884
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800885 fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
886 fh->vidq.field = f->fmt.pix.field;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300887
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800888 /* check if width and height is valid based on set standard */
889 if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
890 fh->width = f->fmt.pix.width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300891
Leonid V. Fedorenchik255c0402011-09-16 14:14:55 +0800892 if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
893 fh->height = f->fmt.pix.height;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300894
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800895 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
896 pix_format = PIXEL_FRMT_411;
897 else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
898 pix_format = PIXEL_FRMT_422;
899 else
900 return -EINVAL;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300901
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800902 cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300903
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800904 /* check if cif resolution */
905 if (fh->width == 320 || fh->width == 352)
906 dev->channels[fh->channel_id].use_cif_resolution = 1;
907 else
908 dev->channels[fh->channel_id].use_cif_resolution = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300909
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800910 dev->channels[fh->channel_id].cif_width = fh->width;
911 medusa_set_resolution(dev, fh->width, SRAM_CH00);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300912
Hans Verkuilc5e76a62010-08-06 16:18:23 -0300913 v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
914 cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300915
Leonid V. Fedorenchik66787622011-09-16 14:14:56 +0800916 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300917}
918
919static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
920{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800921 int ret_val = 0;
922 struct cx25821_fh *fh = priv;
923 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300924
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800925 ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300926
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800927 p->sequence = dev->channels[fh->channel_id].vidq.count;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300928
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800929 return ret_val;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300930}
931
932static int vidioc_log_status(struct file *file, void *priv)
933{
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800934 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
935 struct cx25821_fh *fh = priv;
Hans Verkuilbfef0d32013-04-13 06:28:54 -0300936 const struct sram_channel *sram_ch =
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300937 dev->channels[fh->channel_id].sram_channels;
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800938 u32 tmp = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300939
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800940 cx25821_call_all(dev, core, log_status);
941 tmp = cx_read(sram_ch->dma_ctl);
Joe Perches36d89f72010-11-07 17:48:21 -0300942 pr_info("Video input 0 is %s\n",
943 (tmp & 0x11) ? "streaming" : "stopped");
Leonid V. Fedorenchik02859b62011-09-16 14:14:57 +0800944 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300945}
946
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -0300947
Hans Verkuil95c232a2013-04-13 07:41:29 -0300948static int cx25821_vidioc_querycap(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800949 struct v4l2_capability *cap)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300950{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300951 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300952 struct cx25821_fh *fh = priv;
953 const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE |
954 V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
955 const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300956
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300957 strcpy(cap->driver, "cx25821");
958 strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
959 sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
Hans Verkuil3dd473c2013-04-13 06:06:18 -0300960 if (fh->channel_id >= VID_CHANNEL_NUM)
961 cap->device_caps = cap_output;
962 else
963 cap->device_caps = cap_input;
964 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300965 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300966}
967
Hans Verkuil95c232a2013-04-13 07:41:29 -0300968static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300969 struct v4l2_fmtdesc *f)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300970{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300971 if (unlikely(f->index >= ARRAY_SIZE(formats)))
972 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300973
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300974 strlcpy(f->description, formats[f->index].name, sizeof(f->description));
975 f->pixelformat = formats[f->index].fourcc;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300976
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300977 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300978}
979
Hans Verkuil95c232a2013-04-13 07:41:29 -0300980static int cx25821_vidioc_reqbufs(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800981 struct v4l2_requestbuffers *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300982{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300983 struct cx25821_fh *fh = priv;
984 return videobuf_reqbufs(get_queue(fh), p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300985}
986
Hans Verkuil95c232a2013-04-13 07:41:29 -0300987static int cx25821_vidioc_querybuf(struct file *file, void *priv,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +0800988 struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300989{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300990 struct cx25821_fh *fh = priv;
991 return videobuf_querybuf(get_queue(fh), p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300992}
993
Hans Verkuil95c232a2013-04-13 07:41:29 -0300994static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300995{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -0300996 struct cx25821_fh *fh = priv;
997 return videobuf_qbuf(get_queue(fh), p);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -0300998}
999
Hans Verkuil95c232a2013-04-13 07:41:29 -03001000static int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001001{
1002 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001003 struct cx25821_fh *fh = f;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001004
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001005 *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001006
1007 return 0;
1008}
1009
Hans Verkuil95c232a2013-04-13 07:41:29 -03001010static int cx25821_vidioc_s_priority(struct file *file, void *f,
Leonid V. Fedorenchikc1e6e242011-09-16 14:14:35 +08001011 enum v4l2_priority prio)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001012{
1013 struct cx25821_fh *fh = f;
1014 struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
1015
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001016 return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio,
1017 prio);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001018}
1019
Hans Verkuil95c232a2013-04-13 07:41:29 -03001020static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
Hans Verkuil18c73af2013-04-13 05:50:18 -03001021{
1022 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1023
1024 *tvnorms = dev->tvnorm;
1025 return 0;
1026}
1027
Hans Verkuil314527a2013-03-15 06:10:40 -03001028int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001029{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001030 struct cx25821_fh *fh = priv;
1031 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1032 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001033
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001034 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001035 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
1036 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001037 if (0 != err)
1038 return err;
1039 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001040
Hans Verkuil314527a2013-03-15 06:10:40 -03001041 if (dev->tvnorm == tvnorms)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001042 return 0;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001043
Hans Verkuil314527a2013-03-15 06:10:40 -03001044 cx25821_set_tvnorm(dev, tvnorms);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001045
1046 medusa_set_videostandard(dev);
1047
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001048 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001049}
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001050
Hans Verkuil95c232a2013-04-13 07:41:29 -03001051static int cx25821_vidioc_enum_input(struct file *file, void *priv,
1052 struct v4l2_input *i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001053{
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001054 static const char * const iname[] = {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001055 [CX25821_VMUX_COMPOSITE] = "Composite",
1056 [CX25821_VMUX_SVIDEO] = "S-Video",
1057 [CX25821_VMUX_DEBUG] = "for debug only",
1058 };
Hans Verkuil95c232a2013-04-13 07:41:29 -03001059 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001060 unsigned int n;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001061
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001062 n = i->index;
Hans Verkuil95c232a2013-04-13 07:41:29 -03001063 if (n >= CX25821_NR_INPUT)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001064 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001065
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001066 if (0 == INPUT(n)->type)
1067 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001068
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001069 i->type = V4L2_INPUT_TYPE_CAMERA;
1070 strcpy(i->name, iname[INPUT(n)->type]);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001071
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001072 i->std = CX25821_NORMS;
1073 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001074}
1075
Hans Verkuil95c232a2013-04-13 07:41:29 -03001076static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001077{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001078 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
Mauro Carvalho Chehabbb4c9a72009-09-13 11:25:45 -03001079
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001080 *i = dev->input;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001081 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001082}
1083
Hans Verkuil95c232a2013-04-13 07:41:29 -03001084static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001085{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001086 struct cx25821_fh *fh = priv;
1087 struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
1088 int err;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001089
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001090 if (fh) {
Leonid V. Fedorenchik70e7f142011-09-16 14:14:59 +08001091 err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
1092 fh->prio);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001093 if (0 != err)
1094 return err;
1095 }
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001096
Hans Verkuil6b1dce22013-04-13 07:39:19 -03001097 if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0)
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001098 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001099
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001100 cx25821_video_mux(dev, i);
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001101 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001102}
1103
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001104#ifdef CONFIG_VIDEO_ADV_DEBUG
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001105int cx25821_vidioc_g_register(struct file *file, void *fh,
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001106 struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001107{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001108 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001109
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001110 if (!v4l2_chip_match_host(&reg->match))
1111 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001112
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001113 cx25821_call_all(dev, core, g_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001114
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001115 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001116}
1117
Mauro Carvalho Chehabf2466d62010-03-24 16:33:40 -03001118int cx25821_vidioc_s_register(struct file *file, void *fh,
Hans Verkuil977ba3b2013-03-24 08:28:46 -03001119 const struct v4l2_dbg_register *reg)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001120{
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001121 struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001122
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001123 if (!v4l2_chip_match_host(&reg->match))
1124 return -EINVAL;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001125
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001126 cx25821_call_all(dev, core, s_register, reg);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001127
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001128 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001129}
1130
1131#endif
1132
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001133static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001134{
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001135 struct cx25821_channel *chan =
1136 container_of(ctrl->handler, struct cx25821_channel, hdl);
1137 struct cx25821_dev *dev = chan->dev;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001138
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001139 switch (ctrl->id) {
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001140 case V4L2_CID_BRIGHTNESS:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001141 medusa_set_brightness(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001142 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001143 case V4L2_CID_HUE:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001144 medusa_set_hue(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001145 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001146 case V4L2_CID_CONTRAST:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001147 medusa_set_contrast(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001148 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001149 case V4L2_CID_SATURATION:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001150 medusa_set_saturation(dev, ctrl->val, chan->id);
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001151 break;
Mauro Carvalho Chehab1a9fc852009-09-13 11:30:11 -03001152 default:
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001153 return -EINVAL;
Joe Perches95cd17c2011-04-10 14:31:35 -07001154 }
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001155 return 0;
Mauro Carvalho Chehab02b20b02009-09-15 11:33:54 -03001156}
1157
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001158static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001159 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001160{
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001161 struct cx25821_fh *fh = file->private_data;
1162 struct cx25821_dev *dev = fh->dev;
1163 int command = 0;
1164 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001165
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001166 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001167
Joe Perches36d89f72010-11-07 17:48:21 -03001168 if (!data_from_user) {
1169 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1170 return 0;
1171 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001172
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001173 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001174
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001175 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1176 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001177
Leonid V. Fedorenchik75965b82011-09-16 14:15:02 +08001178 dev->input_filename = data_from_user->input_filename;
1179 dev->input_audiofilename = data_from_user->input_filename;
1180 dev->vid_stdname = data_from_user->vid_stdname;
1181 dev->pixel_format = data_from_user->pixel_format;
1182 dev->channel_select = data_from_user->channel_select;
1183 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001184
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001185 switch (command) {
1186 case UPSTREAM_START_VIDEO:
1187 cx25821_start_upstream_video_ch1(dev, data_from_user);
1188 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001189
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001190 case UPSTREAM_STOP_VIDEO:
1191 cx25821_stop_upstream_video_ch1(dev);
1192 break;
1193 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001194
Leonid V. Fedorenchik6f87cc62011-09-16 14:15:03 +08001195 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001196}
1197
1198static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001199 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001200{
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001201 struct cx25821_fh *fh = file->private_data;
1202 struct cx25821_dev *dev = fh->dev;
1203 int command = 0;
1204 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001205
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001206 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001207
Joe Perches36d89f72010-11-07 17:48:21 -03001208 if (!data_from_user) {
1209 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1210 return 0;
1211 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001212
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001213 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001214
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001215 if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
1216 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001217
Leonid V. Fedorenchik43be3822011-09-16 14:15:04 +08001218 dev->input_filename_ch2 = data_from_user->input_filename;
1219 dev->input_audiofilename = data_from_user->input_filename;
1220 dev->vid_stdname_ch2 = data_from_user->vid_stdname;
1221 dev->pixel_format_ch2 = data_from_user->pixel_format;
1222 dev->channel_select_ch2 = data_from_user->channel_select;
1223 dev->command_ch2 = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001224
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001225 switch (command) {
1226 case UPSTREAM_START_VIDEO:
1227 cx25821_start_upstream_video_ch2(dev, data_from_user);
1228 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001229
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001230 case UPSTREAM_STOP_VIDEO:
1231 cx25821_stop_upstream_video_ch2(dev);
1232 break;
1233 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001234
Leonid V. Fedorenchikf9ef6be2011-09-16 14:15:05 +08001235 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001236}
1237
1238static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001239 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001240{
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001241 struct cx25821_fh *fh = file->private_data;
1242 struct cx25821_dev *dev = fh->dev;
1243 int command = 0;
1244 struct upstream_user_struct *data_from_user;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001245
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001246 data_from_user = (struct upstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001247
Joe Perches36d89f72010-11-07 17:48:21 -03001248 if (!data_from_user) {
1249 pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
1250 return 0;
1251 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001252
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001253 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001254
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001255 if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO)
1256 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001257
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001258 dev->input_filename = data_from_user->input_filename;
1259 dev->input_audiofilename = data_from_user->input_filename;
1260 dev->vid_stdname = data_from_user->vid_stdname;
1261 dev->pixel_format = data_from_user->pixel_format;
1262 dev->channel_select = data_from_user->channel_select;
1263 dev->command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001264
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001265 switch (command) {
1266 case UPSTREAM_START_AUDIO:
1267 cx25821_start_upstream_audio(dev, data_from_user);
1268 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001269
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001270 case UPSTREAM_STOP_AUDIO:
1271 cx25821_stop_upstream_audio(dev);
1272 break;
1273 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001274
Leonid V. Fedorenchik5e644012011-09-16 14:15:06 +08001275 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001276}
1277
1278static long video_ioctl_set(struct file *file, unsigned int cmd,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001279 unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001280{
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001281 struct cx25821_fh *fh = file->private_data;
1282 struct cx25821_dev *dev = fh->dev;
1283 struct downstream_user_struct *data_from_user;
1284 int command;
1285 int width = 720;
Leonid V. Fedorenchik4a33b6f2011-10-22 01:43:52 -03001286 int selected_channel = 0;
1287 int pix_format = 0;
1288 int i = 0;
1289 int cif_enable = 0;
1290 int cif_width = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001291
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001292 data_from_user = (struct downstream_user_struct *)arg;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001293
Joe Perches36d89f72010-11-07 17:48:21 -03001294 if (!data_from_user) {
1295 pr_err("%s(): User data is INVALID. Returning\n", __func__);
1296 return 0;
1297 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001298
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001299 command = data_from_user->command;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001300
Leonid V. Fedorenchik16a81ef2011-09-16 14:15:07 +08001301 if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001302 && command != ENABLE_CIF_RESOLUTION && command != REG_READ
1303 && command != REG_WRITE && command != MEDUSA_READ
1304 && command != MEDUSA_WRITE) {
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001305 return 0;
1306 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001307
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001308 switch (command) {
1309 case SET_VIDEO_STD:
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001310 if (!strcmp(data_from_user->vid_stdname, "PAL"))
1311 dev->tvnorm = V4L2_STD_PAL_BG;
1312 else
1313 dev->tvnorm = V4L2_STD_NTSC_M;
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001314 medusa_set_videostandard(dev);
1315 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001316
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +08001317 case SET_PIXEL_FORMAT:
1318 selected_channel = data_from_user->decoder_select;
1319 pix_format = data_from_user->pixel_format;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001320
Leonid V. Fedorenchik12fe7462011-09-16 14:15:08 +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. Fedorenchik12fe7462011-09-16 14:15:08 +08001326 if (selected_channel >= 0)
1327 cx25821_set_pixel_format(dev, selected_channel,
Mauro Carvalho Chehab3e9442c2010-07-04 15:37:05 -03001328 pix_format);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001329
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001330 break;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001331
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001332 case ENABLE_CIF_RESOLUTION:
1333 selected_channel = data_from_user->decoder_select;
1334 cif_enable = data_from_user->cif_resolution_enable;
1335 cif_width = data_from_user->cif_width;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001336
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001337 if (cif_enable) {
1338 if (dev->tvnorm & V4L2_STD_PAL_BG
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001339 || dev->tvnorm & V4L2_STD_PAL_DK) {
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001340 width = 352;
Leonid V. Fedorenchik3038f632011-09-16 14:15:14 +08001341 } else {
1342 width = cif_width;
1343 if (cif_width != 320 && cif_width != 352)
1344 width = 320;
1345 }
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001346 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001347
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001348 if (!(selected_channel <= 7 && selected_channel >= 0)) {
1349 selected_channel -= 4;
1350 selected_channel = selected_channel % 8;
1351 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001352
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001353 if (selected_channel <= 7 && selected_channel >= 0) {
Leonid V. Fedorenchik0abfefb2011-10-22 01:43:55 -03001354 dev->channels[selected_channel].use_cif_resolution =
1355 cif_enable;
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001356 dev->channels[selected_channel].cif_width = width;
1357 } else {
1358 for (i = 0; i < VID_CHANNEL_NUM; i++) {
1359 dev->channels[i].use_cif_resolution =
1360 cif_enable;
1361 dev->channels[i].cif_width = width;
1362 }
1363 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001364
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001365 medusa_set_resolution(dev, width, selected_channel);
1366 break;
1367 case REG_READ:
1368 data_from_user->reg_data = cx_read(data_from_user->reg_address);
1369 break;
1370 case REG_WRITE:
1371 cx_write(data_from_user->reg_address, data_from_user->reg_data);
1372 break;
1373 case MEDUSA_READ:
Hans Verkuil30fdf032012-04-20 06:26:19 -03001374 cx25821_i2c_read(&dev->i2c_bus[0],
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001375 (u16) data_from_user->reg_address,
1376 &data_from_user->reg_data);
1377 break;
1378 case MEDUSA_WRITE:
1379 cx25821_i2c_write(&dev->i2c_bus[0],
1380 (u16) data_from_user->reg_address,
1381 data_from_user->reg_data);
1382 break;
1383 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001384
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001385 return 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001386}
1387
1388static long cx25821_video_ioctl(struct file *file,
Leonid V. Fedorenchik2a517492011-09-16 14:15:09 +08001389 unsigned int cmd, unsigned long arg)
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001390{
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001391 int ret = 0;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001392
Leonid V. Fedorenchik1316b632011-10-22 01:43:50 -03001393 struct cx25821_fh *fh = file->private_data;
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001394
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001395 /* check to see if it's the video upstream */
1396 if (fh->channel_id == SRAM_CH09) {
1397 ret = video_ioctl_upstream9(file, cmd, arg);
1398 return ret;
1399 } else if (fh->channel_id == SRAM_CH10) {
1400 ret = video_ioctl_upstream10(file, cmd, arg);
1401 return ret;
1402 } else if (fh->channel_id == SRAM_CH11) {
1403 ret = video_ioctl_upstream11(file, cmd, arg);
1404 ret = video_ioctl_set(file, cmd, arg);
1405 return ret;
1406 }
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001407
Leonid V. Fedorenchikd2a167c2011-09-16 14:15:10 +08001408 return video_ioctl2(file, cmd, arg);
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001409}
1410
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001411static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
1412 .s_ctrl = cx25821_s_ctrl,
1413};
1414
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001415static const struct v4l2_file_operations video_fops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001416 .owner = THIS_MODULE,
1417 .open = video_open,
1418 .release = video_release,
1419 .read = video_read,
1420 .poll = video_poll,
1421 .mmap = cx25821_video_mmap,
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001422 .unlocked_ioctl = cx25821_video_ioctl,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001423};
1424
1425static const struct v4l2_ioctl_ops video_ioctl_ops = {
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001426 .vidioc_querycap = cx25821_vidioc_querycap,
1427 .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
1428 .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
1429 .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
1430 .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1431 .vidioc_reqbufs = cx25821_vidioc_reqbufs,
1432 .vidioc_querybuf = cx25821_vidioc_querybuf,
1433 .vidioc_qbuf = cx25821_vidioc_qbuf,
1434 .vidioc_dqbuf = vidioc_dqbuf,
Hans Verkuil18c73af2013-04-13 05:50:18 -03001435 .vidioc_g_std = cx25821_vidioc_g_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001436 .vidioc_s_std = cx25821_vidioc_s_std,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001437 .vidioc_enum_input = cx25821_vidioc_enum_input,
1438 .vidioc_g_input = cx25821_vidioc_g_input,
1439 .vidioc_s_input = cx25821_vidioc_s_input,
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001440 .vidioc_streamon = vidioc_streamon,
1441 .vidioc_streamoff = vidioc_streamoff,
1442 .vidioc_log_status = vidioc_log_status,
1443 .vidioc_g_priority = cx25821_vidioc_g_priority,
1444 .vidioc_s_priority = cx25821_vidioc_s_priority,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001445#ifdef CONFIG_VIDEO_ADV_DEBUG
Leonid V. Fedorenchikfa7ce1f2011-09-16 14:15:11 +08001446 .vidioc_g_register = cx25821_vidioc_g_register,
1447 .vidioc_s_register = cx25821_vidioc_s_register,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001448#endif
1449};
1450
Hans Verkuilffd3c232013-04-13 05:30:48 -03001451static const struct video_device cx25821_video_device = {
1452 .name = "cx25821-video",
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001453 .fops = &video_fops,
Hans Verkuil467870c2013-04-13 08:18:00 -03001454 .release = video_device_release_empty,
Hans Verkuilffd3c232013-04-13 05:30:48 -03001455 .minor = -1,
Leonid V. Fedorenchik527db492011-09-16 14:15:12 +08001456 .ioctl_ops = &video_ioctl_ops,
1457 .tvnorms = CX25821_NORMS,
Palash Bandyopadhyay6d8c2ba2010-07-04 14:15:38 -03001458};
Hans Verkuilffd3c232013-04-13 05:30:48 -03001459
1460void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
1461{
1462 cx_clear(PCI_INT_MSK, 1);
1463
Hans Verkuil467870c2013-04-13 08:18:00 -03001464 if (video_is_registered(&dev->channels[chan_num].vdev)) {
1465 video_unregister_device(&dev->channels[chan_num].vdev);
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001466 v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001467
1468 btcx_riscmem_free(dev->pci,
1469 &dev->channels[chan_num].vidq.stopper);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001470 }
Hans Verkuilffd3c232013-04-13 05:30:48 -03001471}
1472
1473int cx25821_video_register(struct cx25821_dev *dev)
1474{
1475 int err;
1476 int i;
1477
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001478 /* initial device configuration */
1479 dev->tvnorm = V4L2_STD_NTSC_M,
1480 cx25821_set_tvnorm(dev, dev->tvnorm);
1481
Hans Verkuilffd3c232013-04-13 05:30:48 -03001482 spin_lock_init(&dev->slock);
1483
1484 for (i = 0; i < VID_CHANNEL_NUM; ++i) {
Hans Verkuil467870c2013-04-13 08:18:00 -03001485 struct video_device *vdev = &dev->channels[i].vdev;
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001486 struct v4l2_ctrl_handler *hdl = &dev->channels[i].hdl;
Hans Verkuil467870c2013-04-13 08:18:00 -03001487
Hans Verkuilffd3c232013-04-13 05:30:48 -03001488 if (i == SRAM_CH08) /* audio channel */
1489 continue;
1490
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001491 v4l2_ctrl_handler_init(hdl, 4);
1492 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1493 V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
1494 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1495 V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
1496 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1497 V4L2_CID_SATURATION, 0, 10000, 1, 5000);
1498 v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
1499 V4L2_CID_HUE, 0, 10000, 1, 5000);
1500 if (hdl->error) {
1501 err = hdl->error;
1502 goto fail_unreg;
1503 }
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001504 err = v4l2_ctrl_handler_setup(hdl);
1505 if (err)
1506 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001507
1508 cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper,
1509 dev->channels[i].sram_channels->dma_ctl, 0x11, 0);
1510
1511 dev->channels[i].sram_channels = &cx25821_sram_channels[i];
Hans Verkuilffd3c232013-04-13 05:30:48 -03001512 dev->channels[i].resources = 0;
1513
1514 cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
1515
1516 INIT_LIST_HEAD(&dev->channels[i].vidq.active);
1517 INIT_LIST_HEAD(&dev->channels[i].vidq.queued);
1518
1519 dev->channels[i].timeout_data.dev = dev;
1520 dev->channels[i].timeout_data.channel =
1521 &cx25821_sram_channels[i];
1522 dev->channels[i].vidq.timeout.function = cx25821_vid_timeout;
1523 dev->channels[i].vidq.timeout.data =
1524 (unsigned long)&dev->channels[i].timeout_data;
1525 init_timer(&dev->channels[i].vidq.timeout);
1526
1527 /* register v4l devices */
Hans Verkuil467870c2013-04-13 08:18:00 -03001528 *vdev = cx25821_video_device;
1529 vdev->v4l2_dev = &dev->v4l2_dev;
Hans Verkuilf8d7ee72013-04-13 08:38:14 -03001530 vdev->ctrl_handler = hdl;
Hans Verkuilbe178cb2013-04-14 11:53:35 -03001531 vdev->lock = &dev->lock;
Hans Verkuil467870c2013-04-13 08:18:00 -03001532 snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
1533 video_set_drvdata(vdev, dev);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001534
Hans Verkuil467870c2013-04-13 08:18:00 -03001535 err = video_register_device(vdev, VFL_TYPE_GRABBER,
1536 video_nr[dev->nr]);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001537
1538 if (err < 0)
1539 goto fail_unreg;
Hans Verkuilffd3c232013-04-13 05:30:48 -03001540 }
1541
1542 /* set PCI interrupt */
1543 cx_set(PCI_INT_MSK, 0xff);
1544
Hans Verkuilffd3c232013-04-13 05:30:48 -03001545 return 0;
1546
1547fail_unreg:
Hans Verkuil467870c2013-04-13 08:18:00 -03001548 while (i >= 0)
1549 cx25821_video_unregister(dev, i--);
Hans Verkuilffd3c232013-04-13 05:30:48 -03001550 return err;
1551}